@jxsuite/studio 4.1.0 → 5.0.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 (607) hide show
  1. package/README.md +1 -1
  2. package/data/elements-meta.json +5 -15
  3. package/data/html-meta.json +51 -6
  4. package/dist/chunks/{2020-n6tfwnda.js → 2020-g79n01v9.js} +14 -14
  5. package/dist/chunks/action-group-sp6tna8v.js +118 -0
  6. package/dist/chunks/adapter-nj7tnjfn.js +13 -0
  7. package/dist/chunks/cf-account-picker-fyf63pmy.js +495 -0
  8. package/dist/chunks/cf-settings-71bv5zn9.js +20 -0
  9. package/dist/chunks/color-area-v17df7b8.js +154 -0
  10. package/dist/chunks/color-field-anwybnkn.js +208 -0
  11. package/dist/chunks/color-slider-44ez96fc.js +79 -0
  12. package/dist/chunks/color-xgg3kfw7.js +35 -0
  13. package/dist/chunks/combobox-5e7jev23.js +236 -0
  14. package/dist/chunks/components-2w1f35qs.js +18 -0
  15. package/dist/chunks/content-source-3wqeas45.js +46 -0
  16. package/dist/chunks/convert-to-repeater-d0cgnb6d.js +639 -0
  17. package/dist/chunks/dialog-s890b918.js +85 -0
  18. package/dist/chunks/editor-3qhbg51x.js +35 -0
  19. package/dist/chunks/entry-commands-d6g50j7s.js +42 -0
  20. package/dist/chunks/extension-sections-fy7q4fe9.js +651 -0
  21. package/dist/chunks/file-ops-3btj6st0.js +47 -0
  22. package/dist/chunks/files-ef8fgs3w.js +72 -0
  23. package/dist/chunks/format-host-3c33nwr8.js +40 -0
  24. package/dist/chunks/fs-events-13tj6sex.js +18 -0
  25. package/dist/chunks/git-panel-4wp2rn9b.js +49 -0
  26. package/dist/chunks/icons-yy10wk9r.js +402 -0
  27. package/dist/chunks/iframe-entry-15g3n6xv.js +114 -0
  28. package/dist/chunks/iframe-entry-b27vq81n.js +203 -0
  29. package/dist/chunks/iframe-entry-nbyxee1y.js +154 -0
  30. package/dist/chunks/iframe-host-jgesd924.js +115 -0
  31. package/dist/chunks/{index-wcnt3r9g.js → index-mdmyx6s2.js} +11 -11
  32. package/dist/chunks/index-n4j7qxyr.js +109 -0
  33. package/dist/chunks/{javascript-q8kpmfah.js → javascript-xvrfrpkb.js} +8 -9
  34. package/dist/chunks/{jsonMode-dkr040ga.js → jsonMode-tyx2kj6p.js} +526 -527
  35. package/dist/chunks/jx-validate-j0wxk72w.js +15 -0
  36. package/dist/chunks/layers-1nq5evsh.js +29 -0
  37. package/dist/chunks/layers-panel-ar2gh90g.js +40 -0
  38. package/dist/chunks/listbox-6v2ac08j.js +44 -0
  39. package/dist/chunks/lit-html-m244w9nh.js +17 -0
  40. package/dist/chunks/media-picker-2qbetq73.js +33 -0
  41. package/dist/chunks/menu-q99sy9rf.js +285 -0
  42. package/dist/chunks/menu-rf7n72mf.js +14 -0
  43. package/dist/chunks/{monaco-binding-rj6xpx9y.js → monaco-binding-sw6en4dw.js} +12 -15
  44. package/dist/chunks/monaco-buffer-bhy3hb6m.js +24 -0
  45. package/dist/chunks/{monaco-setup-vx9bhp1d.js → monaco-setup-8r62fj6y.js} +27 -37
  46. package/dist/chunks/notify-628t0anh.js +21 -0
  47. package/dist/chunks/number-field-5cndyft8.js +72 -0
  48. package/dist/chunks/parse-0zx14y15.js +10 -0
  49. package/dist/chunks/platform-ts9cg1a4.js +15 -0
  50. package/dist/chunks/popover-47z3ytva.js +25 -0
  51. package/dist/chunks/publish-panel-98f7sr3g.js +27 -0
  52. package/dist/chunks/quick-search-srzz83k2.js +45 -0
  53. package/dist/chunks/references-n553f0e1.js +26 -0
  54. package/dist/chunks/right-panel-rrgx2dn3.js +45 -0
  55. package/dist/chunks/section-registry-5pq32t0q.js +25 -0
  56. package/dist/chunks/select-2r16ez41.js +49 -0
  57. package/dist/chunks/split-g7nm1rgb.js +191 -0
  58. package/dist/chunks/studio-0hqbpbd0.js +62 -0
  59. package/dist/chunks/studio-18avnhjp.js +2430 -0
  60. package/dist/chunks/{studio-kryvsw6j.js → studio-1k325pwf.js} +48 -48
  61. package/dist/chunks/{studio-msd847zn.js → studio-25hkdrkw.js} +357 -86
  62. package/dist/chunks/studio-26d7myd1.js +258 -0
  63. package/dist/chunks/{studio-4r1pv6zf.js → studio-38emantv.js} +22 -5
  64. package/dist/chunks/studio-3gxv60tn.js +422 -0
  65. package/dist/chunks/{studio-fbf92ckf.js → studio-3hxkd92t.js} +275 -163
  66. package/dist/chunks/studio-4m0haseg.js +185 -0
  67. package/dist/chunks/{studio-ynxwkrzd.js → studio-4wbb9ct0.js} +1953 -1785
  68. package/dist/chunks/{studio-1wagb550.js → studio-5523bpzt.js} +11 -11
  69. package/dist/chunks/{studio-x4qkdat5.js → studio-57mf66w2.js} +1749 -2481
  70. package/dist/chunks/studio-5jy81t3s.js +17463 -0
  71. package/dist/chunks/studio-5rt7sqa0.js +1168 -0
  72. package/dist/chunks/studio-5te5tqng.js +81 -0
  73. package/dist/chunks/{studio-p4ngc046.js → studio-6ewqv390.js} +9 -9
  74. package/dist/chunks/{studio-9ab8gqsm.js → studio-6nzaktvy.js} +7 -7
  75. package/dist/chunks/studio-6xa21ej9.js +28 -0
  76. package/dist/chunks/{studio-5ehhackm.js → studio-727xh0e3.js} +19 -19
  77. package/dist/chunks/{studio-ahn3pdgx.js → studio-79y5sz51.js} +52 -38
  78. package/dist/chunks/{studio-gcye7qka.js → studio-7e11jpa9.js} +21 -21
  79. package/dist/chunks/{studio-q7v10cg2.js → studio-7r42c6ca.js} +17 -7
  80. package/dist/chunks/studio-7xptrg0j.js +954 -0
  81. package/dist/chunks/{studio-cft9r4r7.js → studio-81390n6f.js} +22 -22
  82. package/dist/chunks/{studio-q43a5y9h.js → studio-8jn5yhyn.js} +16 -16
  83. package/dist/chunks/studio-8qtrpzr3.js +839 -0
  84. package/dist/chunks/{studio-dg7zyt5x.js → studio-98b3z07n.js} +1 -1
  85. package/dist/chunks/studio-9xxz1q69.js +1356 -0
  86. package/dist/chunks/studio-akbww0j5.js +13615 -0
  87. package/dist/chunks/{studio-x813zp48.js → studio-arfpe389.js} +30 -30
  88. package/dist/chunks/{studio-trxrabqf.js → studio-az3zd49t.js} +475 -283
  89. package/dist/chunks/studio-cpvb2ed1.js +1171 -0
  90. package/dist/chunks/{studio-f3wqjtk5.js → studio-d0300636.js} +5076 -18
  91. package/dist/chunks/{studio-bgxt93ga.js → studio-d055c37e.js} +13 -13
  92. package/dist/chunks/studio-d1ja2x9r.js +362 -0
  93. package/dist/chunks/{studio-b9b6t1dg.js → studio-e1f24eff.js} +5664 -5666
  94. package/dist/chunks/{studio-3bqpr0zh.js → studio-em9nw8eh.js} +299 -110
  95. package/dist/chunks/studio-erdatzvp.js +1190 -0
  96. package/dist/chunks/{studio-g1wdche0.js → studio-esrxgwh6.js} +80 -80
  97. package/dist/chunks/studio-fabxk6r9.js +2811 -0
  98. package/dist/chunks/{studio-3n4ndrzh.js → studio-h4nvnjvz.js} +303 -303
  99. package/dist/chunks/{studio-dm19q43r.js → studio-hhvs4sdg.js} +10 -10
  100. package/dist/chunks/{studio-q9jd1a60.js → studio-kcgff4r0.js} +15 -18
  101. package/dist/chunks/{studio-685s0ytq.js → studio-nqgawfks.js} +572 -572
  102. package/dist/chunks/{studio-xrapxwwc.js → studio-p1dw8wfw.js} +55 -29
  103. package/dist/chunks/studio-pm6hgy7r.js +4763 -0
  104. package/dist/chunks/studio-q0a3yk4n.js +33 -0
  105. package/dist/chunks/{studio-wcy8trfx.js → studio-q3x06vmj.js} +23 -22
  106. package/dist/chunks/studio-qahxvnan.js +111 -0
  107. package/dist/chunks/{studio-53n8bp04.js → studio-r6xmmtfh.js} +1 -1
  108. package/dist/chunks/{studio-2b946z26.js → studio-rkstz940.js} +3658 -6134
  109. package/dist/chunks/{studio-tvgyw9xw.js → studio-rnyf3f8e.js} +83 -250
  110. package/dist/chunks/studio-rpyah2ew.js +2805 -0
  111. package/dist/chunks/studio-rs76k67r.js +12 -0
  112. package/dist/chunks/{studio-jkftxyvz.js → studio-s6z853aq.js} +5858 -2152
  113. package/dist/chunks/{studio-6yw4y3my.js → studio-sgdc5pfc.js} +8 -8
  114. package/dist/chunks/studio-tb3ev01j.js +763 -0
  115. package/dist/chunks/{studio-t5wqwzdh.js → studio-tjjk7jvk.js} +1 -1
  116. package/dist/chunks/studio-vhv5tgxm.js +51 -0
  117. package/dist/chunks/{studio-qjy2z9bv.js → studio-vz68yn9e.js} +32 -137
  118. package/dist/chunks/studio-wqpngpsk.js +174 -0
  119. package/dist/chunks/{studio-b55y6ewx.js → studio-x3rty6tr.js} +58 -58
  120. package/dist/chunks/studio-xsykpvsh.js +8448 -0
  121. package/dist/chunks/{studio-92ab2jqe.js → studio-y9zedyjn.js} +14 -14
  122. package/dist/chunks/studio-yxa81f45.js +12 -0
  123. package/dist/chunks/swatch-group-t0n6h2rn.js +139 -0
  124. package/dist/chunks/tabs-wbp1cdws.js +156 -0
  125. package/dist/chunks/textfield-abk6qyee.js +73 -0
  126. package/dist/chunks/toast-780pvfbv.js +27 -0
  127. package/dist/chunks/toast-host-3sqv46sn.js +116 -0
  128. package/dist/chunks/toolbar-xbh5bhtr.js +194 -0
  129. package/dist/chunks/tooltip-eptb614w.js +369 -0
  130. package/dist/chunks/tree-a73p0pqm.js +367 -0
  131. package/dist/chunks/{tsMode-76kr53q0.js → tsMode-jy4m86rv.js} +83 -85
  132. package/dist/chunks/workspace-wrew8zk4.js +69 -0
  133. package/dist/chunks/{ws-client-6shc5rze.js → ws-client-ny4zc51r.js} +20 -22
  134. package/dist/iframe-entry.js +1780 -667
  135. package/dist/studio.js +52819 -36480
  136. package/dist/workers/editor.worker.js +1040 -1085
  137. package/dist/workers/json.worker.js +1946 -1991
  138. package/dist/workers/ts.worker.js +4960 -5005
  139. package/index.html +1 -0
  140. package/package.json +18 -52
  141. package/src/about/about-modal.ts +72 -123
  142. package/src/browse/library-commands.ts +20 -49
  143. package/src/browse/library-layouts.ts +87 -218
  144. package/src/browse/library-pane.ts +406 -438
  145. package/src/canvas/canvas-helpers.ts +0 -49
  146. package/src/canvas/canvas-live-render.ts +25 -2
  147. package/src/canvas/canvas-render.ts +666 -231
  148. package/src/canvas/canvas-surface.ts +0 -1
  149. package/src/canvas/canvas-utils.ts +310 -117
  150. package/src/canvas/dialog-path.ts +76 -0
  151. package/src/canvas/dialog-state.ts +67 -0
  152. package/src/canvas/diff-marks.ts +252 -0
  153. package/src/canvas/diff-toolbar.ts +349 -0
  154. package/src/canvas/diff-view.ts +123 -0
  155. package/src/canvas/edit-width-drag.ts +187 -0
  156. package/src/canvas/edit-width.ts +150 -0
  157. package/src/canvas/iframe-entry.ts +125 -8
  158. package/src/canvas/iframe-host.ts +271 -15
  159. package/src/canvas/iframe-interaction.ts +133 -13
  160. package/src/canvas/iframe-patch.ts +7 -1
  161. package/src/canvas/iframe-position.ts +5 -6
  162. package/src/canvas/iframe-protocol.ts +106 -5
  163. package/src/canvas/iframe-render.ts +373 -5
  164. package/src/canvas/iframe-slash.ts +2 -2
  165. package/src/canvas/iframe-subtree.ts +5 -8
  166. package/src/canvas/path-mapping.ts +25 -3
  167. package/src/canvas/popover-path.ts +106 -0
  168. package/src/canvas/popover-state.ts +155 -0
  169. package/src/canvas/surface-registry.ts +21 -10
  170. package/src/collab/presence-chips.ts +51 -73
  171. package/src/commands/app-commands.ts +10 -0
  172. package/src/commands/budget.ts +12 -0
  173. package/src/commands/command-args.ts +369 -6
  174. package/src/commands/defaults.ts +44 -14
  175. package/src/commands/live-context.ts +11 -5
  176. package/src/commands/reference.ts +12 -2
  177. package/src/commands/registry.ts +165 -8
  178. package/src/content/entry-commands.ts +16 -23
  179. package/src/content/entry-editor.ts +144 -101
  180. package/src/editor/canvas-slash-bridge.ts +2 -2
  181. package/src/editor/context-menu.ts +49 -200
  182. package/src/editor/convert-to-component.ts +42 -82
  183. package/src/editor/convert-to-repeater.ts +132 -173
  184. package/src/editor/inline-edit.ts +11 -0
  185. package/src/editor/shortcuts.ts +65 -26
  186. package/src/editor/slash-menu.ts +150 -157
  187. package/src/files/file-ops.ts +117 -11
  188. package/src/files/files.ts +943 -660
  189. package/src/files/json-layout.ts +474 -0
  190. package/src/files/serialize-document.ts +8 -1
  191. package/src/format/convert-file.ts +16 -10
  192. package/src/format/format-host.ts +50 -1
  193. package/src/github/github-auth.ts +71 -29
  194. package/src/github/github-publish.ts +57 -65
  195. package/src/grid/cell-editors.ts +46 -4
  196. package/src/grid/cell-popovers.ts +65 -62
  197. package/src/grid/grid-open.ts +86 -64
  198. package/src/grid/grid-panel.ts +390 -469
  199. package/src/grid/redirects-grid.ts +40 -44
  200. package/src/hosting/layout.ts +2 -0
  201. package/src/i18n/i18n-commands.ts +127 -62
  202. package/src/media/media-pane.ts +83 -133
  203. package/src/new-project/add-repo-modal.ts +125 -176
  204. package/src/new-project/import-tab.ts +181 -252
  205. package/src/new-project/location-fields.ts +93 -160
  206. package/src/new-project/new-project-modal.ts +376 -367
  207. package/src/packages/jxsuite-update.ts +76 -18
  208. package/src/panels/activity-panel.ts +137 -104
  209. package/src/panels/ai-chat/chat-markdown.ts +15 -13
  210. package/src/panels/ai-chat/chat-view.ts +307 -472
  211. package/src/panels/ai-chat/composer.ts +175 -163
  212. package/src/panels/ai-chat/sessions-view.ts +31 -62
  213. package/src/panels/ai-panel.ts +210 -185
  214. package/src/panels/block-action-bar.ts +437 -643
  215. package/src/panels/bottom-dock.ts +112 -47
  216. package/src/panels/chat-panel.ts +19 -14
  217. package/src/panels/data-explorer.ts +141 -102
  218. package/src/panels/data-grid.ts +183 -150
  219. package/src/panels/dnd.ts +75 -20
  220. package/src/panels/editors.ts +26 -19
  221. package/src/panels/elements-panel.ts +243 -186
  222. package/src/panels/empty-state.ts +26 -42
  223. package/src/panels/events-panel.ts +950 -729
  224. package/src/panels/formula-workspace.ts +434 -207
  225. package/src/panels/frontmatter-fields.ts +185 -153
  226. package/src/panels/frontmatter-panel.ts +411 -187
  227. package/src/panels/git-diff-open.ts +148 -0
  228. package/src/panels/git-panel.ts +679 -605
  229. package/src/panels/head-panel.ts +617 -435
  230. package/src/panels/i18n-panel.ts +153 -133
  231. package/src/panels/imports-panel.ts +388 -414
  232. package/src/panels/jump-bar.ts +174 -147
  233. package/src/panels/layers-panel.ts +785 -671
  234. package/src/panels/left-panel.ts +166 -94
  235. package/src/panels/navigator-panels.ts +1 -1
  236. package/src/panels/pane-context.ts +529 -677
  237. package/src/panels/pane-grid.ts +265 -241
  238. package/src/panels/panel-registry.ts +15 -4
  239. package/src/panels/problems-panel.ts +177 -99
  240. package/src/panels/properties-panel.ts +1525 -966
  241. package/src/panels/provenance.ts +31 -113
  242. package/src/panels/quick-search.ts +217 -172
  243. package/src/panels/right-panel.ts +135 -169
  244. package/src/panels/seo-modal.ts +346 -167
  245. package/src/panels/settings-menu.ts +109 -646
  246. package/src/panels/settings-pane.ts +102 -86
  247. package/src/panels/signals-panel.ts +1318 -1172
  248. package/src/panels/statement-editor.ts +556 -428
  249. package/src/panels/style-panel.ts +1367 -630
  250. package/src/panels/style-utils.ts +36 -32
  251. package/src/panels/stylebook-doc.ts +30 -73
  252. package/src/panels/stylebook-layers-panel.ts +202 -109
  253. package/src/panels/stylebook-panel.ts +124 -88
  254. package/src/panels/tab-strip.ts +385 -287
  255. package/src/platforms/cloud.ts +106 -16
  256. package/src/platforms/devserver.ts +13 -0
  257. package/src/publish/deploy-checklist.ts +124 -78
  258. package/src/publish/publish-commands.ts +4 -12
  259. package/src/publish/publish-panel.ts +134 -328
  260. package/src/services/a11y-report.ts +100 -43
  261. package/src/services/ai-command-tools.ts +468 -0
  262. package/src/services/ai-session-store.ts +6 -0
  263. package/src/services/ai-system-prompt.ts +110 -18
  264. package/src/services/ai-tools.ts +28 -143
  265. package/src/services/ai-write-report.ts +174 -0
  266. package/src/services/document-assistant.ts +50 -2
  267. package/src/services/idle.ts +16 -14
  268. package/src/services/live-surfaces.ts +237 -0
  269. package/src/services/model-uri.ts +75 -0
  270. package/src/services/notify.ts +63 -6
  271. package/src/services/popover-report.ts +325 -0
  272. package/src/services/surface-registry.ts +56 -0
  273. package/src/services/tool-executor.ts +6 -0
  274. package/src/settings/contexts-section.ts +301 -299
  275. package/src/settings/contributed-section.ts +361 -222
  276. package/src/settings/css-vars-editor.ts +320 -325
  277. package/src/settings/defs-editor.ts +572 -535
  278. package/src/settings/dependencies-editor.ts +79 -107
  279. package/src/settings/extension-commands.ts +379 -0
  280. package/src/settings/extension-rows.ts +113 -0
  281. package/src/settings/extensions-section.ts +287 -0
  282. package/src/settings/general-settings.ts +130 -181
  283. package/src/settings/head-editor.ts +10 -305
  284. package/src/settings/locales-section.ts +146 -196
  285. package/src/settings/preferences-accounts.ts +1 -1
  286. package/src/settings/preferences-dialog.ts +350 -330
  287. package/src/settings/project-sections.ts +108 -181
  288. package/src/settings/schema-field-ui.ts +11 -399
  289. package/src/settings/section-registry.ts +8 -1
  290. package/src/settings/settings-document.ts +31 -29
  291. package/src/shell/tree.ts +42 -87
  292. package/src/shell.ts +48 -36
  293. package/src/studio.ts +90 -67
  294. package/src/style/token-ref.ts +0 -39
  295. package/src/surfaces/about.json +263 -0
  296. package/src/surfaces/about.ts +163 -0
  297. package/src/surfaces/add-repo.json +486 -0
  298. package/src/surfaces/add-repo.ts +236 -0
  299. package/src/surfaces/ai-chat.json +2185 -0
  300. package/src/surfaces/ai-chat.ts +549 -0
  301. package/src/surfaces/ai-credentials-form.json +332 -0
  302. package/src/surfaces/ai-credentials-form.ts +151 -0
  303. package/src/surfaces/ai-managed-connect.json +108 -0
  304. package/src/surfaces/ai-managed-connect.ts +123 -0
  305. package/src/surfaces/ai-model-picker.json +114 -0
  306. package/src/surfaces/ai-model-picker.ts +139 -0
  307. package/src/surfaces/block-action-bar.json +640 -0
  308. package/src/surfaces/block-action-bar.ts +368 -0
  309. package/src/surfaces/bottom-dock.json +154 -0
  310. package/src/surfaces/bottom-dock.ts +125 -0
  311. package/src/surfaces/canvas-stage.json +444 -0
  312. package/src/surfaces/canvas-stage.ts +253 -0
  313. package/src/surfaces/cf-account-picker.json +300 -0
  314. package/src/surfaces/cf-account-picker.ts +214 -0
  315. package/src/surfaces/commandbar.json +984 -0
  316. package/src/{panels/toolbar.ts → surfaces/commandbar.ts} +414 -389
  317. package/src/surfaces/convert-repeater.json +309 -0
  318. package/src/surfaces/convert-repeater.ts +276 -0
  319. package/src/surfaces/data-actions.json +157 -0
  320. package/src/surfaces/data-actions.ts +115 -0
  321. package/src/surfaces/dialog.json +289 -0
  322. package/src/surfaces/dialog.ts +343 -0
  323. package/src/surfaces/diff-toolbar.json +266 -0
  324. package/src/surfaces/diff-toolbar.ts +139 -0
  325. package/src/surfaces/doc-header.json +739 -0
  326. package/src/surfaces/doc-header.ts +223 -0
  327. package/src/surfaces/empty-state.json +152 -0
  328. package/src/surfaces/empty-state.ts +173 -0
  329. package/src/surfaces/entry-editor.json +281 -0
  330. package/src/surfaces/entry-editor.ts +191 -0
  331. package/src/surfaces/expression-editor.json +977 -0
  332. package/src/surfaces/expression-editor.ts +266 -0
  333. package/src/surfaces/files-panel.json +592 -0
  334. package/src/surfaces/files-panel.ts +301 -0
  335. package/src/surfaces/formula-palette.json +364 -0
  336. package/src/surfaces/formula-palette.ts +340 -0
  337. package/src/surfaces/git-panel.json +1822 -0
  338. package/src/surfaces/git-panel.ts +272 -0
  339. package/src/surfaces/github-auth.json +112 -0
  340. package/src/surfaces/github-auth.ts +139 -0
  341. package/src/surfaces/github-publish.json +206 -0
  342. package/src/surfaces/github-publish.ts +169 -0
  343. package/src/surfaces/grid-cell.json +218 -0
  344. package/src/surfaces/grid-cell.ts +120 -0
  345. package/src/surfaces/grid-open.json +147 -0
  346. package/src/surfaces/grid-open.ts +87 -0
  347. package/src/surfaces/grid-panel.json +706 -0
  348. package/src/surfaces/grid-panel.ts +206 -0
  349. package/src/surfaces/grid-replace.json +179 -0
  350. package/src/surfaces/grid-replace.ts +89 -0
  351. package/src/surfaces/grid-views.json +446 -0
  352. package/src/surfaces/grid-views.ts +172 -0
  353. package/src/surfaces/inspector-dock.json +187 -0
  354. package/src/surfaces/inspector-dock.ts +161 -0
  355. package/src/surfaces/jump-bar.json +243 -0
  356. package/src/surfaces/jump-bar.ts +129 -0
  357. package/src/surfaces/jxsuite-update.json +146 -0
  358. package/src/surfaces/jxsuite-update.ts +149 -0
  359. package/src/surfaces/library-pane.json +1509 -0
  360. package/src/surfaces/library-pane.ts +363 -0
  361. package/src/surfaces/logic-panel.json +1949 -0
  362. package/src/surfaces/logic-panel.ts +369 -0
  363. package/src/surfaces/logic-workspace.json +685 -0
  364. package/src/surfaces/logic-workspace.ts +238 -0
  365. package/src/surfaces/media-browser.json +303 -0
  366. package/src/surfaces/media-browser.ts +145 -0
  367. package/src/surfaces/media-field.json +163 -0
  368. package/src/surfaces/media-field.ts +116 -0
  369. package/src/surfaces/media-pane.json +513 -0
  370. package/src/surfaces/media-pane.ts +197 -0
  371. package/src/surfaces/menu.json +232 -0
  372. package/src/surfaces/menu.ts +375 -0
  373. package/src/surfaces/navigator-dock.json +113 -0
  374. package/src/surfaces/navigator-dock.ts +130 -0
  375. package/src/surfaces/new-project.json +1654 -0
  376. package/src/surfaces/new-project.ts +411 -0
  377. package/src/surfaces/palette.json +535 -0
  378. package/src/surfaces/pane-context.json +1497 -0
  379. package/src/surfaces/pane-context.ts +513 -0
  380. package/src/surfaces/pane-grid.json +188 -0
  381. package/src/surfaces/pane-grid.ts +250 -0
  382. package/src/surfaces/panel-activity.json +563 -0
  383. package/src/surfaces/panel-activity.ts +187 -0
  384. package/src/surfaces/panel-data.json +141 -0
  385. package/src/surfaces/panel-data.ts +156 -0
  386. package/src/surfaces/panel-deploy-checklist.json +283 -0
  387. package/src/surfaces/panel-deploy-checklist.ts +175 -0
  388. package/src/surfaces/panel-elements.json +367 -0
  389. package/src/surfaces/panel-elements.ts +175 -0
  390. package/src/surfaces/panel-i18n.json +569 -0
  391. package/src/surfaces/panel-i18n.ts +212 -0
  392. package/src/surfaces/panel-imports.json +780 -0
  393. package/src/surfaces/panel-imports.ts +209 -0
  394. package/src/surfaces/panel-outline.json +734 -0
  395. package/src/surfaces/panel-outline.ts +326 -0
  396. package/src/surfaces/panel-page.json +1017 -0
  397. package/src/surfaces/panel-page.ts +240 -0
  398. package/src/surfaces/panel-problems.json +497 -0
  399. package/src/surfaces/panel-problems.ts +157 -0
  400. package/src/surfaces/panel-signals.json +1973 -0
  401. package/src/surfaces/panel-signals.ts +436 -0
  402. package/src/surfaces/panel-stylebook-layers.json +317 -0
  403. package/src/surfaces/panel-stylebook-layers.ts +155 -0
  404. package/src/surfaces/preferences.json +850 -0
  405. package/src/surfaces/preferences.ts +332 -0
  406. package/src/surfaces/progress-modal.json +110 -0
  407. package/src/surfaces/progress-modal.ts +150 -0
  408. package/src/surfaces/properties-panel.json +1578 -0
  409. package/src/surfaces/properties-panel.ts +337 -0
  410. package/src/surfaces/publish.json +945 -0
  411. package/src/surfaces/publish.ts +392 -0
  412. package/src/surfaces/push-plan.json +110 -0
  413. package/src/surfaces/push-plan.ts +87 -0
  414. package/src/surfaces/rail.json +255 -0
  415. package/src/surfaces/rail.ts +206 -0
  416. package/src/surfaces/reference-field.json +191 -0
  417. package/src/surfaces/reference-field.ts +168 -0
  418. package/src/surfaces/schema-builder.json +1011 -0
  419. package/src/surfaces/schema-builder.ts +181 -0
  420. package/src/surfaces/schema-form.json +1013 -0
  421. package/src/surfaces/schema-form.ts +287 -0
  422. package/src/surfaces/secret-field.json +60 -0
  423. package/src/surfaces/secret-field.ts +146 -0
  424. package/src/surfaces/seo.json +932 -0
  425. package/src/surfaces/seo.ts +334 -0
  426. package/src/surfaces/settings-contexts.json +538 -0
  427. package/src/surfaces/settings-contexts.ts +196 -0
  428. package/src/surfaces/settings-contributed.json +489 -0
  429. package/src/surfaces/settings-contributed.ts +199 -0
  430. package/src/surfaces/settings-css-vars.json +820 -0
  431. package/src/surfaces/settings-css-vars.ts +199 -0
  432. package/src/surfaces/settings-defs.json +1363 -0
  433. package/src/surfaces/settings-defs.ts +232 -0
  434. package/src/surfaces/settings-deploy.json +108 -0
  435. package/src/surfaces/settings-deploy.ts +135 -0
  436. package/src/surfaces/settings-extensions.json +486 -0
  437. package/src/surfaces/settings-extensions.ts +201 -0
  438. package/src/surfaces/settings-head.json +779 -0
  439. package/src/surfaces/settings-head.ts +397 -0
  440. package/src/surfaces/settings-locales.json +420 -0
  441. package/src/surfaces/settings-locales.ts +137 -0
  442. package/src/surfaces/settings-overview.json +423 -0
  443. package/src/surfaces/settings-overview.ts +218 -0
  444. package/src/surfaces/settings-packages.json +549 -0
  445. package/src/surfaces/settings-packages.ts +158 -0
  446. package/src/surfaces/settings-pane.json +147 -0
  447. package/src/surfaces/settings-pane.ts +150 -0
  448. package/src/surfaces/settings-rawjson.json +104 -0
  449. package/src/surfaces/settings-rawjson.ts +107 -0
  450. package/src/surfaces/shell.json +99 -0
  451. package/src/surfaces/shell.ts +30 -0
  452. package/src/surfaces/slash-menu.json +180 -0
  453. package/src/surfaces/slash-menu.ts +272 -0
  454. package/src/surfaces/statements.json +607 -0
  455. package/src/surfaces/statements.ts +238 -0
  456. package/src/surfaces/statusbar.json +94 -0
  457. package/src/{panels → surfaces}/statusbar.ts +163 -90
  458. package/src/surfaces/style-panel.json +1643 -0
  459. package/src/surfaces/style-panel.ts +338 -0
  460. package/src/surfaces/stylebook-chrome.json +122 -0
  461. package/src/surfaces/stylebook-chrome.ts +122 -0
  462. package/src/surfaces/tab-strip.json +448 -0
  463. package/src/surfaces/tab-strip.ts +200 -0
  464. package/src/surfaces/target-line.json +419 -0
  465. package/src/surfaces/target-line.ts +349 -0
  466. package/src/surfaces/toasts.json +189 -0
  467. package/src/surfaces/welcome.json +571 -0
  468. package/src/surfaces/welcome.ts +338 -0
  469. package/src/tabs/project-config.ts +71 -15
  470. package/src/tabs/tab.ts +52 -1
  471. package/src/types.ts +22 -0
  472. package/src/ui/ai-credentials-form.ts +104 -100
  473. package/src/ui/ai-managed-connect.ts +54 -36
  474. package/src/ui/ai-model-picker.ts +75 -47
  475. package/src/ui/cf-account-picker.ts +76 -141
  476. package/src/ui/color-selector.ts +80 -301
  477. package/src/ui/dynamic-slot.ts +43 -283
  478. package/src/ui/expression-editor.ts +797 -576
  479. package/src/ui/field-input.ts +8 -181
  480. package/src/ui/form-controls.ts +838 -366
  481. package/src/ui/formula-chips.ts +80 -85
  482. package/src/ui/kit.ts +33 -0
  483. package/src/ui/layers.ts +293 -593
  484. package/src/ui/media-picker.ts +203 -284
  485. package/src/ui/panel-resize.ts +251 -64
  486. package/src/ui/popover-surface.ts +153 -0
  487. package/src/ui/progress-modal.ts +22 -60
  488. package/src/ui/regions.ts +13 -7
  489. package/src/ui/schema-form.ts +906 -440
  490. package/src/ui/surface.ts +122 -0
  491. package/src/ui/unit-selector.ts +15 -131
  492. package/src/ui/value-source.ts +14 -0
  493. package/src/ui/virtual-window.ts +88 -9
  494. package/src/utils/canvas-media.ts +72 -0
  495. package/src/utils/edit-display.ts +7 -2
  496. package/src/utils/element-selectors.ts +69 -0
  497. package/src/utils/link-target.ts +2 -2
  498. package/src/utils/studio-utils.ts +0 -10
  499. package/src/view.ts +15 -0
  500. package/src/workspace/pane-derive.ts +36 -14
  501. package/src/workspace/workspace.ts +15 -6
  502. package/styles/canvas.css +72 -467
  503. package/styles/forced-colors.css +48 -82
  504. package/styles/forced-colors.json +41 -0
  505. package/styles/inspector.css +2 -1301
  506. package/styles/overlays.css +96 -2823
  507. package/styles/panels.css +6 -1423
  508. package/styles/shell-frame.css +272 -0
  509. package/styles/shell-frame.json +227 -0
  510. package/styles/shell.css +0 -1568
  511. package/styles/tokens.css +65 -136
  512. package/styles/tokens.json +84 -0
  513. package/dist/chunks/Overlay.dev-etqjwyf9.js +0 -23
  514. package/dist/chunks/adapter-jkcyhgtr.js +0 -14
  515. package/dist/chunks/cf-account-picker-en86v7x7.js +0 -163
  516. package/dist/chunks/cf-settings-45fgyx8y.js +0 -21
  517. package/dist/chunks/components-zmx10t62.js +0 -21
  518. package/dist/chunks/content-source-48xg86wj.js +0 -49
  519. package/dist/chunks/convert-to-repeater-43tfn7cs.js +0 -268
  520. package/dist/chunks/editor-cptq5jp1.js +0 -37
  521. package/dist/chunks/entry-commands-e63f1xc0.js +0 -46
  522. package/dist/chunks/extension-sections-txv08xxg.js +0 -311
  523. package/dist/chunks/file-ops-wbh4hhsx.js +0 -48
  524. package/dist/chunks/files-3kfkwhk4.js +0 -93
  525. package/dist/chunks/flow-qbfgrpeh.js +0 -634
  526. package/dist/chunks/focus-trap.esm-9t2drp0g.js +0 -1025
  527. package/dist/chunks/focus-visible-6eg70z18.js +0 -167
  528. package/dist/chunks/format-host-w16q81tf.js +0 -43
  529. package/dist/chunks/fs-events-hrrg328g.js +0 -21
  530. package/dist/chunks/git-panel-532whr1y.js +0 -59
  531. package/dist/chunks/index-zqxmqxmh.js +0 -109
  532. package/dist/chunks/jx-validate-8er6gbxy.js +0 -19
  533. package/dist/chunks/layers-panel-07hm7g5j.js +0 -67
  534. package/dist/chunks/layers-q75tj2mf.js +0 -45
  535. package/dist/chunks/lit-html-j055mkh8.js +0 -22
  536. package/dist/chunks/monaco-buffer-dqw0xxpx.js +0 -25
  537. package/dist/chunks/notify-yjm79n4s.js +0 -30
  538. package/dist/chunks/parse-24d0gay3.js +0 -19
  539. package/dist/chunks/platform-ba1j1gbh.js +0 -16
  540. package/dist/chunks/publish-panel-v9st96ja.js +0 -29
  541. package/dist/chunks/quick-search-zccjp6gv.js +0 -66
  542. package/dist/chunks/references-3qx8fkyp.js +0 -29
  543. package/dist/chunks/right-panel-vm3b6kwy.js +0 -46
  544. package/dist/chunks/section-registry-sx1ykvkw.js +0 -30
  545. package/dist/chunks/sp-overlay.dev-qgvhnxf4.js +0 -18
  546. package/dist/chunks/sp-popover.dev-n2etmqdp.js +0 -9
  547. package/dist/chunks/sp-progress-circle.dev-hryhj0es.js +0 -15
  548. package/dist/chunks/sp-tooltip.dev-4sastdnw.js +0 -15
  549. package/dist/chunks/sp-tray.dev-tkbscm06.js +0 -199
  550. package/dist/chunks/studio-0a5qrh01.js +0 -3
  551. package/dist/chunks/studio-0bq6eh7v.js +0 -12
  552. package/dist/chunks/studio-18j3bmcz.js +0 -14
  553. package/dist/chunks/studio-1ngbejft.js +0 -181
  554. package/dist/chunks/studio-4b5z1x43.js +0 -424
  555. package/dist/chunks/studio-4n2b5gzb.js +0 -357
  556. package/dist/chunks/studio-4rzyrtjz.js +0 -426
  557. package/dist/chunks/studio-5fx3g9jg.js +0 -4325
  558. package/dist/chunks/studio-5myknm0a.js +0 -1903
  559. package/dist/chunks/studio-7afd21nw.js +0 -67
  560. package/dist/chunks/studio-7nte2hj4.js +0 -613
  561. package/dist/chunks/studio-8jpzqk5s.js +0 -128
  562. package/dist/chunks/studio-8q517dfr.js +0 -24
  563. package/dist/chunks/studio-950k0dx6.js +0 -6939
  564. package/dist/chunks/studio-9n4mrmnb.js +0 -184
  565. package/dist/chunks/studio-a0tswy0w.js +0 -58
  566. package/dist/chunks/studio-ahnzd9rg.js +0 -23
  567. package/dist/chunks/studio-cmb03bg5.js +0 -13890
  568. package/dist/chunks/studio-d1ks410h.js +0 -175
  569. package/dist/chunks/studio-ef49pnzx.js +0 -387
  570. package/dist/chunks/studio-eqq1w638.js +0 -113
  571. package/dist/chunks/studio-ew0djmhg.js +0 -341
  572. package/dist/chunks/studio-gfgb8pe6.js +0 -1652
  573. package/dist/chunks/studio-h4rxscfc.js +0 -10
  574. package/dist/chunks/studio-jc994dnr.js +0 -1066
  575. package/dist/chunks/studio-kyh9avvv.js +0 -28
  576. package/dist/chunks/studio-m3hwn7y1.js +0 -120
  577. package/dist/chunks/studio-mtfnaqs9.js +0 -659
  578. package/dist/chunks/studio-n6j9t10q.js +0 -318
  579. package/dist/chunks/studio-n8b9wqwy.js +0 -291
  580. package/dist/chunks/studio-qcy05dp8.js +0 -1743
  581. package/dist/chunks/studio-qq6jym04.js +0 -53
  582. package/dist/chunks/studio-rdx8jcxy.js +0 -83
  583. package/dist/chunks/studio-rn9ta2mz.js +0 -111
  584. package/dist/chunks/studio-t7qb9db8.js +0 -665
  585. package/dist/chunks/studio-tmc5emrw.js +0 -8
  586. package/dist/chunks/studio-z6nw2ek2.js +0 -18
  587. package/dist/chunks/studio-zczps70q.js +0 -378
  588. package/dist/chunks/studio-zqazsct2.js +0 -1823
  589. package/dist/chunks/workspace-fjx52ryv.js +0 -89
  590. package/src/panels/activity-bar.ts +0 -251
  591. package/src/panels/panel-scheduler.ts +0 -219
  592. package/src/panels/style-inputs.ts +0 -237
  593. package/src/panels/target-line.ts +0 -274
  594. package/src/panels/welcome-screen.ts +0 -346
  595. package/src/ui/button-group.ts +0 -102
  596. package/src/ui/choice-field.ts +0 -72
  597. package/src/ui/field-row.ts +0 -249
  598. package/src/ui/formula-palette.ts +0 -213
  599. package/src/ui/icons.ts +0 -52
  600. package/src/ui/jx-theme.ts +0 -130
  601. package/src/ui/spectrum.ts +0 -340
  602. package/src/ui/value-selector.ts +0 -174
  603. package/src/ui/widgets.ts +0 -172
  604. /package/dist/chunks/{javascript-s56a8dpk.css → javascript-4abzjcy9.css} +0 -0
  605. /package/dist/chunks/{jsonMode-zr9sw0c7.css → jsonMode-vvmpmk34.css} +0 -0
  606. /package/dist/chunks/{monaco-setup-pav68602.css → monaco-setup-8vbyqnhr.css} +0 -0
  607. /package/dist/chunks/{tsMode-ef187txx.css → tsMode-hnxxb73h.css} +0 -0
@@ -1,3 +1,35 @@
1
+ var __chunkGraphs;
2
+ var __chunkSeen;
3
+ var __chunkNonce;
4
+ var __preload = (id, seenOnly) => {
5
+ for (var [base, graph, ids] of __chunkGraphs || [])
6
+ for (var stack = [id], g = globalThis, d = g.document, head, j, node, k, link;j = stack.pop(); )
7
+ if (!__chunkSeen[j] && (node = graph[j])) {
8
+ __chunkSeen[j] = 1;
9
+ for (k = 1;k < node.length; k++)
10
+ stack.push(ids[node[k]]);
11
+ if (!seenOnly && j !== id && (head = d && d.head)) {
12
+ if (__chunkNonce === undefined)
13
+ __chunkNonce = (k = d.querySelector("meta[property=csp-nonce]")) && (k.nonce || k.getAttribute("nonce")) || "";
14
+ link = d.createElement("link");
15
+ link.rel = "modulepreload";
16
+ link.crossOrigin = "";
17
+ if (__chunkNonce)
18
+ link.nonce = __chunkNonce;
19
+ link.href = new g.URL(node[0], base);
20
+ head.appendChild(link);
21
+ }
22
+ }
23
+ };
24
+ var __chunks = (base, ids, nodes, entry) => {
25
+ for (var graph = {}, i = 0;i < ids.length; i++)
26
+ graph[ids[i]] = nodes[i];
27
+ (__chunkGraphs ||= []).push([base, graph, ids]);
28
+ __chunkSeen ||= {};
29
+ __preload(ids[entry], 1);
30
+ };
31
+ __chunks(import.meta.url,["f4ktqr2q","a73p0pqm","eptb614w","abk6qyee","780pvfbv","3sqv46sn","xgg3kfw7","yy10wk9r","5cndyft8","sp6tna8v","47z3ytva","2r16ez41","g7nm1rgb","t0n6h2rn","wbp1cdws","xbh5bhtr","v17df7b8","anwybnkn","44ez96fc","5e7jev23","s890b918","6v2ac08j","q99sy9rf","nbyxee1y","15g3n6xv","b27vq81n"],[["./iframe-entry.js"],["./chunks/tree-a73p0pqm.js"],["./chunks/tooltip-eptb614w.js",23],["./chunks/textfield-abk6qyee.js"],["./chunks/toast-780pvfbv.js",24],["./chunks/toast-host-3sqv46sn.js",24],["./chunks/color-xgg3kfw7.js",25],["./chunks/icons-yy10wk9r.js"],["./chunks/number-field-5cndyft8.js"],["./chunks/action-group-sp6tna8v.js"],["./chunks/popover-47z3ytva.js",23],["./chunks/select-2r16ez41.js"],["./chunks/split-g7nm1rgb.js"],["./chunks/swatch-group-t0n6h2rn.js"],["./chunks/tabs-wbp1cdws.js"],["./chunks/toolbar-xbh5bhtr.js"],["./chunks/color-area-v17df7b8.js",25],["./chunks/color-field-anwybnkn.js",25,23],["./chunks/color-slider-44ez96fc.js",25],["./chunks/combobox-5e7jev23.js",23],["./chunks/dialog-s890b918.js"],["./chunks/listbox-6v2ac08j.js"],["./chunks/menu-q99sy9rf.js",23],["./chunks/iframe-entry-nbyxee1y.js"],["./chunks/iframe-entry-15g3n6xv.js"],["./chunks/iframe-entry-b27vq81n.js"]],0);
32
+
1
33
  // src/canvas/iframe-channel.ts
2
34
  var ENVELOPE = "jx:canvas";
3
35
  function postMessageChannel(opts) {
@@ -31,6 +63,17 @@ function postMessageChannel(opts) {
31
63
  };
32
64
  }
33
65
 
66
+ // src/utils/geometry.ts
67
+ function rectOf(el) {
68
+ return el.getBoundingClientRect();
69
+ }
70
+ function rectOfRange(r) {
71
+ return r.getBoundingClientRect();
72
+ }
73
+ function elementAtPoint(x, y, root = document) {
74
+ return root.elementFromPoint(x, y);
75
+ }
76
+
34
77
  // ../schema/src/guards.ts
35
78
  function isJsonObject(value) {
36
79
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -91,7 +134,17 @@ function paramNames(parameters) {
91
134
  return parameters.map((p) => typeof p === "string" ? p : p.name);
92
135
  }
93
136
  function isTagExpression(tagName) {
94
- return isJsonObject(tagName) && isJsonObject(tagName.$expression);
137
+ if (!isJsonObject(tagName) || !isJsonObject(tagName.$expression)) {
138
+ return false;
139
+ }
140
+ const expression = tagName.$expression;
141
+ if (expression.operator === "?:") {
142
+ return typeof expression.value === "string" && typeof expression.initial === "string";
143
+ }
144
+ if (expression.operator === "switch") {
145
+ return isJsonObject(expression.cases) && Object.values(expression.cases).every((tag) => typeof tag === "string") && typeof expression.default === "string";
146
+ }
147
+ return false;
95
148
  }
96
149
  function tagNameCandidates(tagName) {
97
150
  if (typeof tagName === "string") {
@@ -292,6 +345,13 @@ class EffectScope {
292
345
  function effectScope(detached) {
293
346
  return new EffectScope(detached);
294
347
  }
348
+ function onScopeDispose(fn, failSilently = false) {
349
+ if (activeEffectScope) {
350
+ activeEffectScope.cleanups.push(fn);
351
+ } else if (!failSilently) {
352
+ warn(`onScopeDispose() is called when there is no active effect scope to be associated with.`);
353
+ }
354
+ }
295
355
  var activeSub;
296
356
  var pausedQueueEffects = /* @__PURE__ */ new WeakSet;
297
357
 
@@ -1127,6 +1187,7 @@ class ReadonlyReactiveHandler extends BaseReactiveHandler {
1127
1187
  }
1128
1188
  var mutableHandlers = /* @__PURE__ */ new MutableReactiveHandler;
1129
1189
  var readonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler;
1190
+ var shallowReactiveHandlers = /* @__PURE__ */ new MutableReactiveHandler(true);
1130
1191
  var toShallow = (value) => value;
1131
1192
  var getProto = (v) => Reflect.getPrototypeOf(v);
1132
1193
  function createIterableMethod(method, isReadonly2, isShallow2) {
@@ -1304,6 +1365,9 @@ function createInstrumentationGetter(isReadonly2, shallow) {
1304
1365
  var mutableCollectionHandlers = {
1305
1366
  get: /* @__PURE__ */ createInstrumentationGetter(false, false)
1306
1367
  };
1368
+ var shallowCollectionHandlers = {
1369
+ get: /* @__PURE__ */ createInstrumentationGetter(false, true)
1370
+ };
1307
1371
  var readonlyCollectionHandlers = {
1308
1372
  get: /* @__PURE__ */ createInstrumentationGetter(true, false)
1309
1373
  };
@@ -1338,6 +1402,9 @@ function reactive(target) {
1338
1402
  }
1339
1403
  return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap);
1340
1404
  }
1405
+ function shallowReactive(target) {
1406
+ return createReactiveObject(target, false, shallowReactiveHandlers, shallowCollectionHandlers, shallowReactiveMap);
1407
+ }
1341
1408
  function readonly(target) {
1342
1409
  return createReactiveObject(target, true, readonlyHandlers, readonlyCollectionHandlers, readonlyMap);
1343
1410
  }
@@ -1514,6 +1581,87 @@ function resolveAtQuery(atKey, mediaQueries) {
1514
1581
  }
1515
1582
  return null;
1516
1583
  }
1584
+ function isDeclarationAtRule(atKey) {
1585
+ return atKey.startsWith("@position-try") || atKey.startsWith("@property") || atKey.startsWith("@font-face") || atKey.startsWith("@counter-style");
1586
+ }
1587
+ function isKeyframesAtRule(atKey) {
1588
+ return atKey.startsWith("@keyframes");
1589
+ }
1590
+ function resolveNestedSelector(scope, key) {
1591
+ const resolved = [];
1592
+ for (const scopePart of splitSelectorList(scope)) {
1593
+ for (const keyPart of splitSelectorList(key)) {
1594
+ resolved.push(resolveOneNestedSelector(scopePart, keyPart));
1595
+ }
1596
+ }
1597
+ return resolved.join(", ");
1598
+ }
1599
+ function resolveOneNestedSelector(scope, key) {
1600
+ if (key.startsWith("&")) {
1601
+ return key.replaceAll("&", scope);
1602
+ }
1603
+ if (key.startsWith("[") || key.startsWith(":") || key.startsWith(".")) {
1604
+ return `${scope}${key}`;
1605
+ }
1606
+ return `${scope} ${key}`;
1607
+ }
1608
+ function splitSelectorList(selector) {
1609
+ const members = [];
1610
+ let depth = 0;
1611
+ let quote = null;
1612
+ let start = 0;
1613
+ for (let i = 0;i < selector.length; i += 1) {
1614
+ const ch = selector[i];
1615
+ if (quote) {
1616
+ if (ch === "\\") {
1617
+ i += 1;
1618
+ } else if (ch === quote) {
1619
+ quote = null;
1620
+ }
1621
+ continue;
1622
+ }
1623
+ if (ch === '"' || ch === "'") {
1624
+ quote = ch;
1625
+ } else if (ch === "(" || ch === "[") {
1626
+ depth += 1;
1627
+ } else if (ch === ")" || ch === "]") {
1628
+ depth = Math.max(0, depth - 1);
1629
+ } else if (ch === "," && depth === 0) {
1630
+ members.push(selector.slice(start, i));
1631
+ start = i + 1;
1632
+ }
1633
+ }
1634
+ members.push(selector.slice(start));
1635
+ const trimmed = members.map((member) => member.trim()).filter((member) => member !== "");
1636
+ return trimmed.length > 0 ? trimmed : [selector];
1637
+ }
1638
+ var COMPOUND_BREAK = /[\s>+~,()]/;
1639
+ var LEADING_TYPE = /^[A-Za-z_\u{00A0}-\u{FFFF}][\w\u{00A0}-\u{FFFF}-]*/u;
1640
+ function transposeOpenAttribute(selector, options) {
1641
+ let out = "";
1642
+ let from = 0;
1643
+ for (;; ) {
1644
+ const at = selector.indexOf("[open]", from);
1645
+ if (at === -1) {
1646
+ return out + selector.slice(from);
1647
+ }
1648
+ let start = at;
1649
+ while (start > 0 && !COMPOUND_BREAK.test(selector[start - 1])) {
1650
+ start -= 1;
1651
+ }
1652
+ const type = LEADING_TYPE.exec(selector.slice(start, at))?.[0]?.toLowerCase();
1653
+ const dialog = type === undefined ? options.dialog === true : type === "dialog";
1654
+ out += selector.slice(from, at) + (dialog ? "[data-jx-dialog-open]" : "[open]");
1655
+ from = at + "[open]".length;
1656
+ }
1657
+ }
1658
+ function transposeCanvasOverlaySelector(selector, options = {}) {
1659
+ if (selector.includes("::backdrop")) {
1660
+ return null;
1661
+ }
1662
+ const transposed = selector.replaceAll(":popover-open", "[data-jx-popover-open]").replaceAll(":modal", "[data-jx-dialog-open]").replaceAll("[inert]", "[data-jx-inert]");
1663
+ return transposeOpenAttribute(transposed, options);
1664
+ }
1517
1665
  var COLOR_SCHEME_ATTR = "data-color-scheme";
1518
1666
  function pureSchemeOf(query) {
1519
1667
  const m = /^\(\s*prefers-color-scheme\s*:\s*(light|dark)\s*\)$/.exec(query.trim());
@@ -1531,6 +1679,195 @@ function schemeSelectors(selector, scheme) {
1531
1679
  forced: `:where(:root[${COLOR_SCHEME_ATTR}="${scheme}"]) ${selector}`
1532
1680
  };
1533
1681
  }
1682
+ function isNestedSelectorKey(key) {
1683
+ return key.startsWith(":") || key.startsWith(".") || key.startsWith("&") || key.startsWith("[");
1684
+ }
1685
+ function cssPropertyName(property) {
1686
+ return property.startsWith("--") ? property : camelToKebab(property);
1687
+ }
1688
+ function hashCss(text) {
1689
+ let h = 2166136261;
1690
+ for (let i = 0;i < text.length; i += 1) {
1691
+ h ^= text.charCodeAt(i);
1692
+ h = Math.imul(h, 16777619);
1693
+ }
1694
+ return (h >>> 0).toString(36);
1695
+ }
1696
+ function cssRuleText(conditions, selector, declarations) {
1697
+ const body = declarations.map(([property, value]) => `${property}: ${value}`).join("; ");
1698
+ let text = selector === null ? body : `${selector} { ${body} }`;
1699
+ for (let i = conditions.length - 1;i >= 0; i -= 1) {
1700
+ text = `${conditions[i]} { ${text} }`;
1701
+ }
1702
+ return text;
1703
+ }
1704
+ function cssKeyframesText(conditions, name, blocks) {
1705
+ const body = blocks.map(({ selector, declarations }) => `${selector} { ${declarations.map(([property, value]) => `${property}: ${value}`).join("; ")} }`).join(" ");
1706
+ let text = `@keyframes ${name} { ${body} }`;
1707
+ for (let i = conditions.length - 1;i >= 0; i -= 1) {
1708
+ text = `${conditions[i]} { ${text} }`;
1709
+ }
1710
+ return text;
1711
+ }
1712
+ function withoutKeyframes(block) {
1713
+ const keyframeKeys = Object.keys(block).filter((key) => isKeyframesAtRule(key));
1714
+ if (keyframeKeys.length === 0) {
1715
+ return block;
1716
+ }
1717
+ const rest = { ...block };
1718
+ for (const key of keyframeKeys) {
1719
+ delete rest[key];
1720
+ }
1721
+ return rest;
1722
+ }
1723
+ function compoundsOntoScope(key) {
1724
+ const rest = key.startsWith("&") ? key.slice(1) : key;
1725
+ return rest === "" || rest.startsWith(":") || rest.startsWith(".") || rest.startsWith("[");
1726
+ }
1727
+ function buildStyleRules(style, options = {}) {
1728
+ const {
1729
+ scope = null,
1730
+ mediaQueries = {},
1731
+ transposeValue = (value) => value,
1732
+ transposeSelector = (selector) => selector,
1733
+ resolveValue
1734
+ } = options;
1735
+ const rules = [];
1736
+ const isBlock = (value) => value !== null && typeof value === "object" && !Array.isArray(value) && !isRef(value);
1737
+ const blocksOf = (key, value) => {
1738
+ if (isBlock(value)) {
1739
+ return [value];
1740
+ }
1741
+ if (!isDeclarationAtRule(key) || !Array.isArray(value) || value.length === 0) {
1742
+ return [];
1743
+ }
1744
+ return value.every((entry) => isBlock(entry)) ? value : [];
1745
+ };
1746
+ const declarationValue = (property, value, reactive, target) => {
1747
+ if (value === undefined || value === null) {
1748
+ return null;
1749
+ }
1750
+ if (isRef(value)) {
1751
+ return reactive ? resolveValue?.(property, value, target) ?? null : null;
1752
+ }
1753
+ if (typeof value === "object") {
1754
+ return null;
1755
+ }
1756
+ const raw = String(value);
1757
+ if (isTemplateString(raw)) {
1758
+ return reactive ? resolveValue?.(property, raw, target) ?? null : null;
1759
+ }
1760
+ return transposeValue(raw);
1761
+ };
1762
+ const declarationsOf = (node, skipSelectorKeys, reactive = true, target = "self") => {
1763
+ const declarations = [];
1764
+ for (const [key, value] of Object.entries(node)) {
1765
+ if (blocksOf(key, value).length > 0) {
1766
+ continue;
1767
+ }
1768
+ if (skipSelectorKeys && (key.startsWith("@") || isNestedSelectorKey(key))) {
1769
+ continue;
1770
+ }
1771
+ if (key.startsWith("$")) {
1772
+ continue;
1773
+ }
1774
+ const resolved = declarationValue(key, value, reactive, target);
1775
+ if (resolved !== null) {
1776
+ declarations.push([cssPropertyName(key), resolved]);
1777
+ }
1778
+ }
1779
+ return declarations;
1780
+ };
1781
+ const emit = (conditions, selector, declarations, target, description) => {
1782
+ if (declarations.length === 0) {
1783
+ return;
1784
+ }
1785
+ let resolved = selector;
1786
+ if (resolved !== null) {
1787
+ const transposed = transposeSelector(resolved);
1788
+ if (transposed === null) {
1789
+ return;
1790
+ }
1791
+ resolved = transposed;
1792
+ }
1793
+ const text = cssRuleText(conditions, resolved, declarations);
1794
+ rules.push({
1795
+ text,
1796
+ conditions: [...conditions],
1797
+ selector: resolved,
1798
+ declarations,
1799
+ target,
1800
+ key: hashCss(text),
1801
+ ...typeof description === "string" && description !== "" ? { description } : {}
1802
+ });
1803
+ };
1804
+ const emitKeyframes = (atKey, block, conditions) => {
1805
+ const name = atKey.slice("@keyframes".length).trim();
1806
+ if (name === "") {
1807
+ return;
1808
+ }
1809
+ const blocks = [];
1810
+ for (const [key, value] of Object.entries(block)) {
1811
+ if (!isBlock(value)) {
1812
+ continue;
1813
+ }
1814
+ const declarations = declarationsOf(value, true, false, "unscoped");
1815
+ if (declarations.length > 0) {
1816
+ blocks.push({ declarations, selector: key.trim() });
1817
+ }
1818
+ }
1819
+ if (blocks.length === 0) {
1820
+ return;
1821
+ }
1822
+ const text = cssKeyframesText(conditions, name, blocks);
1823
+ rules.push({
1824
+ blocks,
1825
+ conditions: [...conditions],
1826
+ declarations: [],
1827
+ key: hashCss(text),
1828
+ selector: null,
1829
+ target: "unscoped",
1830
+ text
1831
+ });
1832
+ };
1833
+ const walkAt = (atKey, block, selector, conditions, target) => {
1834
+ if (atKey === "@--") {
1835
+ return;
1836
+ }
1837
+ if (isDeclarationAtRule(atKey)) {
1838
+ emit([...conditions, atKey], null, declarationsOf(block, false, true, "unscoped"), "unscoped", block["$description"]);
1839
+ return;
1840
+ }
1841
+ if (isKeyframesAtRule(atKey)) {
1842
+ emitKeyframes(atKey, block, conditions);
1843
+ return;
1844
+ }
1845
+ const query = resolveAtQuery(atKey, mediaQueries);
1846
+ const atRule = query === null ? atKey : `@media ${query}`;
1847
+ const scheme = query === null ? null : pureSchemeOf(query);
1848
+ if (scheme !== null && selector !== null) {
1849
+ const { auto, forced } = schemeSelectors(selector, scheme);
1850
+ walk(block, auto, [...conditions, atRule], target);
1851
+ walk(withoutKeyframes(block), forced, conditions, target);
1852
+ return;
1853
+ }
1854
+ walk(block, selector, [...conditions, atRule], target);
1855
+ };
1856
+ function walk(node, selector, conditions, target) {
1857
+ emit(conditions, selector, declarationsOf(node, true, true, target), target, node["$description"]);
1858
+ for (const [key, value] of Object.entries(node)) {
1859
+ for (const block of blocksOf(key, value)) {
1860
+ if (key.startsWith("@")) {
1861
+ walkAt(key, block, selector, conditions, target);
1862
+ } else if (selector !== null) {
1863
+ walk(block, resolveNestedSelector(selector, key), conditions, compoundsOntoScope(key) ? target : "descendant");
1864
+ }
1865
+ }
1866
+ }
1867
+ }
1868
+ walk(style, scope, [], "self");
1869
+ return rules;
1870
+ }
1534
1871
 
1535
1872
  // ../schema/src/intl.ts
1536
1873
  var DEFAULT_FORMAT_LOCALE = "en-US";
@@ -1762,8 +2099,8 @@ function withPageLocale(path, args, state) {
1762
2099
  filled[index] = locale;
1763
2100
  return filled;
1764
2101
  }
1765
- function isBlessedGlobal(ref2) {
1766
- return ref2.startsWith("window#/") && BLESSED_GLOBALS.has(ref2.slice("window#/".length));
2102
+ function isBlessedGlobal(ref) {
2103
+ return ref.startsWith("window#/") && BLESSED_GLOBALS.has(ref.slice("window#/".length));
1767
2104
  }
1768
2105
  function isMutating(op) {
1769
2106
  return MUTATING_OPS.has(op);
@@ -1802,24 +2139,43 @@ function resolveOperand(operand, state, event, iterCtx, trace) {
1802
2139
  trace?.report(trace.path ?? [], operand);
1803
2140
  return operand;
1804
2141
  }
1805
- function resolveExprRef(ref2, state, event, iterCtx) {
1806
- if (ref2 === "$reduce/acc") {
2142
+ function calleeOwner(ref, state, event, iterCtx) {
2143
+ const parentRef = (prefix) => {
2144
+ const rest = ref.slice(prefix.length);
2145
+ if (!rest.includes("/")) {
2146
+ return state;
2147
+ }
2148
+ return resolveExprRef(ref.slice(0, ref.lastIndexOf("/")), state, event, iterCtx);
2149
+ };
2150
+ if (ref.startsWith("#/state/")) {
2151
+ return parentRef("#/state/");
2152
+ }
2153
+ if (ref.startsWith("parent#/")) {
2154
+ return parentRef("parent#/");
2155
+ }
2156
+ if (ref.startsWith("$map/") || ref.startsWith("$args/")) {
2157
+ return ref.split("/").length > 2 ? resolveExprRef(ref.slice(0, ref.lastIndexOf("/")), state, event, iterCtx) : undefined;
2158
+ }
2159
+ return;
2160
+ }
2161
+ function resolveExprRef(ref, state, event, iterCtx) {
2162
+ if (ref === "$reduce/acc") {
1807
2163
  return iterCtx?.acc;
1808
2164
  }
1809
- if (ref2.startsWith("$reduce/")) {
2165
+ if (ref.startsWith("$reduce/")) {
1810
2166
  return iterCtx?.acc;
1811
2167
  }
1812
- if (ref2.startsWith("$args/")) {
1813
- const parts = ref2.slice("$args/".length).split("/");
2168
+ if (ref.startsWith("$args/")) {
2169
+ const parts = ref.slice("$args/".length).split("/");
1814
2170
  const base = iterCtx?.args?.[parts[0]];
1815
2171
  return parts.length > 1 ? getPath(base, parts.slice(1).join("/")) : base;
1816
2172
  }
1817
- if (ref2.startsWith("event#/")) {
1818
- const path = ref2.slice("event#/".length);
2173
+ if (ref.startsWith("event#/")) {
2174
+ const path = ref.slice("event#/".length);
1819
2175
  return getPath(event, path);
1820
2176
  }
1821
- if (ref2.startsWith("$map/")) {
1822
- const parts = ref2.split("/");
2177
+ if (ref.startsWith("$map/")) {
2178
+ const parts = ref.split("/");
1823
2179
  const [, key] = parts;
1824
2180
  let base;
1825
2181
  const map = scopeMap(state);
@@ -1832,23 +2188,23 @@ function resolveExprRef(ref2, state, event, iterCtx) {
1832
2188
  }
1833
2189
  return parts.length > 2 ? getPath(base, parts.slice(2).join("/")) : base;
1834
2190
  }
1835
- if (ref2.startsWith("#/state/")) {
1836
- return readPath(state, ref2.slice("#/state/".length));
2191
+ if (ref.startsWith("#/state/")) {
2192
+ return readPath(state, ref.slice("#/state/".length));
1837
2193
  }
1838
- if (ref2.startsWith("parent#/")) {
1839
- return readPath(state, ref2.slice("parent#/".length));
2194
+ if (ref.startsWith("parent#/")) {
2195
+ return readPath(state, ref.slice("parent#/".length));
1840
2196
  }
1841
- if (ref2.startsWith("window#/")) {
1842
- return getPath(globalThis.window, ref2.slice("window#/".length));
2197
+ if (ref.startsWith("window#/")) {
2198
+ return getPath(globalThis.window, ref.slice("window#/".length));
1843
2199
  }
1844
- if (ref2.startsWith("document#/")) {
1845
- return getPath(globalThis.document, ref2.slice("document#/".length));
2200
+ if (ref.startsWith("document#/")) {
2201
+ return getPath(globalThis.document, ref.slice("document#/".length));
1846
2202
  }
1847
- return readPath(state, ref2) ?? null;
2203
+ return readPath(state, ref) ?? null;
1848
2204
  }
1849
- function resolveWritableRef(ref2, state, _event, iterCtx) {
1850
- if (ref2.startsWith("$map/")) {
1851
- const parts = ref2.split("/");
2205
+ function resolveWritableRef(ref, state, _event, iterCtx) {
2206
+ if (ref.startsWith("$map/")) {
2207
+ const parts = ref.split("/");
1852
2208
  const [, key] = parts;
1853
2209
  let base;
1854
2210
  const map = scopeMap(state);
@@ -1870,8 +2226,8 @@ function resolveWritableRef(ref2, state, _event, iterCtx) {
1870
2226
  obj: scopeMap(state) ?? state
1871
2227
  };
1872
2228
  }
1873
- if (ref2.startsWith("#/state/")) {
1874
- const sub = ref2.slice("#/state/".length);
2229
+ if (ref.startsWith("#/state/")) {
2230
+ const sub = ref.slice("#/state/".length);
1875
2231
  const slash = sub.indexOf("/");
1876
2232
  if (slash === -1) {
1877
2233
  return { key: sub, obj: state };
@@ -1884,7 +2240,7 @@ function resolveWritableRef(ref2, state, _event, iterCtx) {
1884
2240
  }
1885
2241
  return { key: lastKey, obj };
1886
2242
  }
1887
- return { key: ref2, obj: state };
2243
+ return { key: ref, obj: state };
1888
2244
  }
1889
2245
  function evaluateExpression(node, state, event, iterCtx, trace) {
1890
2246
  const result = evaluateNode(node, state, event, iterCtx, trace);
@@ -1931,19 +2287,19 @@ function evaluateNode(node, state, event, iterCtx, trace) {
1931
2287
  }
1932
2288
  const callee = resolveExprRef(calleeRef, state, event, iterCtx);
1933
2289
  if (typeof callee === "function") {
1934
- return callee(...argValues);
2290
+ return callee.apply(calleeOwner(calleeRef, state, event, iterCtx), argValues);
1935
2291
  }
1936
2292
  if (callee && typeof callee === "object" && "$expression" in callee) {
1937
- const def2 = callee;
2293
+ const def = callee;
1938
2294
  const args = {};
1939
- for (const [i, p] of (def2.parameters ?? []).entries()) {
2295
+ for (const [i, p] of (def.parameters ?? []).entries()) {
1940
2296
  const name = typeof p === "string" ? p : p?.name ?? "";
1941
2297
  if (!name) {
1942
2298
  continue;
1943
2299
  }
1944
2300
  args[name] = argValues[i] === undefined && typeof p === "object" && p !== null && "default" in p ? p.default : argValues[i];
1945
2301
  }
1946
- return evaluateExpression(def2.$expression, state, event, { args, callDepth });
2302
+ return evaluateExpression(def.$expression, state, event, { args, callDepth });
1947
2303
  }
1948
2304
  throw new TypeError(`$expression: call target "${calleeRef}" is not callable`);
1949
2305
  }
@@ -2185,10 +2541,10 @@ function isNonRelativeRef(value) {
2185
2541
  function normalizeProjectPath(path) {
2186
2542
  return path.replaceAll("\\", "/").replace(/^\.\//, "").replace(/^\/+/, "").replace(/\/+$/, "");
2187
2543
  }
2188
- function joinProjectPath(dir, ref2) {
2544
+ function joinProjectPath(dir, ref) {
2189
2545
  const base = dir === "" || dir === "." ? [] : normalizeProjectPath(dir).split("/");
2190
2546
  const out = base.filter((segment) => segment !== "" && segment !== ".");
2191
- for (const segment of ref2.replaceAll("\\", "/").split("/")) {
2547
+ for (const segment of ref.replaceAll("\\", "/").split("/")) {
2192
2548
  if (segment === "" || segment === ".") {
2193
2549
  continue;
2194
2550
  }
@@ -2310,6 +2666,12 @@ function statementKind(statement) {
2310
2666
  if ("$switch" in statement) {
2311
2667
  return "switch";
2312
2668
  }
2669
+ if ("stopPropagation" in statement) {
2670
+ return "stopPropagation";
2671
+ }
2672
+ if ("preventDefault" in statement) {
2673
+ return "preventDefault";
2674
+ }
2313
2675
  return "dispatch";
2314
2676
  }
2315
2677
  async function runStatements(statements, state, event, opts = {}) {
@@ -2343,7 +2705,8 @@ async function runStatements(statements, state, event, opts = {}) {
2343
2705
  }
2344
2706
  case "dispatch": {
2345
2707
  const dispatch = statement;
2346
- const target = opts.target ?? event?.currentTarget;
2708
+ const fallback = typeof opts.target === "function" ? opts.target() : opts.target;
2709
+ const target = event?.currentTarget ?? fallback;
2347
2710
  if (!target) {
2348
2711
  break;
2349
2712
  }
@@ -2360,6 +2723,14 @@ async function runStatements(statements, state, event, opts = {}) {
2360
2723
  target.dispatchEvent(new CustomEvent(dispatch.dispatchEvent, init));
2361
2724
  break;
2362
2725
  }
2726
+ case "stopPropagation": {
2727
+ event?.stopPropagation();
2728
+ break;
2729
+ }
2730
+ case "preventDefault": {
2731
+ event?.preventDefault();
2732
+ break;
2733
+ }
2363
2734
  default: {
2364
2735
  break;
2365
2736
  }
@@ -2407,10 +2778,14 @@ function serializeCookie(name, value, options) {
2407
2778
  }
2408
2779
  // ../runtime/src/runtime.ts
2409
2780
  var _resolveCache = new Map;
2410
- async function resolve(source) {
2781
+ async function resolve(source, ctx) {
2411
2782
  if (typeof source !== "string") {
2412
2783
  return source;
2413
2784
  }
2785
+ const served = ctx?.resolver?.(source);
2786
+ if (served) {
2787
+ return served;
2788
+ }
2414
2789
  if (_resolveCache.has(source)) {
2415
2790
  return _resolveCache.get(source);
2416
2791
  }
@@ -2495,10 +2870,36 @@ var _canvasDelinkAnchors = false;
2495
2870
  function setCanvasDelinkAnchors(on) {
2496
2871
  _canvasDelinkAnchors = on;
2497
2872
  }
2873
+ var _canvasDelinkPopovers = false;
2874
+ function setCanvasDelinkPopovers(on) {
2875
+ _canvasDelinkPopovers = on;
2876
+ }
2877
+ var _canvasDelinkCommands = false;
2878
+ function setCanvasDelinkCommands(on) {
2879
+ _canvasDelinkCommands = on;
2880
+ }
2881
+ var _canvasInsideStampedHost = false;
2882
+ function canvasStamped(el) {
2883
+ return _canvasInsideStampedHost || el.dataset.jxPath !== undefined;
2884
+ }
2498
2885
  function canvasAttrName(el, key) {
2499
2886
  if (_canvasDelinkAnchors && key === "href" && (el.tagName === "A" || el.tagName === "AREA")) {
2500
2887
  return "data-jx-href";
2501
2888
  }
2889
+ if (_canvasDelinkPopovers && key === "popover" && canvasStamped(el)) {
2890
+ return "data-jx-popover";
2891
+ }
2892
+ if (_canvasDelinkCommands && canvasStamped(el)) {
2893
+ if (key === "commandfor") {
2894
+ return "data-jx-commandfor";
2895
+ }
2896
+ if (key === "inert") {
2897
+ return "data-jx-inert";
2898
+ }
2899
+ if (key === "open" && el.tagName === "DIALOG") {
2900
+ return "data-jx-open";
2901
+ }
2902
+ }
2502
2903
  return key;
2503
2904
  }
2504
2905
  var _canvasAssetResolver = null;
@@ -2578,71 +2979,84 @@ function boundPropKey(key, val, state) {
2578
2979
  }
2579
2980
  return sub;
2580
2981
  }
2581
- async function buildScope(doc, parentScope = {}, base = location.href) {
2982
+ async function buildScope(doc, parentScope = {}, base = location.href, ctx) {
2983
+ const dispatchRoot = () => ctx?.root ?? null;
2582
2984
  const raw = {};
2583
- for (const [key, val] of Object.entries(parentScope)) {
2584
- raw[key] = val;
2585
- }
2586
2985
  const defs = doc.state ?? {};
2986
+ const linked = isReactive(parentScope);
2987
+ for (const key of Object.keys(parentScope)) {
2988
+ if (linked && !(key in defs)) {
2989
+ Object.defineProperty(raw, key, {
2990
+ configurable: true,
2991
+ enumerable: true,
2992
+ get: () => parentScope[key],
2993
+ set: (value) => {
2994
+ parentScope[key] = value;
2995
+ }
2996
+ });
2997
+ } else {
2998
+ raw[key] = parentScope[key];
2999
+ }
3000
+ }
2587
3001
  const imports = doc.imports ?? {};
2588
- for (const [, def2] of Object.entries(defs)) {
2589
- if (isPrototypeDef(def2) && !def2.$src) {
2590
- const mapped = imports[def2.$prototype];
3002
+ for (const [, def] of Object.entries(defs)) {
3003
+ if (isPrototypeDef(def) && !def.$src) {
3004
+ const mapped = imports[def.$prototype];
2591
3005
  if (mapped) {
2592
3006
  if (!mapped.endsWith(".class.json")) {
2593
- console.warn(`Jx: import "${def2.$prototype}" must map to a .class.json path, got "${mapped}"`);
3007
+ console.warn(`Jx: import "${def.$prototype}" must map to a .class.json path, got "${mapped}"`);
2594
3008
  continue;
2595
3009
  }
2596
- def2.$src = mapped;
3010
+ def.$src = mapped;
2597
3011
  }
2598
3012
  }
2599
3013
  }
2600
- for (const [key, def2] of Object.entries(defs)) {
2601
- if (typeof def2 === "string") {
2602
- if (!def2.includes("${")) {
2603
- raw[key] = def2;
3014
+ for (const [key, def] of Object.entries(defs)) {
3015
+ if (typeof def === "string") {
3016
+ if (!def.includes("${")) {
3017
+ raw[key] = def;
2604
3018
  }
2605
3019
  continue;
2606
3020
  }
2607
- if (typeof def2 === "number" || typeof def2 === "boolean" || def2 === null) {
2608
- raw[key] = def2;
3021
+ if (typeof def === "number" || typeof def === "boolean" || def === null) {
3022
+ raw[key] = def;
2609
3023
  continue;
2610
3024
  }
2611
- if (Array.isArray(def2)) {
2612
- raw[key] = def2;
3025
+ if (Array.isArray(def)) {
3026
+ raw[key] = def;
2613
3027
  continue;
2614
3028
  }
2615
- if (typeof def2 === "object") {
2616
- if (def2.$prototype) {
3029
+ if (typeof def === "object") {
3030
+ if (def.$prototype) {
2617
3031
  continue;
2618
3032
  }
2619
- if (isExpressionDef(def2)) {
3033
+ if (isExpressionDef(def)) {
2620
3034
  continue;
2621
3035
  }
2622
- if (isServerFnDef(def2)) {
3036
+ if (isServerFnDef(def)) {
2623
3037
  continue;
2624
3038
  }
2625
- if ("default" in def2) {
2626
- raw[key] = def2.default;
3039
+ if ("default" in def) {
3040
+ raw[key] = def.default;
2627
3041
  continue;
2628
3042
  }
2629
- if (hasSchemaKeywords(def2)) {
3043
+ if (hasSchemaKeywords(def)) {
2630
3044
  continue;
2631
3045
  }
2632
- raw[key] = def2;
3046
+ raw[key] = def;
2633
3047
  }
2634
3048
  }
2635
3049
  const state = reactive(raw);
2636
- for (const [key, def2] of Object.entries(defs)) {
2637
- if (typeof def2 === "string" && def2.includes("${")) {
2638
- state[key] = computed(() => evaluateTemplate(def2, state));
3050
+ for (const [key, def] of Object.entries(defs)) {
3051
+ if (typeof def === "string" && def.includes("${")) {
3052
+ state[key] = computed(() => evaluateTemplate(def, state));
2639
3053
  }
2640
3054
  }
2641
- for (const [key, def2] of Object.entries(defs)) {
2642
- if (isExpressionDef(def2)) {
2643
- const node = def2.$expression;
2644
- if (isNamedFormulaDef(def2)) {
2645
- const params = def2.parameters;
3055
+ for (const [key, def] of Object.entries(defs)) {
3056
+ if (isExpressionDef(def)) {
3057
+ const node = def.$expression;
3058
+ if (isNamedFormulaDef(def)) {
3059
+ const params = def.parameters;
2646
3060
  state[key] = (...argValues) => {
2647
3061
  const args = {};
2648
3062
  for (const [i, p] of params.entries()) {
@@ -2662,11 +3076,11 @@ async function buildScope(doc, parentScope = {}, base = location.href) {
2662
3076
  }
2663
3077
  }
2664
3078
  }
2665
- for (const [key, def2] of Object.entries(defs)) {
2666
- if (hasStructuredBody(def2)) {
2667
- const { body } = def2;
2668
- if (Array.isArray(def2.parameters) && def2.parameters.length > 0) {
2669
- const params = def2.parameters;
3079
+ for (const [key, def] of Object.entries(defs)) {
3080
+ if (hasStructuredBody(def)) {
3081
+ const { body } = def;
3082
+ if (Array.isArray(def.parameters) && def.parameters.length > 0) {
3083
+ const params = def.parameters;
2670
3084
  state[key] = (...argValues) => {
2671
3085
  const args = {};
2672
3086
  for (const [i, p] of params.entries()) {
@@ -2676,34 +3090,35 @@ async function buildScope(doc, parentScope = {}, base = location.href) {
2676
3090
  }
2677
3091
  args[name] = argValues[i] === undefined && typeof p === "object" && p !== null && "default" in p ? p.default : argValues[i];
2678
3092
  }
2679
- return runStatements(body, state, null, { args });
3093
+ return runStatements(body, state, null, { args, target: dispatchRoot });
2680
3094
  };
2681
3095
  } else {
2682
3096
  const handler = (s, event) => {
2683
- runStatements(body, s, event ?? null);
3097
+ runStatements(body, s, event ?? null, { target: dispatchRoot });
2684
3098
  };
2685
3099
  state[key] = handler;
2686
3100
  }
2687
- } else if (isFunctionDef(def2)) {
2688
- state[key] = await resolveFunction(def2, state, key, base);
3101
+ } else if (isFunctionDef(def)) {
3102
+ state[key] = await resolveFunction(def, state, key, base);
2689
3103
  }
2690
3104
  }
2691
- for (const [key, def2] of Object.entries(defs)) {
2692
- if (isPrototypeDef(def2)) {
2693
- state[key] = await resolvePrototype(def2, state, key, base);
3105
+ for (const [key, def] of Object.entries(defs)) {
3106
+ if (isPrototypeDef(def)) {
3107
+ state[key] = await resolvePrototype(def, state, key, base, ctx);
2694
3108
  }
2695
3109
  }
2696
- if (!_serverFnConfig.skip) {
2697
- for (const [key, def2] of Object.entries(defs)) {
2698
- if (isServerFnDef(def2)) {
2699
- state[key] = await resolveServerFunction(def2, state, key, base);
3110
+ if (!(ctx?.skipServerFunctions ?? _serverFnConfig.skip)) {
3111
+ for (const [key, def] of Object.entries(defs)) {
3112
+ if (isServerFnDef(def)) {
3113
+ state[key] = await resolveServerFunction(def, state, key, base);
2700
3114
  }
2701
3115
  }
2702
3116
  }
3117
+ const rootMedia = ctx?.media ?? _rootMedia;
2703
3118
  if (doc.$media) {
2704
3119
  state["$media"] = doc.$media;
2705
- } else if (!state["$media"] && Object.keys(_rootMedia).length > 0) {
2706
- state["$media"] = _rootMedia;
3120
+ } else if (!state["$media"] && Object.keys(rootMedia).length > 0) {
3121
+ state["$media"] = rootMedia;
2707
3122
  }
2708
3123
  return state;
2709
3124
  }
@@ -2747,36 +3162,72 @@ function evaluateAttrTemplate(str, state) {
2747
3162
  return fn(state, $map, $map?.item, $map?.index);
2748
3163
  }
2749
3164
  var _moduleCache = new Map;
2750
- async function resolveFunction(def2, state, key, base) {
2751
- if (def2.body && def2.$src) {
3165
+ var _moduleLoaders = new Map;
3166
+ function preloadModule(specifier, mod) {
3167
+ if (typeof mod === "function") {
3168
+ _moduleCache.delete(specifier);
3169
+ _moduleLoaders.set(specifier, mod);
3170
+ return;
3171
+ }
3172
+ _moduleLoaders.delete(specifier);
3173
+ _moduleCache.set(specifier, mod);
3174
+ }
3175
+ function seededModule(src) {
3176
+ const cached = _moduleCache.get(src);
3177
+ if (cached) {
3178
+ return cached;
3179
+ }
3180
+ const pending = _moduleLoaders.get(src);
3181
+ if (!pending) {
3182
+ return;
3183
+ }
3184
+ if (typeof pending !== "function") {
3185
+ return pending;
3186
+ }
3187
+ const load = Promise.resolve(pending()).then((mod) => {
3188
+ _moduleCache.set(src, mod);
3189
+ _moduleLoaders.delete(src);
3190
+ return mod;
3191
+ }, (error) => {
3192
+ _moduleLoaders.set(src, pending);
3193
+ throw error;
3194
+ });
3195
+ _moduleLoaders.set(src, load);
3196
+ return load;
3197
+ }
3198
+ async function resolveFunction(def, state, key, base) {
3199
+ if (def.body && def.$src) {
2752
3200
  throw new Error(`Jx: '${key}' declares both body and $src — these are mutually exclusive`);
2753
3201
  }
2754
- if (!def2.body && !def2.$src) {
2755
- const params = resolveParamNames(def2);
3202
+ if (!def.body && !def.$src) {
3203
+ const params = resolveParamNames(def);
2756
3204
  const noop = new Function(...params, "");
2757
3205
  Object.defineProperty(noop, "name", {
2758
3206
  configurable: true,
2759
- value: def2.name ?? key
3207
+ value: def.name ?? key
2760
3208
  });
2761
3209
  return noop;
2762
3210
  }
2763
3211
  let fn;
2764
- if (typeof def2.body === "string") {
2765
- const params = resolveParamNames(def2);
2766
- fn = new Function(...params, def2.body);
3212
+ if (typeof def.body === "string") {
3213
+ const params = resolveParamNames(def);
3214
+ fn = new Function(...params, def.body);
2767
3215
  Object.defineProperty(fn, "name", {
2768
3216
  configurable: true,
2769
- value: def2.name ?? key
3217
+ value: def.name ?? key
2770
3218
  });
2771
3219
  } else {
2772
- const src = def2.$src;
3220
+ const src = def.$src;
2773
3221
  if (!src) {
2774
3222
  throw new Error(`Jx: '${key}' has neither body nor $src`);
2775
3223
  }
2776
- const exportName = def2.$export ?? key;
3224
+ const exportName = def.$export ?? key;
2777
3225
  let mod;
2778
- if (_moduleCache.has(src)) {
2779
- mod = _moduleCache.get(src);
3226
+ const seeded = seededModule(src);
3227
+ if (seeded instanceof Promise) {
3228
+ mod = await seeded;
3229
+ } else if (seeded) {
3230
+ mod = seeded;
2780
3231
  } else {
2781
3232
  if (base) {
2782
3233
  const resolvedSrc = new URL(src, base).href;
@@ -2796,11 +3247,11 @@ async function resolveFunction(def2, state, key, base) {
2796
3247
  }
2797
3248
  fn = candidate;
2798
3249
  }
2799
- const hasParams = (def2.parameters ?? def2.arguments ?? []).length > 0;
3250
+ const hasParams = (def.parameters ?? def.arguments ?? []).length > 0;
2800
3251
  let isComputed = false;
2801
3252
  if (!hasParams) {
2802
- if (typeof def2.body === "string") {
2803
- isComputed = bodyReturnsValue(def2.body);
3253
+ if (typeof def.body === "string") {
3254
+ isComputed = bodyReturnsValue(def.body);
2804
3255
  } else if (fn) {
2805
3256
  isComputed = fn.length <= 1 && bodyReturnsValue(fn.toString());
2806
3257
  }
@@ -2810,8 +3261,8 @@ async function resolveFunction(def2, state, key, base) {
2810
3261
  }
2811
3262
  return fn;
2812
3263
  }
2813
- function resolveParamNames(def2) {
2814
- const names = def2.parameters ? paramNames(def2.parameters) : def2.arguments ?? [];
3264
+ function resolveParamNames(def) {
3265
+ const names = def.parameters ? paramNames(def.parameters) : def.arguments ?? [];
2815
3266
  return names.length > 0 && names[0] === "state" ? names : ["state", ...names];
2816
3267
  }
2817
3268
  var RESERVED_KEYS = new Set([
@@ -2860,19 +3311,19 @@ function elementNamespace(tagName, inherited) {
2860
3311
  }
2861
3312
  return inherited ?? null;
2862
3313
  }
2863
- function renderNode(def2, state, options) {
3314
+ function renderNode(def, state, options) {
2864
3315
  const path = options?._path ?? [];
2865
- if (typeof def2 === "string" || typeof def2 === "number" || typeof def2 === "boolean") {
2866
- const textNode = document.createTextNode(String(def2));
2867
- if (typeof def2 === "string" && isTemplateString(def2)) {
3316
+ if (typeof def === "string" || typeof def === "number" || typeof def === "boolean") {
3317
+ const textNode = document.createTextNode(String(def));
3318
+ if (typeof def === "string" && isTemplateString(def)) {
2868
3319
  effect(() => {
2869
- textNode.textContent = evaluateTemplate(def2, state);
3320
+ textNode.textContent = evaluateTemplate(def, state);
2870
3321
  });
2871
3322
  }
2872
3323
  return textNode;
2873
3324
  }
2874
3325
  let localState = state;
2875
- for (const [key, val] of Object.entries(def2)) {
3326
+ for (const [key, val] of Object.entries(def)) {
2876
3327
  if (key.startsWith("$") && !RESERVED_KEYS.has(key)) {
2877
3328
  if (localState === state) {
2878
3329
  localState = Object.create(state);
@@ -2880,38 +3331,41 @@ function renderNode(def2, state, options) {
2880
3331
  localState[key] = isRefObj(val) ? resolveRef(val.$ref, state) : val;
2881
3332
  }
2882
3333
  }
2883
- if ("$ref" in def2 && !def2.tagName) {
2884
- const refTarget = String(def2.$ref ?? "");
3334
+ if ("$ref" in def && !def.tagName) {
3335
+ const refTarget = String(def.$ref ?? "");
2885
3336
  if (!warnedRefChildren.has(refTarget)) {
2886
3337
  warnedRefChildren.add(refTarget);
2887
3338
  console.warn(`Jx: a $ref child ("${refTarget}") is not a supported component instance; register the ` + `component in $elements and use its custom-element tag instead (spec §13).`);
2888
3339
  }
2889
3340
  }
2890
- const tagName = resolveTagName(def2.tagName, localState);
3341
+ const tagName = resolveTagName(def.tagName, localState);
2891
3342
  const isCustomEl = tagName.includes("-") && customElements.get(tagName);
2892
- if (def2.$props && isCustomEl) {
2893
- return renderCustomElementWithProps(def2, localState, options, path);
3343
+ if (def.$props && isCustomEl) {
3344
+ return renderCustomElementWithProps(def, localState, options, path);
2894
3345
  }
2895
- if (def2.$props) {
3346
+ if (def.$props) {
2896
3347
  if (tagName.includes("-")) {
2897
- return renderCustomElementWithProps(def2, localState, options, path);
3348
+ return renderCustomElementWithProps(def, localState, options, path);
2898
3349
  }
2899
- const { $props: _$props, ...rest } = def2;
2900
- return renderNode(rest, mergeProps(def2, localState), options);
3350
+ const { $props: _$props, ...rest } = def;
3351
+ return renderNode(rest, mergeProps(def, localState), options);
2901
3352
  }
2902
- if (def2.$switch) {
2903
- return renderSwitch(def2, localState, options);
3353
+ if (def.$switch) {
3354
+ return renderSwitch(def, localState, options);
2904
3355
  }
2905
3356
  const ns = elementNamespace(tagName, options?._ns);
2906
3357
  const childNs = tagName === "foreignObject" ? null : ns;
2907
3358
  const el = ns ? document.createElementNS(ns, tagName) : document.createElement(tagName);
2908
3359
  if (options?.onNodeCreated) {
2909
- options.onNodeCreated(el, path, def2, localState);
3360
+ options.onNodeCreated(el, path, def, localState);
3361
+ }
3362
+ applyProperties(el, def, localState);
3363
+ if (def.style && tagName.includes("-")) {
3364
+ callSiteStyles.set(el, def.style);
2910
3365
  }
2911
- applyProperties(el, def2, localState);
2912
- applyStyle(el, def2.style ?? {}, localState["$media"] ?? {}, localState);
2913
- applyAttributes(el, def2.attributes ?? {}, localState);
2914
- const kids = def2.children;
3366
+ applyStyle(el, def.style ?? {}, localState["$media"] ?? {}, localState);
3367
+ applyAttributes(el, def.attributes ?? {}, localState);
3368
+ const kids = def.children;
2915
3369
  if (isMappedArray(kids)) {
2916
3370
  const arrOpts = options || childNs ? { ...options, _ns: childNs, _path: [...path, "children"] } : undefined;
2917
3371
  renderMappedArrayInto(el, kids, localState, arrOpts);
@@ -2928,49 +3382,58 @@ function renderNode(def2, state, options) {
2928
3382
  }
2929
3383
  return el;
2930
3384
  }
2931
- function applyProperties(el, def2, state) {
2932
- for (const [key, val] of Object.entries(def2)) {
3385
+ function applyProperties(el, def, state) {
3386
+ for (const [key, val] of Object.entries(def)) {
2933
3387
  if (RESERVED_KEYS.has(key)) {
2934
3388
  continue;
2935
3389
  }
2936
3390
  if (key.startsWith("$")) {
2937
3391
  continue;
2938
3392
  }
2939
- if (key.startsWith("on")) {
2940
- if (isRefObj(val)) {
2941
- const handler = resolveRef(val.$ref, state);
2942
- if (typeof handler === "function") {
2943
- const scope = state;
2944
- const handlerFn = handler;
2945
- el.addEventListener(key.slice(2), (e) => handlerFn(scope, e));
2946
- }
2947
- continue;
2948
- }
2949
- if (hasStructuredBody(val)) {
2950
- const { body } = val;
2951
- const scope = state;
2952
- el.addEventListener(key.slice(2), (e) => {
2953
- runStatements(body, scope, e);
2954
- });
2955
- continue;
2956
- }
2957
- if (isFunctionDef(val) && typeof val.body === "string") {
2958
- const params = resolveParamNames(val);
2959
- const fn = new Function(...params, val.body);
2960
- const scope = state;
2961
- el.addEventListener(key.slice(2), (e) => fn(scope, e));
2962
- continue;
2963
- }
2964
- if (isExpressionDef(val)) {
2965
- const node = val.$expression;
2966
- const scope = state;
2967
- el.addEventListener(key.slice(2), (e) => evaluateExpression(node, scope, e));
2968
- continue;
2969
- }
3393
+ if (key.startsWith("on") && bindHandler(el, key, val, state)) {
3394
+ continue;
2970
3395
  }
2971
3396
  bindProperty(el, key, val, state);
2972
3397
  }
2973
3398
  }
3399
+ function bindHandler(el, key, val, state) {
3400
+ const type = key.slice(2);
3401
+ const scope = state;
3402
+ if (isRefObj(val)) {
3403
+ const handler = resolveRef(val.$ref, state);
3404
+ if (typeof handler === "function") {
3405
+ const handlerFn = handler;
3406
+ el.addEventListener(type, (e) => handlerFn(scope, e));
3407
+ }
3408
+ return true;
3409
+ }
3410
+ if (hasStructuredBody(val)) {
3411
+ const { body } = val;
3412
+ el.addEventListener(type, (e) => {
3413
+ runStatements(body, scope, e);
3414
+ });
3415
+ return true;
3416
+ }
3417
+ if (isFunctionDef(val) && typeof val.body === "string") {
3418
+ const params = resolveParamNames(val);
3419
+ const fn = new Function(...params, val.body);
3420
+ el.addEventListener(type, (e) => fn(scope, e));
3421
+ return true;
3422
+ }
3423
+ if (isExpressionDef(val)) {
3424
+ const node = val.$expression;
3425
+ el.addEventListener(type, (e) => evaluateExpression(node, scope, e));
3426
+ return true;
3427
+ }
3428
+ return false;
3429
+ }
3430
+ function bindDefinitionHandlers(host, def, state) {
3431
+ for (const [key, val] of Object.entries(def)) {
3432
+ if (key.startsWith("on") && !RESERVED_KEYS.has(key)) {
3433
+ bindHandler(host, key, val, state);
3434
+ }
3435
+ }
3436
+ }
2974
3437
  function bindProperty(el, key, val, state) {
2975
3438
  const target = el;
2976
3439
  const boundProp = boundPropKey(key, val, state);
@@ -2984,6 +3447,9 @@ function bindProperty(el, key, val, state) {
2984
3447
  node.setAttribute("class", resolved == null ? "" : String(resolved));
2985
3448
  return;
2986
3449
  }
3450
+ if (target[key] === resolved) {
3451
+ return;
3452
+ }
2987
3453
  target[key] = resolved;
2988
3454
  };
2989
3455
  if (isRefObj(val)) {
@@ -3005,142 +3471,287 @@ function bindProperty(el, key, val, state) {
3005
3471
  }
3006
3472
  write(asAsset(val));
3007
3473
  }
3008
- function applyStyle(el, styleDef, mediaQueries = {}, state = {}) {
3009
- const nested = {};
3010
- const media = {};
3011
- const baseDecls = {};
3012
- const mediaOverriddenProps = new Set;
3013
- for (const [prop, val] of Object.entries(styleDef)) {
3014
- if (prop.startsWith("@") && val && typeof val === "object") {
3015
- for (const k of Object.keys(val)) {
3016
- if (!k.startsWith(":") && !k.startsWith(".") && !k.startsWith("&") && !k.startsWith("[") && !k.startsWith("@")) {
3017
- mediaOverriddenProps.add(k);
3474
+ function cssomSink(sheet, detach) {
3475
+ const entries = [];
3476
+ return {
3477
+ detach,
3478
+ insert(texts) {
3479
+ const rules = [];
3480
+ for (const text of texts) {
3481
+ const index = sheet.cssRules.length;
3482
+ try {
3483
+ sheet.insertRule(text, index);
3484
+ } catch {
3485
+ continue;
3486
+ }
3487
+ const rule = sheet.cssRules[index];
3488
+ if (rule) {
3489
+ rules.push(rule);
3018
3490
  }
3019
3491
  }
3020
- }
3021
- }
3022
- for (const [prop, val] of Object.entries(styleDef)) {
3023
- if (val !== null && typeof val === "object" && !Array.isArray(val)) {
3024
- if (prop.startsWith("@")) {
3025
- media[prop] = val;
3026
- } else {
3027
- nested[prop] = val;
3492
+ const inserted = { rules, texts };
3493
+ entries.push(inserted);
3494
+ return inserted;
3495
+ },
3496
+ remove(inserted) {
3497
+ const at = entries.indexOf(inserted);
3498
+ if (at !== -1) {
3499
+ entries.splice(at, 1);
3028
3500
  }
3029
- continue;
3030
- }
3031
- if (prop.startsWith("@") || isNestedSelector(prop)) {
3032
- continue;
3033
- }
3034
- if (val === undefined) {
3035
- continue;
3501
+ if (inserted.rules.length === 0) {
3502
+ return;
3503
+ }
3504
+ const list = [...sheet.cssRules];
3505
+ const indices = inserted.rules.map((rule) => list.indexOf(rule)).filter((index) => index >= 0).toSorted((a, b) => b - a);
3506
+ for (const index of indices) {
3507
+ sheet.deleteRule(index);
3508
+ }
3509
+ inserted.rules.length = 0;
3510
+ },
3511
+ replaceAll(texts) {
3512
+ entries.length = 0;
3513
+ entries.push({ rules: [], texts });
3514
+ sheet.replaceSync(texts.join(`
3515
+ `));
3516
+ },
3517
+ text() {
3518
+ return entries.flatMap((entry) => entry.texts.join(`
3519
+ `)).join(`
3520
+ `);
3036
3521
  }
3037
- const scalar = String(val);
3038
- if (prop.startsWith("--")) {
3039
- if (isTemplateString(val)) {
3040
- effect(() => {
3041
- el.style.setProperty(prop, canvasStyleValue(evaluateTemplate(val, state)));
3042
- });
3043
- } else {
3044
- el.style.setProperty(prop, canvasStyleValue(scalar));
3522
+ };
3523
+ }
3524
+ function textSink(tag) {
3525
+ const entries = [];
3526
+ const write = () => {
3527
+ tag.textContent = entries.map((entry) => entry.texts.join(`
3528
+ `)).join(`
3529
+ `);
3530
+ };
3531
+ return {
3532
+ detach() {
3533
+ tag.remove();
3534
+ },
3535
+ insert(texts) {
3536
+ const inserted = { rules: [], texts };
3537
+ entries.push(inserted);
3538
+ write();
3539
+ return inserted;
3540
+ },
3541
+ remove(inserted) {
3542
+ const index = entries.indexOf(inserted);
3543
+ if (index !== -1) {
3544
+ entries.splice(index, 1);
3545
+ write();
3045
3546
  }
3046
- } else if (isTemplateString(val)) {
3047
- effect(() => {
3048
- el.style[prop] = canvasStyleValue(evaluateTemplate(val, state));
3049
- });
3050
- } else if (mediaOverriddenProps.has(prop)) {
3051
- baseDecls[prop] = scalar;
3052
- } else {
3053
- el.style[prop] = canvasStyleValue(scalar);
3547
+ },
3548
+ replaceAll(texts) {
3549
+ entries.length = 0;
3550
+ entries.push({ rules: [], texts });
3551
+ write();
3552
+ },
3553
+ text() {
3554
+ return tag.textContent ?? "";
3054
3555
  }
3556
+ };
3557
+ }
3558
+ function openSink(doc) {
3559
+ const view = doc.defaultView;
3560
+ const SheetConstructor = view?.CSSStyleSheet;
3561
+ if (typeof SheetConstructor === "function" && Array.isArray(doc.adoptedStyleSheets)) {
3562
+ try {
3563
+ const sheet = new SheetConstructor;
3564
+ doc.adoptedStyleSheets = [...doc.adoptedStyleSheets, sheet];
3565
+ return cssomSink(sheet, () => {
3566
+ doc.adoptedStyleSheets = doc.adoptedStyleSheets.filter((s) => s !== sheet);
3567
+ });
3568
+ } catch {}
3055
3569
  }
3056
- const hasNested = Object.keys(nested).length > 0;
3057
- const hasMedia = Object.keys(media).length > 0;
3058
- const hasBaseDecls = Object.keys(baseDecls).length > 0;
3059
- if (!hasNested && !hasMedia && !hasBaseDecls) {
3570
+ const tag = doc.createElement("style");
3571
+ tag.dataset.jxSheet = "";
3572
+ (doc.head ?? doc.documentElement).append(tag);
3573
+ return tag.sheet ? cssomSink(tag.sheet, () => tag.remove()) : textSink(tag);
3574
+ }
3575
+ var sheetStates = new WeakMap;
3576
+ function sheetStateFor(doc) {
3577
+ const existing = sheetStates.get(doc);
3578
+ if (existing) {
3579
+ return existing;
3580
+ }
3581
+ const created = {
3582
+ hoisted: new Map,
3583
+ interned: new Map,
3584
+ scratch: null,
3585
+ scratchOwners: new Map,
3586
+ serial: 0,
3587
+ shared: openSink(doc)
3588
+ };
3589
+ sheetStates.set(doc, created);
3590
+ return created;
3591
+ }
3592
+ var elementStyles = new WeakMap;
3593
+ var SCOPE_TOKEN = "\x01jx-scope\x01";
3594
+ function rewriteScratch(state) {
3595
+ if (!state.scratch) {
3060
3596
  return;
3061
3597
  }
3062
- const uid = `jx-${Math.random().toString(36).slice(2, 7)}`;
3063
- el.dataset.jx = uid;
3064
- let css = "";
3065
- const baseCSS = toCSSText(baseDecls);
3066
- if (baseCSS) {
3067
- css += `[data-jx="${uid}"] { ${baseCSS} }
3068
- `;
3598
+ state.scratch.replaceAll([...state.scratchOwners.values()].flat());
3599
+ }
3600
+ function releaseInterned(state, table, key) {
3601
+ const entry = table.get(key);
3602
+ if (!entry) {
3603
+ return;
3069
3604
  }
3070
- function emitNested(scope, rules) {
3071
- const props = toCSSText(rules);
3072
- if (props) {
3073
- css += `${scope} { ${props} }
3074
- `;
3075
- }
3076
- for (const [sel, sub] of Object.entries(rules)) {
3077
- if (sub === null || typeof sub !== "object" || Array.isArray(sub)) {
3078
- continue;
3079
- }
3080
- if (sel.startsWith("@")) {
3081
- continue;
3082
- }
3083
- const resolved = sel.startsWith("&") ? sel.replace("&", scope) : sel.startsWith("[") ? `${scope}${sel}` : sel.startsWith(":") || sel.startsWith(".") ? `${scope}${sel}` : `${scope} ${sel}`;
3084
- emitNested(resolved, sub);
3605
+ entry.refs -= 1;
3606
+ if (entry.refs <= 0) {
3607
+ table.delete(key);
3608
+ state.shared.remove(entry.inserted);
3609
+ }
3610
+ }
3611
+ function retainInterned(state, table, key, texts) {
3612
+ const existing = table.get(key);
3613
+ if (existing) {
3614
+ existing.refs += 1;
3615
+ return;
3616
+ }
3617
+ table.set(key, { inserted: state.shared.insert(texts), refs: 1 });
3618
+ }
3619
+ function releaseElementStyles(el, only) {
3620
+ const entry = elementStyles.get(el);
3621
+ if (!entry || only !== undefined && entry !== only) {
3622
+ return;
3623
+ }
3624
+ elementStyles.delete(el);
3625
+ entry.stop?.();
3626
+ for (const name of entry.vars) {
3627
+ el.style.removeProperty(name);
3628
+ }
3629
+ delete el.dataset.jx;
3630
+ if (sheetStates.get(entry.doc) !== entry.state) {
3631
+ return;
3632
+ }
3633
+ const { state } = entry;
3634
+ if (entry.interned === null) {
3635
+ if (state.scratchOwners.delete(el)) {
3636
+ rewriteScratch(state);
3085
3637
  }
3638
+ } else {
3639
+ releaseInterned(state, state.interned, entry.interned);
3086
3640
  }
3087
- for (const [sel, rules] of Object.entries(nested)) {
3088
- const resolved = sel.startsWith("&") ? sel.replace("&", `[data-jx="${uid}"]`) : sel.startsWith("[") ? `[data-jx="${uid}"]${sel}` : sel.startsWith(":") || sel.startsWith(".") ? `[data-jx="${uid}"]${sel}` : `[data-jx="${uid}"] ${sel}`;
3089
- emitNested(resolved, rules);
3641
+ for (const key of entry.hoisted) {
3642
+ releaseInterned(state, state.hoisted, key);
3090
3643
  }
3091
- function emitMediaNested(atRule, parentSel, obj) {
3092
- for (const [sel, sub] of Object.entries(obj)) {
3093
- if (sub === null || typeof sub !== "object" || Array.isArray(sub)) {
3094
- continue;
3095
- }
3096
- if (sel.startsWith("@")) {
3097
- continue;
3644
+ }
3645
+ function resetDocumentStyles(doc = document) {
3646
+ const state = sheetStates.get(doc);
3647
+ if (!state) {
3648
+ return;
3649
+ }
3650
+ sheetStates.delete(doc);
3651
+ for (const el of state.scratchOwners.keys()) {
3652
+ elementStyles.delete(el);
3653
+ delete el.dataset.jx;
3654
+ }
3655
+ state.scratchOwners.clear();
3656
+ state.interned.clear();
3657
+ state.hoisted.clear();
3658
+ state.shared.detach();
3659
+ state.scratch?.detach();
3660
+ }
3661
+ function declaresDisplay(style) {
3662
+ return Boolean(style) && typeof style === "object" && "display" in style;
3663
+ }
3664
+ var callSiteStyles = new WeakMap;
3665
+ function mergeStyle(base, over) {
3666
+ if (!over) {
3667
+ return base;
3668
+ }
3669
+ const out = { ...base };
3670
+ for (const [key, value] of Object.entries(over)) {
3671
+ const prior = out[key];
3672
+ out[key] = prior !== null && typeof prior === "object" && value !== null && typeof value === "object" && !Array.isArray(value) ? mergeStyle(prior, value) : value;
3673
+ }
3674
+ return out;
3675
+ }
3676
+ function applyStyle(el, styleDef, mediaQueries = {}, state = {}) {
3677
+ applyStyleInto(el, styleDef, mediaQueries, state, false);
3678
+ }
3679
+ function reapplyStyle(el, styleDef, mediaQueries = {}, state = {}) {
3680
+ applyStyleInto(el, styleDef ?? {}, mediaQueries, state, true);
3681
+ }
3682
+ function applyStyleInto(el, styleDef, mediaQueries, state, live) {
3683
+ releaseElementStyles(el);
3684
+ const doc = el.ownerDocument ?? document;
3685
+ const sheetState = sheetStateFor(doc);
3686
+ const transposeSelector = (_canvasDelinkPopovers || _canvasDelinkCommands) && canvasStamped(el) ? (selector) => transposeCanvasOverlaySelector(selector, {
3687
+ dialog: el.tagName === "DIALOG"
3688
+ }) : (selector) => selector;
3689
+ let serial = -1;
3690
+ let indirect = 0;
3691
+ const sources = [];
3692
+ const rules = buildStyleRules(styleDef, {
3693
+ mediaQueries,
3694
+ resolveValue: (property, value, target) => {
3695
+ if (target === "self" && property.startsWith("--")) {
3696
+ sources.push({ name: property, value });
3697
+ return null;
3098
3698
  }
3099
- const resolved = sel.startsWith("&") ? sel.replace("&", parentSel) : sel.startsWith("[") ? `${parentSel}${sel}` : sel.startsWith(":") || sel.startsWith(".") ? `${parentSel}${sel}` : `${parentSel} ${sel}`;
3100
- const props = toCSSText(sub);
3101
- if (props) {
3102
- css += `${atRule} { ${resolved} { ${props} } }
3103
- `;
3699
+ if (serial < 0) {
3700
+ ({ serial } = sheetState);
3701
+ sheetState.serial += 1;
3104
3702
  }
3105
- emitMediaNested(atRule, resolved, sub);
3106
- }
3703
+ const name = `--jx-r${serial}-${indirect}`;
3704
+ indirect += 1;
3705
+ sources.push({ name, value });
3706
+ return `var(${name})`;
3707
+ },
3708
+ scope: SCOPE_TOKEN,
3709
+ transposeSelector,
3710
+ transposeValue: canvasStyleValue
3711
+ });
3712
+ if (rules.length === 0 && sources.length === 0) {
3713
+ return;
3107
3714
  }
3108
- for (const [key, rules] of Object.entries(media)) {
3109
- if (key === "@--") {
3110
- continue;
3111
- }
3112
- const query = resolveAtQuery(key, mediaQueries);
3113
- const atRule = query === null ? key : `@media ${query}`;
3114
- const scope = `[data-jx="${uid}"]`;
3115
- const scheme = query === null ? null : pureSchemeOf(query);
3116
- if (scheme) {
3117
- const { auto, forced } = schemeSelectors(scope, scheme);
3118
- css += `${atRule} { ${auto} { ${toCSSText(rules)} } }
3119
- `;
3120
- emitMediaNested(atRule, auto, rules);
3121
- emitNested(forced, rules);
3715
+ const scoped = rules.filter((rule) => rule.target !== "unscoped");
3716
+ const unscoped = rules.filter((rule) => rule.target === "unscoped");
3717
+ for (const rule of unscoped) {
3718
+ retainInterned(sheetState, sheetState.hoisted, rule.text, [rule.text]);
3719
+ }
3720
+ const uid = `jx-${hashCss(scoped.map((rule) => rule.key).join("|"))}`;
3721
+ const texts = scoped.map((rule) => rule.text.replaceAll(SCOPE_TOKEN, `[data-jx="${uid}"]`));
3722
+ if (texts.length > 0) {
3723
+ el.dataset.jx = uid;
3724
+ if (live) {
3725
+ sheetState.scratch ??= openSink(doc);
3726
+ sheetState.scratchOwners.set(el, texts);
3727
+ rewriteScratch(sheetState);
3122
3728
  } else {
3123
- css += `${atRule} { ${scope} { ${toCSSText(rules)} } }
3124
- `;
3125
- emitMediaNested(atRule, scope, rules);
3729
+ retainInterned(sheetState, sheetState.interned, uid, texts);
3126
3730
  }
3127
3731
  }
3128
- const tag = document.createElement("style");
3129
- tag.textContent = css;
3130
- tag.dataset.jxOwner = uid;
3131
- document.head.append(tag);
3132
- elementStyleTags.set(el, tag);
3133
- }
3134
- var elementStyleTags = new WeakMap;
3135
- function reapplyStyle(el, styleDef, mediaQueries = {}, state = {}) {
3136
- const prev = elementStyleTags.get(el);
3137
- if (prev) {
3138
- prev.remove();
3139
- elementStyleTags.delete(el);
3732
+ const entry = {
3733
+ doc,
3734
+ hoisted: unscoped.map((rule) => rule.text),
3735
+ interned: texts.length > 0 && !live ? uid : null,
3736
+ state: sheetState,
3737
+ stop: null,
3738
+ uid,
3739
+ vars: sources.map((source) => source.name)
3740
+ };
3741
+ if (sources.length > 0) {
3742
+ const scope = effectScope();
3743
+ scope.run(() => {
3744
+ for (const { name, value } of sources) {
3745
+ effect(() => {
3746
+ const resolved = isRefObj(value) ? resolveRef(value.$ref, state) : evaluateTemplate(value, state);
3747
+ el.style.setProperty(name, canvasStyleValue(String(resolved ?? "")));
3748
+ });
3749
+ }
3750
+ });
3751
+ entry.stop = () => scope.stop();
3140
3752
  }
3141
- el.style.cssText = "";
3142
- delete el.dataset.jx;
3143
- applyStyle(el, styleDef ?? {}, mediaQueries, state);
3753
+ elementStyles.set(el, entry);
3754
+ onScopeDispose(() => releaseElementStyles(el, entry), true);
3144
3755
  }
3145
3756
  var ENUMERATED_ATTRS = new Set(["contenteditable", "draggable", "spellcheck"]);
3146
3757
  function booleanAttrValue(name, value) {
@@ -3154,6 +3765,10 @@ function applyAttributes(el, attrs, state) {
3154
3765
  for (const [k, v] of Object.entries(attrs)) {
3155
3766
  const attr = canvasAttrName(el, k);
3156
3767
  const write = (resolved) => {
3768
+ if (resolved === null || resolved === undefined) {
3769
+ el.removeAttribute(attr);
3770
+ return;
3771
+ }
3157
3772
  if (typeof resolved === "boolean") {
3158
3773
  const text = booleanAttrValue(attr, resolved);
3159
3774
  if (text === null) {
@@ -3163,7 +3778,7 @@ function applyAttributes(el, attrs, state) {
3163
3778
  }
3164
3779
  return;
3165
3780
  }
3166
- el.setAttribute(attr, canvasAssetValue(el.tagName, k, String(resolved ?? "")));
3781
+ el.setAttribute(attr, canvasAssetValue(el.tagName, k, String(resolved)));
3167
3782
  };
3168
3783
  if (isRefObj(v)) {
3169
3784
  effect(() => write(resolveRef(v.$ref, state)));
@@ -3178,8 +3793,69 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
3178
3793
  const path = options?._path ?? [];
3179
3794
  const anchor = document.createComment("jx-array");
3180
3795
  parentEl.append(anchor);
3181
- const { items: itemsSrc, map: mapDef, filter: filterRef, sort: sortRef } = arrayDef;
3182
- effect(() => {
3796
+ const { items: itemsSrc, map: mapDef, filter: filterRef, sort: sortRef, key: keyRef } = arrayDef;
3797
+ const keyPointer = isRefObj(keyRef) ? keyRef.$ref : null;
3798
+ let warned = false;
3799
+ const warnOnce = (message) => {
3800
+ if (!warned) {
3801
+ warned = true;
3802
+ console.warn(`Jx $map: ${message}`);
3803
+ }
3804
+ };
3805
+ let rows = [];
3806
+ const teardown = (row) => {
3807
+ row.scope.stop();
3808
+ row.node.remove();
3809
+ };
3810
+ const createRow = (key, item, index) => {
3811
+ const map = shallowReactive({ index, item });
3812
+ const child = Object.create(state);
3813
+ child.$map = map;
3814
+ Object.defineProperty(child, "$map/item", { enumerable: true, get: () => map.item });
3815
+ Object.defineProperty(child, "$map/index", { enumerable: true, get: () => map.index });
3816
+ const scope = effectScope(true);
3817
+ const childOpts = options ? { ...options, _path: [...path, "map", index] } : undefined;
3818
+ const node = scope.run(() => renderNode(mapDef, child, childOpts));
3819
+ return { key, map, node, scope };
3820
+ };
3821
+ const reconcile = (list, keys) => {
3822
+ const previous = new Map;
3823
+ for (const row of rows) {
3824
+ previous.set(row.key, row);
3825
+ }
3826
+ const next = [];
3827
+ for (let index = 0;index < list.length; index++) {
3828
+ const key = keys[index];
3829
+ const item = list[index];
3830
+ const existing = previous.get(key);
3831
+ if (existing) {
3832
+ previous.delete(key);
3833
+ if (existing.map.item !== item) {
3834
+ existing.map.item = item;
3835
+ }
3836
+ if (existing.map.index !== index) {
3837
+ existing.map.index = index;
3838
+ options?.onNodeMoved?.(existing.node, [...path, "map", index]);
3839
+ }
3840
+ next.push(existing);
3841
+ } else {
3842
+ next.push(createRow(key, item, index));
3843
+ }
3844
+ }
3845
+ for (const row of previous.values()) {
3846
+ teardown(row);
3847
+ }
3848
+ let cursor = rows.find((row) => !previous.has(row.key))?.node ?? anchor;
3849
+ for (const row of next) {
3850
+ if (row.node === cursor) {
3851
+ cursor = cursor.nextSibling ?? anchor;
3852
+ continue;
3853
+ }
3854
+ cursor.before(row.node);
3855
+ }
3856
+ rows = next;
3857
+ };
3858
+ const update = () => {
3183
3859
  let items = isRefObj(itemsSrc) ? resolveRef(itemsSrc.$ref, state) : itemsSrc;
3184
3860
  if (Array.isArray(items) && isRefObj(filterRef)) {
3185
3861
  const fn = resolveRef(filterRef.$ref, state);
@@ -3193,30 +3869,65 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
3193
3869
  items = [...items].toSorted(fn);
3194
3870
  }
3195
3871
  }
3196
- if (!Array.isArray(items) || !mapDef) {
3197
- return;
3198
- }
3199
- const scope = effectScope(true);
3200
- const nodes = [];
3201
- scope.run(() => {
3202
- for (const [index, item] of items.entries()) {
3203
- const child = Object.create(state);
3204
- child.$map = { index, item };
3205
- child["$map/item"] = item;
3206
- child["$map/index"] = index;
3207
- const childOpts = options ? { ...options, _path: [...path, "map", index] } : undefined;
3208
- const node = renderNode(mapDef, child, childOpts);
3209
- anchor.before(node);
3210
- nodes.push(node);
3872
+ const list = Array.isArray(items) && mapDef ? items : [];
3873
+ const keys = list.map((item, index) => mappedRowKey(keyPointer, item, index, warnOnce));
3874
+ const seen = new Set;
3875
+ for (let i = 0;i < keys.length; i++) {
3876
+ if (seen.has(keys[i])) {
3877
+ warnOnce(`duplicate key ${String(keys[i])} — every occurrence after the first is rebuilt on each change`);
3878
+ keys[i] = { duplicate: i };
3879
+ } else {
3880
+ seen.add(keys[i]);
3211
3881
  }
3212
- });
3213
- onEffectCleanup(() => {
3214
- scope.stop();
3215
- for (const n of nodes) {
3216
- n.remove();
3882
+ }
3883
+ pauseTracking();
3884
+ try {
3885
+ reconcile(list, keys);
3886
+ } finally {
3887
+ resetTracking();
3888
+ }
3889
+ };
3890
+ let queued = false;
3891
+ let stopped = false;
3892
+ const runner = effect(update, {
3893
+ scheduler: () => {
3894
+ if (queued) {
3895
+ return;
3217
3896
  }
3218
- });
3897
+ queued = true;
3898
+ queueMicrotask(() => {
3899
+ queued = false;
3900
+ if (!stopped) {
3901
+ runner();
3902
+ }
3903
+ });
3904
+ }
3219
3905
  });
3906
+ onScopeDispose(() => {
3907
+ stopped = true;
3908
+ for (const row of rows) {
3909
+ teardown(row);
3910
+ }
3911
+ rows = [];
3912
+ }, true);
3913
+ }
3914
+ function mappedRowKey(pointer, item, index, warnOnce) {
3915
+ if (pointer === null) {
3916
+ return index;
3917
+ }
3918
+ if (pointer === "$map/item") {
3919
+ return item;
3920
+ }
3921
+ if (pointer.startsWith("$map/item/")) {
3922
+ const key = readPath(item, pointer.slice("$map/item/".length));
3923
+ if (key === undefined || key === null) {
3924
+ warnOnce(`key "${pointer}" is empty for some items — those rows fall back to their index`);
3925
+ return index;
3926
+ }
3927
+ return key;
3928
+ }
3929
+ warnOnce(`key "${pointer}" is not a $map/item pointer — rows fall back to their index`);
3930
+ return index;
3220
3931
  }
3221
3932
  function resolveTagName(tagName, scope) {
3222
3933
  if (typeof tagName === "string") {
@@ -3232,65 +3943,86 @@ function resolveTagName(tagName, scope) {
3232
3943
  const key = evaluateOperand(expression.target, scope, null);
3233
3944
  return expression.cases[String(key)] ?? expression.default;
3234
3945
  }
3235
- function renderSwitch(def2, state, options) {
3946
+ function renderSwitch(def, state, options) {
3236
3947
  const path = options?._path ?? [];
3237
- const container = document.createElement(resolveTagName(def2.tagName, state));
3948
+ const container = document.createElement(resolveTagName(def.tagName, state));
3238
3949
  if (options?.onNodeCreated) {
3239
- options.onNodeCreated(container, path, def2, state);
3950
+ options.onNodeCreated(container, path, def, state);
3240
3951
  }
3241
- applyProperties(container, def2, state);
3242
- applyStyle(container, def2.style ?? {}, state["$media"] ?? {}, state);
3243
- applyAttributes(container, def2.attributes ?? {}, state);
3952
+ applyProperties(container, def, state);
3953
+ applyStyle(container, def.style ?? {}, state["$media"] ?? {}, state);
3954
+ applyAttributes(container, def.attributes ?? {}, state);
3244
3955
  let generation = 0;
3956
+ let live = null;
3957
+ let renderedKey = null;
3958
+ const retire = () => {
3959
+ live?.stop();
3960
+ live = null;
3961
+ };
3245
3962
  effect(() => {
3246
- container.replaceChildren();
3247
- if (!isRefObj(def2.$switch)) {
3963
+ if (!isRefObj(def.$switch)) {
3964
+ retire();
3965
+ container.replaceChildren();
3966
+ generation += 1;
3967
+ return;
3968
+ }
3969
+ const key = String(resolveRef(def.$switch.$ref, state));
3970
+ if (key === renderedKey) {
3248
3971
  return;
3249
3972
  }
3250
- const key = resolveRef(def2.$switch.$ref, state);
3251
- const caseDef = def2.cases?.[key];
3973
+ renderedKey = key;
3974
+ retire();
3975
+ container.replaceChildren();
3976
+ generation += 1;
3977
+ const caseDef = def.cases?.[key];
3252
3978
  if (!caseDef) {
3253
3979
  return;
3254
3980
  }
3981
+ const gen = generation;
3982
+ const scope = effectScope(true);
3983
+ live = scope;
3984
+ const childOpts = options ? { ...options, _path: [...path, "cases", key] } : undefined;
3255
3985
  if (isRefObj(caseDef)) {
3256
- generation += 1;
3257
- const gen = generation;
3258
- const { href } = new URL(caseDef.$ref, location.href);
3259
- resolve(href).then(async (doc) => {
3986
+ const { href } = new URL(caseDef.$ref, options?._ctx?.base ?? location.href);
3987
+ resolve(href, options?._ctx).then(async (doc) => {
3260
3988
  if (gen !== generation) {
3261
3989
  return;
3262
3990
  }
3263
- const childScope = await buildScope(doc, {}, href);
3991
+ const childScope = await buildScope(doc, {}, href, options?._ctx);
3264
3992
  if (gen !== generation) {
3265
3993
  return;
3266
3994
  }
3267
3995
  container.replaceChildren();
3268
- const childOpts2 = options ? { ...options, _path: [...path, "cases", key] } : undefined;
3269
- container.append(renderNode(doc, childScope, childOpts2));
3996
+ scope.run(() => container.append(renderNode(doc, childScope, childOpts)));
3270
3997
  }).catch((error) => console.error("Jx $switch: failed to load external case", caseDef.$ref, error));
3271
3998
  return;
3272
3999
  }
3273
- const childOpts = options ? { ...options, _path: [...path, "cases", key] } : undefined;
3274
- container.append(renderNode(caseDef, state, childOpts));
4000
+ pauseTracking();
4001
+ try {
4002
+ scope.run(() => container.append(renderNode(caseDef, state, childOpts)));
4003
+ } finally {
4004
+ resetTracking();
4005
+ }
3275
4006
  });
4007
+ onScopeDispose(retire, true);
3276
4008
  return container;
3277
4009
  }
3278
- async function resolvePrototype(def2, state, key, base) {
3279
- if (def2.$src) {
3280
- return resolveExternalPrototype(def2, state, key, base);
4010
+ async function resolvePrototype(def, state, key, base, ctx) {
4011
+ if (def.$src) {
4012
+ return resolveExternalPrototype(def, state, key, base);
3281
4013
  }
3282
- switch (def2.$prototype) {
4014
+ switch (def.$prototype) {
3283
4015
  case "Request": {
3284
4016
  const s = ref(null);
3285
- const debounceMs = def2.debounce ?? 0;
4017
+ const debounceMs = def.debounce ?? 0;
3286
4018
  let debounceTimer = null;
3287
- if (!def2.manual && !_autoRequestConfig.skip) {
4019
+ if (!def.manual && !(ctx?.skipAutoRequests ?? _autoRequestConfig.skip)) {
3288
4020
  effect(() => {
3289
4021
  let url;
3290
- if (isTemplateString(def2.url)) {
3291
- url = evaluateTemplate(def2.url, state);
4022
+ if (isTemplateString(def.url)) {
4023
+ url = evaluateTemplate(def.url, state);
3292
4024
  } else {
3293
- ({ url } = def2);
4025
+ ({ url } = def);
3294
4026
  }
3295
4027
  if (!url || url === "undefined" || url.includes("undefined")) {
3296
4028
  return;
@@ -3303,11 +4035,11 @@ async function resolvePrototype(def2, state, key, base) {
3303
4035
  }
3304
4036
  });
3305
4037
  const doFetch = () => fetch(url, {
3306
- method: def2.method ?? "GET",
4038
+ method: def.method ?? "GET",
3307
4039
  signal: controller.signal,
3308
- ...def2.headers && { headers: def2.headers },
3309
- ...def2.body && {
3310
- body: typeof def2.body === "object" ? JSON.stringify(def2.body) : def2.body
4040
+ ...def.headers && { headers: def.headers },
4041
+ ...def.body && {
4042
+ body: typeof def.body === "object" ? JSON.stringify(def.body) : def.body
3311
4043
  }
3312
4044
  }).then((r) => r.ok ? r.json() : Promise.reject(r.statusText)).then((d) => {
3313
4045
  s.value = d;
@@ -3328,7 +4060,7 @@ async function resolvePrototype(def2, state, key, base) {
3328
4060
  case "URLSearchParams": {
3329
4061
  return computed(() => {
3330
4062
  const p = {};
3331
- for (const [k, v] of Object.entries(def2)) {
4063
+ for (const [k, v] of Object.entries(def)) {
3332
4064
  if (k !== "$prototype") {
3333
4065
  p[k] = isRefObj(v) ? resolveRef(v.$ref, state) : isTemplateString(v) ? evaluateTemplate(v, state) : v;
3334
4066
  }
@@ -3338,14 +4070,14 @@ async function resolvePrototype(def2, state, key, base) {
3338
4070
  }
3339
4071
  case "LocalStorage":
3340
4072
  case "SessionStorage": {
3341
- const store = def2.$prototype === "LocalStorage" ? localStorage : sessionStorage;
3342
- const k = def2.key ?? key;
4073
+ const store = def.$prototype === "LocalStorage" ? localStorage : sessionStorage;
4074
+ const k = def.key ?? key;
3343
4075
  let init;
3344
4076
  try {
3345
4077
  const s = store.getItem(k);
3346
- init = s !== null ? JSON.parse(s) : def2.default ?? null;
4078
+ init = s !== null ? JSON.parse(s) : def.default ?? null;
3347
4079
  } catch {
3348
- init = def2.default ?? null;
4080
+ init = def.default ?? null;
3349
4081
  }
3350
4082
  const storageState = ref(init);
3351
4083
  effect(() => {
@@ -3363,7 +4095,7 @@ async function resolvePrototype(def2, state, key, base) {
3363
4095
  return storageState;
3364
4096
  }
3365
4097
  case "Cookie": {
3366
- const name = def2.name ?? key;
4098
+ const name = def.name ?? key;
3367
4099
  const read = () => {
3368
4100
  const raw = readCookie(document.cookie, name);
3369
4101
  if (raw === null) {
@@ -3375,9 +4107,9 @@ async function resolvePrototype(def2, state, key, base) {
3375
4107
  return raw;
3376
4108
  }
3377
4109
  };
3378
- const cookieState = ref(read() ?? def2.default ?? null);
4110
+ const cookieState = ref(read() ?? def.default ?? null);
3379
4111
  effect(() => {
3380
- document.cookie = serializeCookie(name, cookieState.value, def2);
4112
+ document.cookie = serializeCookie(name, cookieState.value, def);
3381
4113
  });
3382
4114
  return cookieState;
3383
4115
  }
@@ -3390,7 +4122,7 @@ async function resolvePrototype(def2, state, key, base) {
3390
4122
  keyPath = "id",
3391
4123
  autoIncrement = true,
3392
4124
  indexes = []
3393
- } = def2;
4125
+ } = def;
3394
4126
  if (!database || !store) {
3395
4127
  throw new Error(`Jx: IndexedDB entry '${key}' requires database and store`);
3396
4128
  }
@@ -3420,28 +4152,28 @@ async function resolvePrototype(def2, state, key, base) {
3420
4152
  return idbState;
3421
4153
  }
3422
4154
  case "Set": {
3423
- return new Set(Array.isArray(def2.default) ? def2.default : []);
4155
+ return new Set(Array.isArray(def.default) ? def.default : []);
3424
4156
  }
3425
4157
  case "Map": {
3426
- return new Map(Object.entries(isJsonObject(def2.default) ? def2.default : {}));
4158
+ return new Map(Object.entries(isJsonObject(def.default) ? def.default : {}));
3427
4159
  }
3428
4160
  case "FormData": {
3429
4161
  const fd = new FormData;
3430
- for (const [k, v] of Object.entries(def2.fields ?? {})) {
4162
+ for (const [k, v] of Object.entries(def.fields ?? {})) {
3431
4163
  fd.append(k, v);
3432
4164
  }
3433
4165
  return fd;
3434
4166
  }
3435
4167
  case "Blob": {
3436
- return new Blob(def2.parts ?? [], {
3437
- type: typeof def2.type === "string" ? def2.type : "text/plain"
4168
+ return new Blob(def.parts ?? [], {
4169
+ type: typeof def.type === "string" ? def.type : "text/plain"
3438
4170
  });
3439
4171
  }
3440
4172
  case "ReadableStream": {
3441
4173
  return null;
3442
4174
  }
3443
4175
  default: {
3444
- console.warn(`Jx: unknown $prototype "${def2.$prototype}" for "${key}". Did you mean to add '$src'?`);
4176
+ console.warn(`Jx: unknown $prototype "${def.$prototype}" for "${key}". Did you mean to add '$src'?`);
3445
4177
  return ref(null);
3446
4178
  }
3447
4179
  }
@@ -3458,17 +4190,20 @@ var EXTERNAL_RESERVED = new Set([
3458
4190
  "arguments",
3459
4191
  "name"
3460
4192
  ]);
3461
- async function resolveExternalPrototype(def2, state, key, base) {
3462
- const src = def2.$src;
4193
+ async function resolveExternalPrototype(def, state, key, base) {
4194
+ const src = def.$src;
3463
4195
  if (!src || !src.endsWith(".class.json")) {
3464
- throw new Error(`Jx: $prototype "${def2.$prototype}" requires a .class.json $src, got "${src}". Wrap the class in a .class.json schema with $implementation.`);
4196
+ throw new Error(`Jx: $prototype "${def.$prototype}" requires a .class.json $src, got "${src}". Wrap the class in a .class.json schema with $implementation.`);
3465
4197
  }
3466
- return resolveClassJson(def2, state, key, base);
4198
+ return resolveClassJson(def, state, key, base);
3467
4199
  }
3468
- async function importAndInstantiate(def2, src, exportName, base) {
4200
+ async function importAndInstantiate(def, src, exportName, base) {
3469
4201
  let mod;
3470
- if (_moduleCache.has(src)) {
3471
- mod = _moduleCache.get(src);
4202
+ const seeded = seededModule(src);
4203
+ if (seeded instanceof Promise) {
4204
+ mod = await seeded;
4205
+ } else if (seeded) {
4206
+ mod = seeded;
3472
4207
  } else {
3473
4208
  try {
3474
4209
  mod = await import(src);
@@ -3490,7 +4225,7 @@ async function importAndInstantiate(def2, src, exportName, base) {
3490
4225
  throw new TypeError(`Jx: "${exportName}" from "${src}" is not a class`);
3491
4226
  }
3492
4227
  const config = {};
3493
- for (const [k, v] of Object.entries(def2)) {
4228
+ for (const [k, v] of Object.entries(def)) {
3494
4229
  if (!EXTERNAL_RESERVED.has(k)) {
3495
4230
  config[k] = v;
3496
4231
  }
@@ -3513,15 +4248,15 @@ async function importAndInstantiate(def2, src, exportName, base) {
3513
4248
  }
3514
4249
  return s;
3515
4250
  }
3516
- async function resolveClassJson(def2, state, key, base) {
3517
- const src = def2.$src;
4251
+ async function resolveClassJson(def, state, key, base) {
4252
+ const src = def.$src;
3518
4253
  if (!src) {
3519
4254
  throw new Error(`Jx: class entry '${key}' has no $src`);
3520
4255
  }
3521
4256
  let classDef;
3522
4257
  const isBareSpecifier = !src.startsWith(".") && !src.startsWith("/") && !src.startsWith("http") && !src.startsWith("file:");
3523
4258
  if (isBareSpecifier) {
3524
- return resolveViaDevProxy(def2, state, key, base);
4259
+ return resolveViaDevProxy(def, state, key, base);
3525
4260
  }
3526
4261
  try {
3527
4262
  const url = base ? new URL(src, base).href : src;
@@ -3531,25 +4266,25 @@ async function resolveClassJson(def2, state, key, base) {
3531
4266
  }
3532
4267
  classDef = await res.json();
3533
4268
  } catch {
3534
- return resolveViaDevProxy(def2, state, key, base);
4269
+ return resolveViaDevProxy(def, state, key, base);
3535
4270
  }
3536
4271
  if (classDef.$implementation) {
3537
4272
  const schemaStr = JSON.stringify(classDef);
3538
4273
  if (schemaStr.includes('"#/$context/')) {
3539
- return resolveViaDevProxy(def2, state, key, base);
4274
+ return resolveViaDevProxy(def, state, key, base);
3540
4275
  }
3541
4276
  const schemaUrl = base ? new URL(src, base).href : new URL(src, location.href).href;
3542
4277
  const implSrc = new URL(classDef.$implementation, schemaUrl).href;
3543
- const exportName = def2.$export ?? classDef.title ?? def2.$prototype;
4278
+ const exportName = def.$export ?? classDef.title ?? def.$prototype;
3544
4279
  try {
3545
- return await importAndInstantiate(def2, implSrc, exportName, base);
4280
+ return await importAndInstantiate(def, implSrc, exportName, base);
3546
4281
  } catch {
3547
- return resolveViaDevProxy(def2, state, key, base);
4282
+ return resolveViaDevProxy(def, state, key, base);
3548
4283
  }
3549
4284
  }
3550
4285
  const DynClass = classFromSchema(classDef);
3551
4286
  const config = {};
3552
- for (const [k, v] of Object.entries(def2)) {
4287
+ for (const [k, v] of Object.entries(def)) {
3553
4288
  if (!EXTERNAL_RESERVED.has(k)) {
3554
4289
  config[k] = v;
3555
4290
  }
@@ -3636,9 +4371,9 @@ function classFromSchema(classDef) {
3636
4371
  const dynCtor = DynClass;
3637
4372
  return dynCtor;
3638
4373
  }
3639
- async function resolveViaDevProxy(def2, state, key, base) {
4374
+ async function resolveViaDevProxy(def, state, key, base) {
3640
4375
  const config = {};
3641
- for (const [k, v] of Object.entries(def2)) {
4376
+ for (const [k, v] of Object.entries(def)) {
3642
4377
  if (!EXTERNAL_RESERVED.has(k)) {
3643
4378
  config[k] = v;
3644
4379
  }
@@ -3647,9 +4382,9 @@ async function resolveViaDevProxy(def2, state, key, base) {
3647
4382
  const doResolve = (resolvedConfig) => fetch(resolveProxyPath("/__jx_resolve__"), {
3648
4383
  body: JSON.stringify({
3649
4384
  $base: base,
3650
- $export: def2.$export,
3651
- $prototype: def2.$prototype,
3652
- $src: def2.$src,
4385
+ $export: def.$export,
4386
+ $prototype: def.$prototype,
4387
+ $src: def.$src,
3653
4388
  ...resolvedConfig
3654
4389
  }),
3655
4390
  headers: { "Content-Type": "application/json" },
@@ -3678,12 +4413,15 @@ async function resolveViaDevProxy(def2, state, key, base) {
3678
4413
  }
3679
4414
  return s;
3680
4415
  }
3681
- async function resolveServerFunction(def2, state, key, base) {
3682
- const src = def2.$src;
3683
- const exportName = def2.$export;
4416
+ async function resolveServerFunction(def, state, key, base) {
4417
+ const src = def.$src;
4418
+ const exportName = def.$export;
3684
4419
  let mod;
3685
- if (_moduleCache.has(src)) {
3686
- mod = _moduleCache.get(src);
4420
+ const seeded = seededModule(src);
4421
+ if (seeded instanceof Promise) {
4422
+ mod = await seeded;
4423
+ } else if (seeded) {
4424
+ mod = seeded;
3687
4425
  } else {
3688
4426
  try {
3689
4427
  mod = await import(src);
@@ -3693,10 +4431,10 @@ async function resolveServerFunction(def2, state, key, base) {
3693
4431
  const resolvedSrc = new URL(src, base).href;
3694
4432
  mod = await import(resolvedSrc);
3695
4433
  } catch {
3696
- return resolveServerFunctionViaProxy(def2, state, key, base);
4434
+ return resolveServerFunctionViaProxy(def, state, key, base);
3697
4435
  }
3698
4436
  } else {
3699
- return resolveServerFunctionViaProxy(def2, state, key, base);
4437
+ return resolveServerFunctionViaProxy(def, state, key, base);
3700
4438
  }
3701
4439
  }
3702
4440
  _moduleCache.set(src, mod);
@@ -3709,7 +4447,7 @@ async function resolveServerFunction(def2, state, key, base) {
3709
4447
  throw new TypeError(`Jx: "${exportName}" from "${src}" is not a function`);
3710
4448
  }
3711
4449
  const fn = candidate;
3712
- const rawArgs = def2.arguments ?? {};
4450
+ const rawArgs = def.arguments ?? {};
3713
4451
  const hasReactiveArg = Object.values(rawArgs).some((v) => isRefObj(v));
3714
4452
  const resolveArgs = () => {
3715
4453
  const args = {};
@@ -3732,8 +4470,8 @@ async function resolveServerFunction(def2, state, key, base) {
3732
4470
  }
3733
4471
  return s;
3734
4472
  }
3735
- async function resolveServerFunctionViaProxy(def2, state, key, base) {
3736
- const rawArgs = def2.arguments ?? {};
4473
+ async function resolveServerFunctionViaProxy(def, state, key, base) {
4474
+ const rawArgs = def.arguments ?? {};
3737
4475
  const hasReactiveArg = Object.values(rawArgs).some((v) => isRefObj(v));
3738
4476
  const resolveArgs = () => {
3739
4477
  const args = {};
@@ -3745,8 +4483,8 @@ async function resolveServerFunctionViaProxy(def2, state, key, base) {
3745
4483
  const doResolve = (args) => fetch(resolveProxyPath("/__jx_server__"), {
3746
4484
  body: JSON.stringify({
3747
4485
  $base: base,
3748
- $export: def2.$export,
3749
- $src: def2.$src,
4486
+ $export: def.$export,
4487
+ $src: def.$src,
3750
4488
  arguments: args
3751
4489
  }),
3752
4490
  headers: { "Content-Type": "application/json" },
@@ -3777,8 +4515,8 @@ function resolveRef(refPath, state) {
3777
4515
  if (typeof refPath !== "string") {
3778
4516
  return refPath;
3779
4517
  }
3780
- if (refPath.startsWith("$map/")) {
3781
- const parts = refPath.split("/");
4518
+ if (refPath.startsWith("$map/") || refPath.startsWith("#/$map/")) {
4519
+ const parts = (refPath.startsWith("#/") ? refPath.slice(2) : refPath).split("/");
3782
4520
  const [, key] = parts;
3783
4521
  const map = state.$map;
3784
4522
  const base = map?.[key] ?? state[`$map/${key}`];
@@ -3801,12 +4539,41 @@ function resolveRef(refPath, state) {
3801
4539
  function isRefObj(v) {
3802
4540
  return isRef(v);
3803
4541
  }
3804
- function isNestedSelector(k) {
3805
- return k.startsWith(":") || k.startsWith(".") || k.startsWith("&") || k.startsWith("[");
3806
- }
3807
4542
  function getPath2(obj, path) {
3808
4543
  return readPath(obj, path);
3809
4544
  }
4545
+ function absorbAttribute(state, name, value, defaults) {
4546
+ const camelKey = name.replaceAll(/-([a-z])/g, (_, c) => c.toUpperCase());
4547
+ const current = state[camelKey];
4548
+ if (typeof current === "boolean") {
4549
+ state[camelKey] = value !== null && value !== "false";
4550
+ return;
4551
+ }
4552
+ if (value === null) {
4553
+ const declared = defaults?.get(camelKey);
4554
+ state[camelKey] = declared === undefined ? typeof current === "number" ? 0 : "" : declared;
4555
+ return;
4556
+ }
4557
+ state[camelKey] = typeof current === "number" ? Number(value) : value;
4558
+ }
4559
+ function declaredDefaults(def) {
4560
+ const out = new Map;
4561
+ for (const [key, entry] of Object.entries(def.state ?? {})) {
4562
+ if (entry !== null && typeof entry === "object") {
4563
+ const obj = entry;
4564
+ if ("default" in obj) {
4565
+ out.set(key, obj["default"]);
4566
+ continue;
4567
+ }
4568
+ if (COMPUTED_STATE_KEYS.some((marker) => (marker in obj))) {
4569
+ continue;
4570
+ }
4571
+ }
4572
+ out.set(key, entry);
4573
+ }
4574
+ return out;
4575
+ }
4576
+ var COMPUTED_STATE_KEYS = ["$expression", "$prototype", "$ref", "$src"];
3810
4577
  var _privatePropWarned = new Set;
3811
4578
  function instanceSupplies(el, key) {
3812
4579
  if (Object.hasOwn(el, key)) {
@@ -3829,9 +4596,9 @@ function refusePrivateProp(key, where) {
3829
4596
  }
3830
4597
  return true;
3831
4598
  }
3832
- function mergeProps(def2, parentState) {
4599
+ function mergeProps(def, parentState) {
3833
4600
  const child = Object.create(parentState);
3834
- for (const [k, v] of Object.entries(def2.$props ?? {})) {
4601
+ for (const [k, v] of Object.entries(def.$props ?? {})) {
3835
4602
  if (refusePrivateProp(k, "$props")) {
3836
4603
  continue;
3837
4604
  }
@@ -3839,15 +4606,32 @@ function mergeProps(def2, parentState) {
3839
4606
  }
3840
4607
  return child;
3841
4608
  }
3842
- function toCSSText(rules) {
3843
- return Object.entries(rules).filter(([k, v]) => !isNestedSelector(k) && (v === null || typeof v !== "object")).map(([p, v]) => `${camelToKebab(p)}: ${canvasStyleValue(String(v))}`).join("; ");
3844
- }
3845
4609
  var _rootMedia = {};
3846
4610
  var _elementDefs = new Map;
4611
+ async function redefineElement(doc, baseUrl) {
4612
+ const base = baseUrl ?? location.href;
4613
+ const { tagName } = doc;
4614
+ if (!tagName || !tagName.includes("-")) {
4615
+ throw new Error(`Jx redefineElement: tagName "${tagName}" must contain a hyphen`);
4616
+ }
4617
+ if (!customElements.get(tagName)) {
4618
+ await defineElement(doc, base);
4619
+ return;
4620
+ }
4621
+ if (doc.$elements) {
4622
+ await registerElements(doc.$elements, base);
4623
+ }
4624
+ const before = _elementDefs.get(tagName)?.doc.observedAttributes ?? [];
4625
+ const after = doc.observedAttributes ?? [];
4626
+ if (JSON.stringify(before) !== JSON.stringify(after)) {
4627
+ console.warn(`Jx redefineElement: <${tagName}> keeps observedAttributes [${before.join(", ")}] as first defined; [${after.join(", ")}] takes effect only in a fresh realm`);
4628
+ }
4629
+ _elementDefs.set(tagName, { base, doc });
4630
+ }
3847
4631
  function setRootMedia(map) {
3848
4632
  _rootMedia = map ?? {};
3849
4633
  }
3850
- async function registerElements(elements, base) {
4634
+ async function registerElements(elements, base, ctx) {
3851
4635
  for (const entry of elements) {
3852
4636
  if (typeof entry === "string") {
3853
4637
  try {
@@ -3862,7 +4646,7 @@ async function registerElements(elements, base) {
3862
4646
  continue;
3863
4647
  }
3864
4648
  const { href } = new URL(entry.$ref, base);
3865
- const doc = await resolve(href);
4649
+ const doc = await resolve(href, ctx);
3866
4650
  if (!doc.tagName || !doc.tagName.includes("-")) {
3867
4651
  continue;
3868
4652
  }
@@ -3870,7 +4654,7 @@ async function registerElements(elements, base) {
3870
4654
  continue;
3871
4655
  }
3872
4656
  if (doc.$elements) {
3873
- await registerElements(doc.$elements, href);
4657
+ await registerElements(doc.$elements, href, ctx);
3874
4658
  }
3875
4659
  await defineElement(doc, href);
3876
4660
  }
@@ -3900,8 +4684,9 @@ async function defineElement(source, baseUrl) {
3900
4684
  await registerElements(source_.$elements, base);
3901
4685
  }
3902
4686
  _elementDefs.set(tagName, { base, doc: source_ });
3903
- const def2 = source_;
3904
- const observedAttrs = def2.observedAttributes ?? [];
4687
+ const initialDef = source_;
4688
+ const initialBase = base;
4689
+ const observedAttrs = initialDef.observedAttributes ?? [];
3905
4690
  const ElementClass = class extends HTMLElement {
3906
4691
  _jxInitialized = false;
3907
4692
  _state = null;
@@ -3916,7 +4701,15 @@ async function defineElement(source, baseUrl) {
3916
4701
  return;
3917
4702
  }
3918
4703
  this._jxInitialized = true;
3919
- const state = await buildScope(def2, {}, base);
4704
+ const live = _elementDefs.get(tagName) ?? { base: initialBase, doc: initialDef };
4705
+ const def = live.doc;
4706
+ const defBase = live.base;
4707
+ const state = await buildScope(def, {}, defBase, { base: defBase, media: null, root: this });
4708
+ for (const attr of observedAttrs) {
4709
+ if (this.hasAttribute(attr)) {
4710
+ absorbAttribute(state, attr, this.getAttribute(attr));
4711
+ }
4712
+ }
3920
4713
  const propsAttr = this.dataset.jxProps;
3921
4714
  if (propsAttr) {
3922
4715
  try {
@@ -3925,7 +4718,7 @@ async function defineElement(source, baseUrl) {
3925
4718
  if (refusePrivateProp(key, "data-jx-props")) {
3926
4719
  continue;
3927
4720
  }
3928
- if (key in (def2.state ?? {})) {
4721
+ if (key in (def.state ?? {})) {
3929
4722
  state[key] = val;
3930
4723
  }
3931
4724
  }
@@ -3939,12 +4732,12 @@ async function defineElement(source, baseUrl) {
3939
4732
  this.removeAttribute(name);
3940
4733
  continue;
3941
4734
  }
3942
- if (key in (def2.state ?? {})) {
4735
+ if (key in (def.state ?? {})) {
3943
4736
  state[key] = this.getAttribute(name);
3944
4737
  this.removeAttribute(name);
3945
4738
  }
3946
4739
  }
3947
- for (const key of Object.keys(def2.state ?? {})) {
4740
+ for (const key of Object.keys(def.state ?? {})) {
3948
4741
  if (isPrivateStateKey(key)) {
3949
4742
  continue;
3950
4743
  }
@@ -3952,7 +4745,7 @@ async function defineElement(source, baseUrl) {
3952
4745
  state[key] = this[key];
3953
4746
  }
3954
4747
  }
3955
- for (const key of Object.keys(def2.state ?? {})) {
4748
+ for (const key of Object.keys(def.state ?? {})) {
3956
4749
  if (isPrivateStateKey(key)) {
3957
4750
  continue;
3958
4751
  }
@@ -3969,22 +4762,28 @@ async function defineElement(source, baseUrl) {
3969
4762
  this._state = state;
3970
4763
  const slottedChildren = [...this.childNodes];
3971
4764
  this.replaceChildren();
3972
- if (!this.style.display) {
3973
- this.style.display = "block";
3974
- }
3975
- applyStyle(this, def2.style ?? {}, state["$media"] ?? {}, state);
3976
- applyAttributes(this, def2.attributes ?? {}, state);
3977
- if (!Array.isArray(def2.children) && def2.textContent !== undefined) {
3978
- bindProperty(this, "textContent", def2.textContent, state);
3979
- }
3980
- const children = Array.isArray(def2.children) ? def2.children : [];
3981
- for (const childDef of children) {
3982
- this.append(renderNode(childDef, state));
4765
+ const defStyle = declaresDisplay(def.style) ? def.style : { display: "block", ...def.style };
4766
+ const hostStyle = mergeStyle(defStyle, callSiteStyles.get(this));
4767
+ applyStyle(this, hostStyle, state["$media"] ?? {}, state);
4768
+ applyAttributes(this, def.attributes ?? {}, state);
4769
+ bindDefinitionHandlers(this, def, state);
4770
+ if (!Array.isArray(def.children) && def.textContent !== undefined) {
4771
+ bindProperty(this, "textContent", def.textContent, state);
4772
+ }
4773
+ const children = Array.isArray(def.children) ? def.children : [];
4774
+ const wasInside = _canvasInsideStampedHost;
4775
+ _canvasInsideStampedHost ||= this.dataset.jxPath !== undefined;
4776
+ try {
4777
+ for (const childDef of children) {
4778
+ this.append(renderNode(childDef, state));
4779
+ }
4780
+ } finally {
4781
+ _canvasInsideStampedHost = wasInside;
3983
4782
  }
3984
4783
  distributeSlots(this, slottedChildren);
3985
4784
  const { onMount } = state;
3986
4785
  if (typeof onMount === "function") {
3987
- queueMicrotask(() => onMount(state));
4786
+ queueMicrotask(() => onMount(state, this));
3988
4787
  }
3989
4788
  }
3990
4789
  disconnectedCallback() {
@@ -4001,25 +4800,17 @@ async function defineElement(source, baseUrl) {
4001
4800
  if (!this._state || oldVal === newVal) {
4002
4801
  return;
4003
4802
  }
4004
- const camelKey = name.replaceAll(/-([a-z])/g, (_, c) => c.toUpperCase());
4005
- const current = this._state[camelKey];
4006
- if (typeof current === "number") {
4007
- this._state[camelKey] = Number(newVal);
4008
- } else if (typeof current === "boolean") {
4009
- this._state[camelKey] = newVal !== null && newVal !== "false";
4010
- } else {
4011
- this._state[camelKey] = newVal;
4012
- }
4803
+ absorbAttribute(this._state, name, newVal, declaredDefaults(_elementDefs.get(tagName)?.doc ?? initialDef));
4013
4804
  }
4014
4805
  };
4015
4806
  customElements.define(tagName, ElementClass);
4016
4807
  }
4017
- function renderCustomElementWithProps(def2, state, options, path) {
4018
- const el = document.createElement(resolveTagName(def2.tagName, state));
4808
+ function renderCustomElementWithProps(def, state, options, path) {
4809
+ const el = document.createElement(resolveTagName(def.tagName, state));
4019
4810
  if (options?.onNodeCreated) {
4020
- options.onNodeCreated(el, path ?? [], def2, state);
4811
+ options.onNodeCreated(el, path ?? [], def, state);
4021
4812
  }
4022
- for (const [key, val] of Object.entries(def2.$props ?? {})) {
4813
+ for (const [key, val] of Object.entries(def.$props ?? {})) {
4023
4814
  if (refusePrivateProp(key, "$props")) {
4024
4815
  continue;
4025
4816
  }
@@ -4040,19 +4831,25 @@ function renderCustomElementWithProps(def2, state, options, path) {
4040
4831
  write(val);
4041
4832
  }
4042
4833
  }
4043
- applyStyle(el, def2.style ?? {}, state["$media"] ?? {}, state);
4044
- applyAttributes(el, def2.attributes ?? {}, state);
4045
- const children = Array.isArray(def2.children) ? def2.children : [];
4834
+ if (def.style) {
4835
+ callSiteStyles.set(el, def.style);
4836
+ }
4837
+ applyStyle(el, def.style ?? {}, state["$media"] ?? {}, state);
4838
+ applyAttributes(el, def.attributes ?? {}, state);
4839
+ applyProperties(el, def, state);
4840
+ const children = Array.isArray(def.children) ? def.children : [];
4046
4841
  for (let i = 0;i < children.length; i++) {
4842
+ const child = children[i];
4047
4843
  const childOpts = options && path ? { ...options, _path: [...path, "children", i] } : undefined;
4048
- el.append(renderNode(children[i], state, childOpts));
4844
+ if (isMappedArray(child)) {
4845
+ renderMappedArrayInto(el, child, state, childOpts);
4846
+ } else {
4847
+ el.append(renderNode(child, state, childOpts));
4848
+ }
4049
4849
  }
4050
4850
  return el;
4051
4851
  }
4052
4852
  function distributeSlots(host, slottedChildren) {
4053
- if (slottedChildren.length === 0) {
4054
- return;
4055
- }
4056
4853
  const slots = host.querySelectorAll("slot");
4057
4854
  if (slots.length === 0) {
4058
4855
  return;
@@ -4073,12 +4870,7 @@ function distributeSlots(host, slottedChildren) {
4073
4870
  for (const slot of slots) {
4074
4871
  const name = slot.getAttribute("name");
4075
4872
  const matches = name ? named.get(name) ?? [] : unnamed;
4076
- if (matches.length > 0) {
4077
- slot.replaceChildren();
4078
- for (const child of matches) {
4079
- slot.append(child);
4080
- }
4081
- }
4873
+ slot.replaceWith(...matches.length > 0 ? matches : [...slot.childNodes]);
4082
4874
  }
4083
4875
  }
4084
4876
 
@@ -4124,14 +4916,18 @@ function mountedRefFor(value, entryDir, mount) {
4124
4916
  }
4125
4917
 
4126
4918
  // src/canvas/path-mapping.ts
4919
+ function jxPathSelector(serialized) {
4920
+ const escaped = serialized.replaceAll("\\", String.raw`\\`).replaceAll("'", String.raw`\'`);
4921
+ return `[data-jx-path='${escaped}']`;
4922
+ }
4127
4923
  function wrapsPageContent(path, prefix) {
4128
4924
  if (!prefix) {
4129
4925
  return false;
4130
4926
  }
4131
4927
  return path.length <= prefix.length && path.every((seg, i) => prefix[i] === seg);
4132
4928
  }
4133
- function classifyRenderNode(path, def2, ctx) {
4134
- const marker = ctx.layoutWrapped && typeof def2 === "object" ? def2?.$__layout : undefined;
4929
+ function classifyRenderNode(path, def, ctx) {
4930
+ const marker = ctx.layoutWrapped && typeof def === "object" ? def?.$__layout : undefined;
4135
4931
  if (marker) {
4136
4932
  const origin = typeof marker === "object" ? marker : {};
4137
4933
  return {
@@ -4150,7 +4946,7 @@ function classifyRenderNode(path, def2, ctx) {
4150
4946
  mappedPath = typeof containerIdx === "number" ? ["children", containerIdx - (ctx.pageContentOffset ?? 0), ...rest.slice(1)] : ["children", ...rest];
4151
4947
  }
4152
4948
  }
4153
- if ((ctx.canvasMode === "design" || ctx.canvasMode === "edit") && ctx.arrayPaths.size > 0) {
4949
+ if (ctx.arrayPaths.size > 0) {
4154
4950
  let changed = true;
4155
4951
  while (changed) {
4156
4952
  changed = false;
@@ -4172,57 +4968,159 @@ function parseJxPath(serialized) {
4172
4968
  return JSON.parse(serialized);
4173
4969
  }
4174
4970
 
4971
+ // src/canvas/iframe-position.ts
4972
+ function isIslandBoundary(el) {
4973
+ if (el.dataset.jxDefinitionRoot !== undefined) {
4974
+ return false;
4975
+ }
4976
+ return el.getAttribute("contenteditable") === "false" || el.tagName.includes("-");
4977
+ }
4978
+ function activeBlockAt(node, isEditable) {
4979
+ let el = node instanceof Element ? node : node?.parentElement ?? null;
4980
+ while (el) {
4981
+ if (el instanceof HTMLElement) {
4982
+ if (el.dataset.jxPath && isEditable(el)) {
4983
+ return { el, path: parseJxPath(el.dataset.jxPath) };
4984
+ }
4985
+ if (isIslandBoundary(el)) {
4986
+ return null;
4987
+ }
4988
+ }
4989
+ el = el.parentElement;
4990
+ }
4991
+ return null;
4992
+ }
4993
+ function elementForPath(container, path) {
4994
+ const el = container.querySelector(jxPathSelector(serializeJxPath(path)));
4995
+ return el instanceof HTMLElement ? el : null;
4996
+ }
4997
+ function blockTextLength(block) {
4998
+ return block.textContent?.length ?? 0;
4999
+ }
5000
+ function offsetOf(block, node, offset) {
5001
+ if (!block.contains(node)) {
5002
+ return null;
5003
+ }
5004
+ const range = block.ownerDocument.createRange();
5005
+ range.setStart(block, 0);
5006
+ try {
5007
+ range.setEnd(node, offset);
5008
+ } catch {
5009
+ return null;
5010
+ }
5011
+ return range.toString().length;
5012
+ }
5013
+ function domPositionAt(block, offset) {
5014
+ const target = Math.max(0, Math.min(offset, blockTextLength(block)));
5015
+ const walker = block.ownerDocument.createTreeWalker(block, NodeFilter.SHOW_TEXT);
5016
+ let seen = 0;
5017
+ let last = null;
5018
+ let current = walker.nextNode();
5019
+ while (current) {
5020
+ const len = current.length;
5021
+ if (seen + len >= target) {
5022
+ return { node: current, offset: target - seen };
5023
+ }
5024
+ seen += len;
5025
+ last = current;
5026
+ current = walker.nextNode();
5027
+ }
5028
+ return last ? { node: last, offset: last.length } : { node: block, offset: 0 };
5029
+ }
5030
+ function toDocPos(node, offset, isEditable) {
5031
+ const block = activeBlockAt(node, isEditable);
5032
+ if (!block || !node) {
5033
+ return null;
5034
+ }
5035
+ const charOffset = offsetOf(block.el, node, offset);
5036
+ return charOffset === null ? null : { offset: charOffset, path: block.path };
5037
+ }
5038
+ function toDomPosition(container, pos) {
5039
+ const el = elementForPath(container, pos.path);
5040
+ return el ? domPositionAt(el, pos.offset) : null;
5041
+ }
5042
+ function isAtBlockStart(pos) {
5043
+ return pos.offset <= 0;
5044
+ }
5045
+ function samePath(a, b) {
5046
+ return serializeJxPath(a.path) === serializeJxPath(b.path);
5047
+ }
5048
+ function blocksInOrder(container, isEditable) {
5049
+ const out = [];
5050
+ for (const el of container.querySelectorAll("[data-jx-path]")) {
5051
+ if (isEditable(el) && !sealedInIsland(el, container)) {
5052
+ out.push(el);
5053
+ }
5054
+ }
5055
+ return out;
5056
+ }
5057
+ function sealedInIsland(el, container) {
5058
+ let cur = el.parentElement;
5059
+ while (cur && cur !== container) {
5060
+ if (isIslandBoundary(cur)) {
5061
+ return true;
5062
+ }
5063
+ cur = cur.parentElement;
5064
+ }
5065
+ return false;
5066
+ }
5067
+ function adjacentBlock(container, path, direction, isEditable) {
5068
+ const blocks = blocksInOrder(container, isEditable);
5069
+ const key = serializeJxPath(path);
5070
+ const index = blocks.findIndex((el) => el.dataset.jxPath === key);
5071
+ const neighbour = index === -1 ? undefined : blocks[index + direction];
5072
+ return neighbour ? { el: neighbour, path: parseJxPath(neighbour.dataset.jxPath) } : null;
5073
+ }
5074
+
4175
5075
  // ../site/src/site-style.ts
4176
5076
  var SITE_STYLE_ID = "jx-site-style";
4177
- function toDecls(props, transpose) {
4178
- return Object.entries(props).map(([key, value]) => `${camelToKebab(key)}: ${transpose(String(value))}`).join("; ");
4179
- }
4180
5077
  function buildSiteStyleCSS(siteStyle, mediaQueries, transpose) {
4181
5078
  const rules = [];
5079
+ const push = (style, selector) => {
5080
+ for (const rule of buildStyleRules(style, {
5081
+ mediaQueries,
5082
+ scope: selector,
5083
+ transposeValue: transpose
5084
+ })) {
5085
+ rules.push(rule.text);
5086
+ }
5087
+ };
4182
5088
  const rootProps = {};
4183
5089
  const bodyProps = {};
4184
5090
  const condBlocks = [];
5091
+ const selectorBlocks = [];
4185
5092
  for (const [key, value] of Object.entries(siteStyle)) {
4186
5093
  if (value !== null && typeof value === "object" && !Array.isArray(value)) {
4187
5094
  if (key.startsWith("@")) {
4188
5095
  condBlocks.push([key, value]);
5096
+ } else if (!key.startsWith("--")) {
5097
+ selectorBlocks.push([key, value]);
4189
5098
  }
4190
5099
  continue;
4191
5100
  }
4192
- if (key.startsWith(":") || key.startsWith(".") || key.startsWith("[") || key.startsWith("@")) {
5101
+ if (isNestedSelectorKey(key) || key.startsWith("@")) {
4193
5102
  continue;
4194
5103
  }
4195
- if (key.startsWith("--")) {
5104
+ if (key.startsWith("--") || key === "colorScheme" || key === "color-scheme") {
4196
5105
  rootProps[key] = value;
4197
5106
  } else {
4198
5107
  bodyProps[key] = value;
4199
5108
  }
4200
5109
  }
4201
- const rootCSS = toDecls(rootProps, transpose);
4202
- if (rootCSS) {
4203
- rules.push(`:root { ${rootCSS} }`);
4204
- }
4205
- const bodyCSS = toDecls(bodyProps, transpose);
4206
- if (bodyCSS) {
4207
- rules.push(`body { ${bodyCSS} }`);
4208
- }
4209
- for (const [atKey, block] of condBlocks) {
4210
- const query = resolveAtQuery(atKey, mediaQueries);
4211
- if (query === null) {
4212
- continue;
5110
+ push(rootProps, ":root");
5111
+ push(bodyProps, "body");
5112
+ for (const [key, block] of selectorBlocks) {
5113
+ if (key.startsWith("&")) {
5114
+ push({ [key]: block }, ":root");
5115
+ } else {
5116
+ push(block, key);
5117
+ }
5118
+ }
5119
+ for (const [atKey, block] of condBlocks) {
5120
+ if (isDeclarationAtRule(atKey) || isKeyframesAtRule(atKey)) {
5121
+ push({ [atKey]: block }, null);
5122
+ continue;
4213
5123
  }
4214
- const scheme = pureSchemeOf(query);
4215
- const emit = (selector, props) => {
4216
- if (!props) {
4217
- return;
4218
- }
4219
- if (scheme) {
4220
- const { auto, forced } = schemeSelectors(selector, scheme);
4221
- rules.push(`@media ${query} { ${auto} { ${props} } }`, `${forced} { ${props} }`);
4222
- } else {
4223
- rules.push(`@media ${query} { ${selector} { ${props} } }`);
4224
- }
4225
- };
4226
5124
  const condRoot = {};
4227
5125
  const condBody = {};
4228
5126
  const condSubs = [];
@@ -4239,14 +5137,14 @@ function buildSiteStyleCSS(siteStyle, mediaQueries, transpose) {
4239
5137
  condBody[k] = v;
4240
5138
  }
4241
5139
  }
4242
- emit(":root", toDecls(condRoot, transpose));
4243
- emit("body", toDecls(condBody, transpose));
5140
+ push({ [atKey]: condRoot }, ":root");
5141
+ push({ [atKey]: condBody }, "body");
4244
5142
  for (const [sel, sub] of condSubs) {
4245
- emit(sel, toDecls(sub, transpose));
5143
+ push({ [atKey]: sub }, sel);
4246
5144
  }
4247
5145
  }
4248
- if (Object.values(mediaQueries).some((q) => pureSchemeOf(q) !== null)) {
4249
- rules.push(":root { color-scheme: light dark }");
5146
+ if (Object.values(mediaQueries).some((q) => pureSchemeOf(q) !== null) && !("colorScheme" in siteStyle)) {
5147
+ rules.push(":root { color-scheme: light dark }", `:root:where([${COLOR_SCHEME_ATTR}="light"]) { color-scheme: light }`, `:root:where([${COLOR_SCHEME_ATTR}="dark"]) { color-scheme: dark }`);
4250
5148
  }
4251
5149
  return rules.join(`
4252
5150
  `);
@@ -4386,6 +5284,196 @@ function syncEditModeCss(doc, mode) {
4386
5284
  style.textContent = EDIT_PLACEHOLDER_CSS;
4387
5285
  doc.head.append(style);
4388
5286
  }
5287
+ var CANVAS_OVERLAY_STYLE_ID = "jx-canvas-overlay-css";
5288
+ var CANVAS_OVERLAY_CSS = `
5289
+ /* The UA rule a de-popovered element lost, re-supplied at UA-EQUIVALENT PRECEDENCE.
5290
+
5291
+ The cascade layer is the mechanism and it is the whole point. An unlayered author declaration
5292
+ beats a layered one whatever its specificity, and every declaration applyStyle emits is an
5293
+ unlayered rule in an adopted sheet. That is exactly how author origin beats UA origin on the
5294
+ shipped page, so the canvas reproduces the real cascade rather than an approximation of it.
5295
+
5296
+ This used to read "a base declaration is written as an INLINE style", which was true and is the
5297
+ reason the guarantee survived the move: inline beat layered harder still, and unlayered beats it
5298
+ by the same rule one step down. Jx emits no layer of its own, which is what keeps that true.
5299
+
5300
+ Deliberately NOT forced with a priority flag. A popover whose base rule sets display is laid out
5301
+ on every page whether open or not; that is a real defect, @jxsuite/schema/overlays reports it as
5302
+ base-display, and the canvas's job is to SHOW it, not to hide it behind a stronger rule. */
5303
+ @layer jx-canvas-ua {
5304
+ [data-jx-popover]:not([data-jx-popover-open]) {
5305
+ display: none;
5306
+ }
5307
+ dialog[data-jx-dialog-open] {
5308
+ display: block;
5309
+ }
5310
+ }
5311
+ /* SHOWN IN PLACE, and the position declaration is what makes that true.
5312
+
5313
+ Dropping the popover attribute drops the UA rule that made the panel fixed, so a panel that never
5314
+ set position itself — every one in the fleet — lands in normal flow at its document position,
5315
+ contributes to #jx-canvas-root's scrollHeight, and the host grows the artboard to fit it. That is
5316
+ the whole geometry fix, and it is why an open panel is reachable at all.
5317
+
5318
+ The two alignment declarations are the other half, and they were found by measuring rather than
5319
+ by reasoning. Every drawer in the fleet is declared inside its header's flex row, so in flow it
5320
+ becomes a FLEX ITEM: align-items:center on the row centres a 904px panel on a 64px header and
5321
+ half of it sits above the artboard at a negative offset, where it contributes nothing to the
5322
+ scrollable overflow the host measures. Pinned to the start and refused any flex sizing, the same
5323
+ panel hangs down from its own position and the artboard grows by its full height.
5324
+
5325
+ Forced, because a panel that DOES set position: fixed would otherwise keep it and be laid out
5326
+ against the frame's own viewport — which in a de-linked mode is the document's full height, so a
5327
+ drawer pinned with inset: 0 lands halfway down a long page and a short component frame clips it.
5328
+ This is a presentation override for a canvas affordance, the same kind as the layout-region
5329
+ dimming in EDIT_PLACEHOLDER_CSS, and it is NOT the same move as forcing display: that would hide
5330
+ a real defect in the document (base-display), while this hides nothing — Preview renders the
5331
+ panel natively, top layer and all. */
5332
+ [data-jx-popover][data-jx-popover-open] {
5333
+ position: relative !important;
5334
+ inset: auto !important;
5335
+ align-self: start !important;
5336
+ flex: none !important;
5337
+ outline: 1px dashed color-mix(in srgb, #808080 55%, transparent);
5338
+ outline-offset: 2px;
5339
+ }
5340
+ [data-jx-popover][data-jx-popover-open]::before {
5341
+ content: "POPOVER \\00B7 SHOWN IN PLACE";
5342
+ position: absolute;
5343
+ top: 0;
5344
+ left: 0;
5345
+ z-index: 2;
5346
+ padding: 1px 5px;
5347
+ border-radius: 0 0 3px 0;
5348
+ background: color-mix(in srgb, #808080 78%, transparent);
5349
+ color: #fff;
5350
+ font: 700 9px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
5351
+ letter-spacing: 0.08em;
5352
+ pointer-events: none;
5353
+ }
5354
+ dialog[data-jx-dialog-open] {
5355
+ position: relative !important;
5356
+ inset: auto !important;
5357
+ align-self: start !important;
5358
+ flex: none !important;
5359
+ outline: 1px dashed color-mix(in srgb, #808080 55%, transparent);
5360
+ outline-offset: 2px;
5361
+ }
5362
+ dialog[data-jx-dialog-open]::before {
5363
+ content: "DIALOG \\00B7 SHOWN IN PLACE";
5364
+ position: absolute;
5365
+ top: 0;
5366
+ left: 0;
5367
+ z-index: 2;
5368
+ padding: 1px 5px;
5369
+ border-radius: 0 0 3px 0;
5370
+ background: color-mix(in srgb, #808080 78%, transparent);
5371
+ color: #fff;
5372
+ font: 700 9px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
5373
+ letter-spacing: 0.08em;
5374
+ pointer-events: none;
5375
+ }
5376
+ `;
5377
+ function syncCanvasOverlayCss(doc, mode) {
5378
+ const existing = doc.head.querySelector(`#${CANVAS_OVERLAY_STYLE_ID}`);
5379
+ if (mode === "preview") {
5380
+ existing?.remove();
5381
+ return;
5382
+ }
5383
+ if (existing) {
5384
+ return;
5385
+ }
5386
+ const style = doc.createElement("style");
5387
+ style.id = CANVAS_OVERLAY_STYLE_ID;
5388
+ style.textContent = CANVAS_OVERLAY_CSS;
5389
+ doc.head.append(style);
5390
+ }
5391
+ var DIFF_MARK_STYLE_ID = "jx-canvas-diff-css";
5392
+ var DIFF_MARK_CSS = `
5393
+ [data-jx-diff] {
5394
+ position: relative;
5395
+ border-left-width: 3px;
5396
+ border-left-color: currentColor;
5397
+ }
5398
+ [data-jx-diff]::before {
5399
+ position: absolute;
5400
+ top: 0;
5401
+ left: -3px;
5402
+ width: 3px;
5403
+ content: "";
5404
+ }
5405
+ [data-jx-diff="added"] {
5406
+ border-left-style: solid;
5407
+ border-left-color: #0a7c42;
5408
+ background: color-mix(in srgb, #0a7c42 12%, transparent);
5409
+ }
5410
+ [data-jx-diff="removed"] {
5411
+ border-left-style: double;
5412
+ border-left-color: #c9252d;
5413
+ background: color-mix(in srgb, #c9252d 12%, transparent);
5414
+ }
5415
+ [data-jx-diff="modified-before"] {
5416
+ border-left-style: dashed;
5417
+ border-left-color: #c9252d;
5418
+ background: color-mix(in srgb, #c9252d 8%, transparent);
5419
+ }
5420
+ [data-jx-diff="modified-after"] {
5421
+ border-left-style: dashed;
5422
+ border-left-color: #0a7c42;
5423
+ background: color-mix(in srgb, #0a7c42 8%, transparent);
5424
+ }
5425
+ [data-jx-diff-within] {
5426
+ border-left: 3px dotted color-mix(in srgb, #808080 60%, transparent);
5427
+ }
5428
+ @media (forced-colors: active) {
5429
+ [data-jx-diff],
5430
+ [data-jx-diff-within] {
5431
+ background: none;
5432
+ border-left-color: CanvasText;
5433
+ }
5434
+ }
5435
+ `;
5436
+ function syncDiffCss(doc, on) {
5437
+ const existing = doc.head.querySelector(`#${DIFF_MARK_STYLE_ID}`);
5438
+ if (!on) {
5439
+ existing?.remove();
5440
+ return;
5441
+ }
5442
+ if (existing) {
5443
+ return;
5444
+ }
5445
+ const style = doc.createElement("style");
5446
+ style.id = DIFF_MARK_STYLE_ID;
5447
+ style.textContent = DIFF_MARK_CSS;
5448
+ doc.head.append(style);
5449
+ }
5450
+ function applyDiffMarks(container, marks) {
5451
+ for (const stale of container.querySelectorAll("[data-jx-diff], [data-jx-diff-within]")) {
5452
+ if (stale instanceof HTMLElement) {
5453
+ delete stale.dataset.jxDiff;
5454
+ delete stale.dataset.jxDiffWithin;
5455
+ }
5456
+ }
5457
+ if (!marks?.length) {
5458
+ return;
5459
+ }
5460
+ for (const mark of marks) {
5461
+ const exact = elementForPath(container, mark.path);
5462
+ if (exact) {
5463
+ exact.dataset.jxDiff = mark.kind;
5464
+ continue;
5465
+ }
5466
+ let { path } = mark;
5467
+ while (path.length >= 2) {
5468
+ path = path.slice(0, -2);
5469
+ const ancestor = elementForPath(container, path);
5470
+ if (ancestor) {
5471
+ ancestor.dataset.jxDiffWithin = "";
5472
+ break;
5473
+ }
5474
+ }
5475
+ }
5476
+ }
4389
5477
  function syncPreviewShell(doc, mode) {
4390
5478
  doc.documentElement.toggleAttribute("data-jx-preview", mode === "preview");
4391
5479
  }
@@ -4528,6 +5616,30 @@ function applyPreviewColorScheme(doc, scheme) {
4528
5616
  delete doc.documentElement.dataset.colorScheme;
4529
5617
  }
4530
5618
  }
5619
+ function applyCanvasPopoverOpen(root, path) {
5620
+ for (const el of root.querySelectorAll("[data-jx-popover-open]")) {
5621
+ delete el.dataset.jxPopoverOpen;
5622
+ }
5623
+ if (path === null) {
5624
+ return;
5625
+ }
5626
+ const target = root.querySelector(`[data-jx-popover]${jxPathSelector(path)}`);
5627
+ if (target) {
5628
+ target.dataset.jxPopoverOpen = "";
5629
+ }
5630
+ }
5631
+ function applyCanvasDialogOpen(root, path) {
5632
+ for (const el of root.querySelectorAll("[data-jx-dialog-open]")) {
5633
+ delete el.dataset.jxDialogOpen;
5634
+ }
5635
+ if (path === null) {
5636
+ return;
5637
+ }
5638
+ const target = root.querySelector(`dialog${jxPathSelector(path)}`);
5639
+ if (target) {
5640
+ target.dataset.jxDialogOpen = "";
5641
+ }
5642
+ }
4531
5643
  function injectHead(doc, assets = null) {
4532
5644
  const head = doc.$head;
4533
5645
  if (!Array.isArray(head)) {
@@ -4570,11 +5682,11 @@ function injectHead(doc, assets = null) {
4570
5682
  function makeStamper(ctx) {
4571
5683
  const islands = [];
4572
5684
  const insideIsland = (path) => islands.some((island) => path.length > island.length && island.every((seg, i) => path[i] === seg));
4573
- return (created, path, def2) => {
5685
+ return (created, path, def) => {
4574
5686
  if (!(created instanceof HTMLElement)) {
4575
5687
  return;
4576
5688
  }
4577
- const isDefinitionRoot = path.length === 0 && def2?.tagName?.includes("-");
5689
+ const isDefinitionRoot = path.length === 0 && def?.tagName?.includes("-");
4578
5690
  if (isDefinitionRoot) {
4579
5691
  created.dataset.jxDefinitionRoot = "";
4580
5692
  }
@@ -4583,7 +5695,7 @@ function makeStamper(ctx) {
4583
5695
  created.contentEditable = "false";
4584
5696
  islands.push(path);
4585
5697
  }
4586
- const classified = classifyRenderNode(path, def2, ctx);
5698
+ const classified = classifyRenderNode(path, def, ctx);
4587
5699
  if (classified.kind === "layout") {
4588
5700
  created.dataset.jxLayoutPath = serializeJxPath(classified.layoutPath);
4589
5701
  if (classified.layoutFile) {
@@ -4634,36 +5746,32 @@ async function renderResolvedDocument(opts) {
4634
5746
  setSkipAutoRequests(opts.mode !== "preview" && !opts.allowAutoRequests);
4635
5747
  setCanvasViewportTranspose(true);
4636
5748
  setCanvasDelinkAnchors(opts.mode !== "preview");
5749
+ setCanvasDelinkPopovers(opts.mode !== "preview");
5750
+ setCanvasDelinkCommands(opts.mode !== "preview");
4637
5751
  setStampPropBindings(opts.mode === "design" || opts.mode === "edit");
4638
5752
  applySiteStyle(opts.siteStyle, opts.doc.$media ?? {});
4639
5753
  injectHead(opts.doc, assets);
4640
5754
  syncEditModeCss(opts.container.ownerDocument, opts.mode);
5755
+ syncCanvasOverlayCss(opts.container.ownerDocument, opts.mode);
4641
5756
  syncPreviewShell(opts.container.ownerDocument, opts.mode);
4642
5757
  syncStylebookCss(opts.container.ownerDocument, opts.mode);
5758
+ syncDiffCss(opts.container.ownerDocument, Boolean(opts.diffMarks?.length));
4643
5759
  setRootMedia(opts.doc.$media ?? {});
4644
5760
  await registerElements2(opts.doc, opts.docBase);
4645
5761
  const $defs = await buildScope(opts.doc, {}, opts.docBase);
4646
5762
  const onNodeCreated = makeStamper(opts.mapperCtx);
4647
5763
  const { result: el, stop } = runScoped(() => renderNode(opts.doc, $defs, { _path: [], onNodeCreated }));
4648
5764
  opts.container.replaceChildren(el);
5765
+ applyCanvasPopoverOpen(opts.container, opts.popoverOpen ?? null);
5766
+ applyCanvasDialogOpen(opts.container, opts.dialogOpen ?? null);
4649
5767
  syncEditableRoot(opts.container, opts.mode);
5768
+ applyDiffMarks(opts.container, opts.diffMarks ?? null);
4650
5769
  return {
4651
5770
  ctx: { defs: $defs, docBase: opts.docBase, mapperCtx: opts.mapperCtx, mode: opts.mode },
4652
5771
  dispose: stop
4653
5772
  };
4654
5773
  }
4655
5774
 
4656
- // src/utils/geometry.ts
4657
- function rectOf(el) {
4658
- return el.getBoundingClientRect();
4659
- }
4660
- function rectOfRange(r) {
4661
- return r.getBoundingClientRect();
4662
- }
4663
- function elementAtPoint(x, y, root = document) {
4664
- return root.elementFromPoint(x, y);
4665
- }
4666
-
4667
5775
  // src/state.ts
4668
5776
  function getNodeAtPath(doc, path) {
4669
5777
  let node = doc;
@@ -4811,41 +5919,35 @@ var elements_meta_default = {
4811
5919
  {
4812
5920
  tag: "strong",
4813
5921
  label: "Bold",
4814
- icon: "sp-icon-text-bold",
4815
5922
  command: "bold"
4816
5923
  },
4817
5924
  {
4818
5925
  tag: "em",
4819
5926
  label: "Italic",
4820
- icon: "sp-icon-text-italic",
4821
5927
  command: "italic"
4822
5928
  },
4823
5929
  {
4824
5930
  tag: "u",
4825
5931
  label: "Underline",
4826
- icon: "sp-icon-text-underline",
4827
5932
  command: "underline"
4828
5933
  },
4829
5934
  {
4830
5935
  tag: "del",
4831
5936
  label: "Strikethrough",
4832
- icon: "sp-icon-text-strikethrough",
4833
5937
  command: "strikethrough"
4834
5938
  },
4835
5939
  {
4836
5940
  tag: "sup",
4837
5941
  label: "Superscript",
4838
- icon: "sp-icon-text-superscript",
4839
5942
  command: "superscript"
4840
5943
  },
4841
5944
  {
4842
5945
  tag: "sub",
4843
5946
  label: "Subscript",
4844
- icon: "sp-icon-text-subscript",
4845
5947
  command: "subscript"
4846
5948
  },
4847
- { tag: "code", label: "Code", icon: "sp-icon-code", command: "code" },
4848
- { tag: "a", label: "Link", icon: "sp-icon-link", command: "link" }
5949
+ { tag: "code", label: "Code", command: "code" },
5950
+ { tag: "a", label: "Link", command: "link" }
4849
5951
  ]
4850
5952
  },
4851
5953
  h1: {
@@ -4855,17 +5957,15 @@ var elements_meta_default = {
4855
5957
  {
4856
5958
  tag: "strong",
4857
5959
  label: "Bold",
4858
- icon: "sp-icon-text-bold",
4859
5960
  command: "bold"
4860
5961
  },
4861
5962
  {
4862
5963
  tag: "em",
4863
5964
  label: "Italic",
4864
- icon: "sp-icon-text-italic",
4865
5965
  command: "italic"
4866
5966
  },
4867
- { tag: "code", label: "Code", icon: "sp-icon-code", command: "code" },
4868
- { tag: "a", label: "Link", icon: "sp-icon-link", command: "link" }
5967
+ { tag: "code", label: "Code", command: "code" },
5968
+ { tag: "a", label: "Link", command: "link" }
4869
5969
  ]
4870
5970
  },
4871
5971
  h2: {
@@ -5088,16 +6188,14 @@ var elements_meta_default = {
5088
6188
  {
5089
6189
  tag: "strong",
5090
6190
  label: "Bold",
5091
- icon: "sp-icon-text-bold",
5092
6191
  command: "bold"
5093
6192
  },
5094
6193
  {
5095
6194
  tag: "em",
5096
6195
  label: "Italic",
5097
- icon: "sp-icon-text-italic",
5098
6196
  command: "italic"
5099
6197
  },
5100
- { tag: "code", label: "Code", icon: "sp-icon-code", command: "code" }
6198
+ { tag: "code", label: "Code", command: "code" }
5101
6199
  ]
5102
6200
  },
5103
6201
  span: {
@@ -5526,7 +6624,7 @@ function findTemplateExpressions(text) {
5526
6624
 
5527
6625
  // src/editor/editable-tags.ts
5528
6626
  var EXCLUDED = new Set(["pre"]);
5529
- var BUILTIN_EDITABLE_TAGS = new Set(Object.entries(elements_meta_default.$defs).filter(([tag, def2]) => !EXCLUDED.has(tag) && (def2.$inlineChildren?.length ?? 0) > 0).map(([tag]) => tag));
6627
+ var BUILTIN_EDITABLE_TAGS = new Set(Object.entries(elements_meta_default.$defs).filter(([tag, def]) => !EXCLUDED.has(tag) && (def.$inlineChildren?.length ?? 0) > 0).map(([tag]) => tag));
5530
6628
  function isEditableTag(tag, verdicts) {
5531
6629
  const declared = verdicts?.[tag.toLowerCase()];
5532
6630
  return declared ?? BUILTIN_EDITABLE_TAGS.has(tag.toLowerCase());
@@ -5978,18 +7076,64 @@ function nearestHit(target) {
5978
7076
  }
5979
7077
  return measureHit(el, el.dataset.jxPath);
5980
7078
  }
7079
+ function isRendered(el) {
7080
+ const check = el.checkVisibility;
7081
+ return typeof check === "function" ? check.call(el, { checkVisibilityCSS: true }) : true;
7082
+ }
5981
7083
  function measureHits(paths, doc = document) {
5982
- const out = [];
7084
+ const hits = [];
7085
+ const hidden = [];
5983
7086
  for (const path of paths) {
5984
- const serialized = serializeJxPath(path);
5985
- const esc = serialized.replaceAll("\\", String.raw`\\`).replaceAll("'", String.raw`\'`);
5986
- const el = doc.querySelector(`[data-jx-path='${esc}']`);
5987
- if (el) {
7087
+ const el = doc.querySelector(jxPathSelector(serializeJxPath(path)));
7088
+ if (!el) {
7089
+ continue;
7090
+ }
7091
+ if (isRendered(el)) {
5988
7092
  const r = rectOf(el);
5989
- out.push({ path, rect: { height: r.height, width: r.width, x: r.x, y: r.y } });
7093
+ hits.push({ path, rect: { height: r.height, width: r.width, x: r.x, y: r.y } });
7094
+ } else {
7095
+ hidden.push(path);
5990
7096
  }
5991
7097
  }
5992
- return out;
7098
+ return { hidden, hits };
7099
+ }
7100
+ var INVOKER_ACTIONS = new Set(["toggle", "show", "hide"]);
7101
+ function postPopoverInvoke(target, channel) {
7102
+ if (!(target instanceof Element)) {
7103
+ return;
7104
+ }
7105
+ const invoker = target.closest("[popovertarget]");
7106
+ const id = invoker?.getAttribute("popovertarget");
7107
+ if (!invoker || !id) {
7108
+ return;
7109
+ }
7110
+ const panels = invoker.ownerDocument.querySelectorAll("[data-jx-popover]");
7111
+ const panel = [...panels].find((el) => el.id === id);
7112
+ const serialized = panel?.dataset.jxPath;
7113
+ if (!serialized) {
7114
+ return;
7115
+ }
7116
+ const raw = invoker.getAttribute("popovertargetaction") ?? "toggle";
7117
+ const action = INVOKER_ACTIONS.has(raw) ? raw : "toggle";
7118
+ channel.post({ action, kind: "popoverTargetClick", targetPath: parseJxPath(serialized) });
7119
+ }
7120
+ function postCommandInvoke(target, channel) {
7121
+ if (!(target instanceof Element)) {
7122
+ return;
7123
+ }
7124
+ const invoker = target.closest("[data-jx-commandfor]");
7125
+ const id = invoker?.dataset["jxCommandfor"];
7126
+ const command = invoker?.getAttribute("command")?.trim().toLowerCase() ?? "";
7127
+ if (!invoker || !id || !command) {
7128
+ return;
7129
+ }
7130
+ const overlays = invoker.ownerDocument.querySelectorAll("[data-jx-popover], dialog[data-jx-path]");
7131
+ const overlay = [...overlays].find((el) => el.id === id);
7132
+ const serialized = overlay?.dataset.jxPath;
7133
+ if (!serialized) {
7134
+ return;
7135
+ }
7136
+ channel.post({ command, kind: "commandTargetClick", targetPath: parseJxPath(serialized) });
5993
7137
  }
5994
7138
  function startInteraction(channel, doc = document, deps) {
5995
7139
  let lastHoverKey = null;
@@ -6020,6 +7164,8 @@ function startInteraction(channel, doc = document, deps) {
6020
7164
  kind: "hit"
6021
7165
  });
6022
7166
  }
7167
+ postPopoverInvoke(e.target, channel);
7168
+ postCommandInvoke(e.target, channel);
6023
7169
  };
6024
7170
  const reportHover = (el) => {
6025
7171
  if (isPreview()) {
@@ -6251,112 +7397,6 @@ function scrollDirection(y, viewportH, band = AUTO_SCROLL_BAND) {
6251
7397
  return 0;
6252
7398
  }
6253
7399
 
6254
- // src/canvas/iframe-position.ts
6255
- function isIslandBoundary(el) {
6256
- if (el.dataset.jxDefinitionRoot !== undefined) {
6257
- return false;
6258
- }
6259
- return el.getAttribute("contenteditable") === "false" || el.tagName.includes("-");
6260
- }
6261
- function activeBlockAt(node, isEditable) {
6262
- let el = node instanceof Element ? node : node?.parentElement ?? null;
6263
- while (el) {
6264
- if (el instanceof HTMLElement) {
6265
- if (el.dataset.jxPath && isEditable(el)) {
6266
- return { el, path: parseJxPath(el.dataset.jxPath) };
6267
- }
6268
- if (isIslandBoundary(el)) {
6269
- return null;
6270
- }
6271
- }
6272
- el = el.parentElement;
6273
- }
6274
- return null;
6275
- }
6276
- function elementForPath(container, path) {
6277
- const serialized = serializeJxPath(path);
6278
- const esc = serialized.replaceAll("\\", String.raw`\\`).replaceAll("'", String.raw`\'`);
6279
- const el = container.querySelector(`[data-jx-path='${esc}']`);
6280
- return el instanceof HTMLElement ? el : null;
6281
- }
6282
- function blockTextLength(block) {
6283
- return block.textContent?.length ?? 0;
6284
- }
6285
- function offsetOf(block, node, offset) {
6286
- if (!block.contains(node)) {
6287
- return null;
6288
- }
6289
- const range = block.ownerDocument.createRange();
6290
- range.setStart(block, 0);
6291
- try {
6292
- range.setEnd(node, offset);
6293
- } catch {
6294
- return null;
6295
- }
6296
- return range.toString().length;
6297
- }
6298
- function domPositionAt(block, offset) {
6299
- const target = Math.max(0, Math.min(offset, blockTextLength(block)));
6300
- const walker = block.ownerDocument.createTreeWalker(block, NodeFilter.SHOW_TEXT);
6301
- let seen = 0;
6302
- let last = null;
6303
- let current = walker.nextNode();
6304
- while (current) {
6305
- const len = current.length;
6306
- if (seen + len >= target) {
6307
- return { node: current, offset: target - seen };
6308
- }
6309
- seen += len;
6310
- last = current;
6311
- current = walker.nextNode();
6312
- }
6313
- return last ? { node: last, offset: last.length } : { node: block, offset: 0 };
6314
- }
6315
- function toDocPos(node, offset, isEditable) {
6316
- const block = activeBlockAt(node, isEditable);
6317
- if (!block || !node) {
6318
- return null;
6319
- }
6320
- const charOffset = offsetOf(block.el, node, offset);
6321
- return charOffset === null ? null : { offset: charOffset, path: block.path };
6322
- }
6323
- function toDomPosition(container, pos) {
6324
- const el = elementForPath(container, pos.path);
6325
- return el ? domPositionAt(el, pos.offset) : null;
6326
- }
6327
- function isAtBlockStart(pos) {
6328
- return pos.offset <= 0;
6329
- }
6330
- function samePath(a, b) {
6331
- return serializeJxPath(a.path) === serializeJxPath(b.path);
6332
- }
6333
- function blocksInOrder(container, isEditable) {
6334
- const out = [];
6335
- for (const el of container.querySelectorAll("[data-jx-path]")) {
6336
- if (isEditable(el) && !sealedInIsland(el, container)) {
6337
- out.push(el);
6338
- }
6339
- }
6340
- return out;
6341
- }
6342
- function sealedInIsland(el, container) {
6343
- let cur = el.parentElement;
6344
- while (cur && cur !== container) {
6345
- if (isIslandBoundary(cur)) {
6346
- return true;
6347
- }
6348
- cur = cur.parentElement;
6349
- }
6350
- return false;
6351
- }
6352
- function adjacentBlock(container, path, direction, isEditable) {
6353
- const blocks = blocksInOrder(container, isEditable);
6354
- const key = serializeJxPath(path);
6355
- const index = blocks.findIndex((el) => el.dataset.jxPath === key);
6356
- const neighbour = index === -1 ? undefined : blocks[index + direction];
6357
- return neighbour ? { el: neighbour, path: parseJxPath(neighbour.dataset.jxPath) } : null;
6358
- }
6359
-
6360
7400
  // src/canvas/editable-actions.ts
6361
7401
  var DELETE_BACKWARD = new Set([
6362
7402
  "deleteContentBackward",
@@ -6465,7 +7505,7 @@ function restoreDocSelection(container, range) {
6465
7505
  }
6466
7506
  function startEditableRoot(container, deps) {
6467
7507
  const doc = container.ownerDocument;
6468
- let activeEl2 = null;
7508
+ let activeEl = null;
6469
7509
  let activeKey = null;
6470
7510
  const editingAllowed = () => {
6471
7511
  const mode = deps.getMode?.();
@@ -6480,7 +7520,7 @@ function startEditableRoot(container, deps) {
6480
7520
  };
6481
7521
  const commitTick = () => {
6482
7522
  commitTimer = 0;
6483
- if (!activeEl2 || !deps.onCommitTick) {
7523
+ if (!activeEl || !deps.onCommitTick) {
6484
7524
  return;
6485
7525
  }
6486
7526
  const caret = captureDocSelection(container, deps.isEditableBlock);
@@ -6491,7 +7531,7 @@ function startEditableRoot(container, deps) {
6491
7531
  };
6492
7532
  let composing = false;
6493
7533
  const scheduleCommitTick = () => {
6494
- if (!deps.onCommitTick || !activeEl2 || composing) {
7534
+ if (!deps.onCommitTick || !activeEl || composing) {
6495
7535
  return;
6496
7536
  }
6497
7537
  cancelCommitTick();
@@ -6507,15 +7547,15 @@ function startEditableRoot(container, deps) {
6507
7547
  };
6508
7548
  const forget = () => {
6509
7549
  cancelCommitTick();
6510
- activeEl2 = null;
7550
+ activeEl = null;
6511
7551
  activeKey = null;
6512
7552
  };
6513
7553
  const deactivate = () => {
6514
- if (!activeEl2) {
7554
+ if (!activeEl) {
6515
7555
  return;
6516
7556
  }
6517
7557
  cancelCommitTick();
6518
- activeEl2 = null;
7558
+ activeEl = null;
6519
7559
  activeKey = null;
6520
7560
  deps.onDeactivate();
6521
7561
  };
@@ -6535,7 +7575,7 @@ function startEditableRoot(container, deps) {
6535
7575
  }
6536
7576
  const block = activeBlockAt(focus, deps.isEditableBlock);
6537
7577
  if (!block) {
6538
- if (activeEl2?.contains(focus)) {
7578
+ if (activeEl?.contains(focus)) {
6539
7579
  deps.onSelectionChange?.();
6540
7580
  return;
6541
7581
  }
@@ -6548,7 +7588,7 @@ function startEditableRoot(container, deps) {
6548
7588
  return;
6549
7589
  }
6550
7590
  deactivate();
6551
- activeEl2 = block.el;
7591
+ activeEl = block.el;
6552
7592
  activeKey = key;
6553
7593
  deps.onActivate(block.el, block.path);
6554
7594
  };
@@ -6584,7 +7624,7 @@ function startEditableRoot(container, deps) {
6584
7624
  atBlockStart: resolved ? isAtBlockStart(resolved.from) : false,
6585
7625
  data: e.data ?? "",
6586
7626
  from: resolved?.from ?? null,
6587
- inPropHost: activeEl2 !== null && activeKey === null,
7627
+ inPropHost: activeEl !== null && activeKey === null,
6588
7628
  inputType: e.inputType,
6589
7629
  to: resolved?.to ?? null
6590
7630
  });
@@ -6627,10 +7667,10 @@ function startEditableRoot(container, deps) {
6627
7667
  let el = e.target instanceof Element ? e.target : null;
6628
7668
  while (el && el !== container) {
6629
7669
  if (el.dataset?.jxBoundProp) {
6630
- if (el !== activeEl2) {
7670
+ if (el !== activeEl) {
6631
7671
  deactivate();
6632
7672
  if (deps.onPropActivate(el)) {
6633
- activeEl2 = el;
7673
+ activeEl = el;
6634
7674
  activeKey = null;
6635
7675
  }
6636
7676
  }
@@ -6891,8 +7931,8 @@ function prepareForEditMode(node) {
6891
7931
  propsOut[pk] = templateToEditDisplay(pv);
6892
7932
  }
6893
7933
  } else if (pv && typeof pv === "object" && pv.$ref) {
6894
- const ref2 = pv.$ref;
6895
- const label = ref2.startsWith("#/state/") ? ref2.slice(8) : ref2;
7934
+ const ref = pv.$ref;
7935
+ const label = ref.startsWith("#/state/") ? ref.slice(8) : ref;
6896
7936
  propsOut[pk] = `{${label}}`;
6897
7937
  } else {
6898
7938
  propsOut[pk] = pv;
@@ -6943,8 +7983,8 @@ function prepareForEditMode(node) {
6943
7983
  const isUrlAttr = ak === "href" || ak === "action";
6944
7984
  processed[ak] = isUrlAttr ? "" : templateToEditDisplay(av);
6945
7985
  } else if (av && typeof av === "object" && av.$ref) {
6946
- const ref2 = av.$ref;
6947
- const label = ref2.startsWith("#/state/") ? ref2.slice(8) : ref2;
7986
+ const ref = av.$ref;
7987
+ const label = ref.startsWith("#/state/") ? ref.slice(8) : ref;
6948
7988
  processed[ak] = `{${label}}`;
6949
7989
  } else {
6950
7990
  processed[ak] = av;
@@ -6955,7 +7995,9 @@ function prepareForEditMode(node) {
6955
7995
  if (v && typeof v === "object") {
6956
7996
  const s = {};
6957
7997
  for (const [sk, sv] of Object.entries(v)) {
6958
- s[sk] = typeof sv === "string" && sv.includes("${") ? "" : sv;
7998
+ if (typeof sv !== "string" || !sv.includes("${")) {
7999
+ s[sk] = sv;
8000
+ }
6959
8001
  }
6960
8002
  out.style = s;
6961
8003
  } else {
@@ -6971,8 +8013,8 @@ function prepareForEditMode(node) {
6971
8013
  out[k] = isUrlAttr ? "" : templateToEditDisplay(v);
6972
8014
  }
6973
8015
  } else if (v && typeof v === "object" && v.$ref) {
6974
- const ref2 = v.$ref;
6975
- const label = ref2.startsWith("#/state/") ? ref2.slice(8) : ref2;
8016
+ const ref = v.$ref;
8017
+ const label = ref.startsWith("#/state/") ? ref.slice(8) : ref;
6976
8018
  const isMediaSrc = (k === "src" || k === "poster") && mediaTags.has(obj.tagName || "");
6977
8019
  if (isMediaSrc) {
6978
8020
  needsMediaPlaceholder = true;
@@ -7700,8 +8742,8 @@ function renderSubtreeIframe(shadowDoc, docPath, ctx) {
7700
8742
  if (node === undefined) {
7701
8743
  throw new Error(`iframe-patch-node-not-found:${docPath.join("/")}`);
7702
8744
  }
7703
- const def2 = typeof node === "string" ? node : prepareForEditMode(stripEventHandlers(node));
7704
- const { result: rendered, stop } = runScoped(() => renderNode(def2, ctx.defs, {
8745
+ const def = typeof node === "string" ? node : prepareForEditMode(stripEventHandlers(node));
8746
+ const { result: rendered, stop } = runScoped(() => renderNode(def, ctx.defs, {
7705
8747
  _path: docPathToRenderPath(docPath, ctx),
7706
8748
  onNodeCreated: makeStamper(ctx.mapperCtx)
7707
8749
  }));
@@ -7717,11 +8759,7 @@ function disposeSubtree(el) {
7717
8759
  if (!(t instanceof HTMLElement)) {
7718
8760
  continue;
7719
8761
  }
7720
- const tag = elementStyleTags.get(t);
7721
- if (tag) {
7722
- tag.remove();
7723
- elementStyleTags.delete(t);
7724
- }
8762
+ releaseElementStyles(t);
7725
8763
  const stop = elScope.get(t);
7726
8764
  if (stop) {
7727
8765
  stop();
@@ -7869,9 +8907,9 @@ function syncPlaceholderClass(el, node) {
7869
8907
  el.classList.add(placeholder);
7870
8908
  }
7871
8909
  }
7872
- function insertAt(parentEl, node, ref2) {
7873
- if (ref2) {
7874
- ref2.before(node);
8910
+ function insertAt(parentEl, node, ref) {
8911
+ if (ref) {
8912
+ ref.before(node);
7875
8913
  } else {
7876
8914
  parentEl.append(node);
7877
8915
  }
@@ -7945,7 +8983,10 @@ function editModeStyle(style) {
7945
8983
  }
7946
8984
  const out = {};
7947
8985
  for (const [k, v] of Object.entries(style)) {
7948
- out[k] = typeof v === "string" && v.includes("${") ? "" : v;
8986
+ if (typeof v === "string" && v.includes("${")) {
8987
+ continue;
8988
+ }
8989
+ out[k] = v;
7949
8990
  }
7950
8991
  return out;
7951
8992
  }
@@ -7958,8 +8999,8 @@ function textDisplayValue(node) {
7958
8999
  return v.includes("${") ? templateToEditDisplay(v) : v;
7959
9000
  }
7960
9001
  if (typeof v === "object" && v.$ref) {
7961
- const ref2 = String(v.$ref);
7962
- const label = ref2.startsWith("#/state/") ? ref2.slice(8) : ref2;
9002
+ const ref = String(v.$ref);
9003
+ const label = ref.startsWith("#/state/") ? ref.slice(8) : ref;
7963
9004
  return `{${label}}`;
7964
9005
  }
7965
9006
  return String(v);
@@ -8094,6 +9135,32 @@ function serializeDataScope(defs) {
8094
9135
  return out;
8095
9136
  }
8096
9137
 
9138
+ // ../ui/src/loaders.ts
9139
+ var KIT_LOADERS = {
9140
+ "jx-ui:/behaviors/color-area.ts": () => (__preload("v17df7b8"), import("./chunks/color-area-v17df7b8.js")),
9141
+ "jx-ui:/behaviors/color-field.ts": () => (__preload("anwybnkn"), import("./chunks/color-field-anwybnkn.js")),
9142
+ "jx-ui:/behaviors/color-slider.ts": () => (__preload("44ez96fc"), import("./chunks/color-slider-44ez96fc.js")),
9143
+ "jx-ui:/behaviors/combobox.ts": () => (__preload("5e7jev23"), import("./chunks/combobox-5e7jev23.js")),
9144
+ "jx-ui:/behaviors/dialog.ts": () => (__preload("s890b918"), import("./chunks/dialog-s890b918.js")),
9145
+ "jx-ui:/behaviors/listbox.ts": () => (__preload("6v2ac08j"), import("./chunks/listbox-6v2ac08j.js")),
9146
+ "jx-ui:/behaviors/menu.ts": () => (__preload("q99sy9rf"), import("./chunks/menu-q99sy9rf.js")),
9147
+ "jx-ui:/behaviors/number-field.ts": () => (__preload("5cndyft8"), import("./chunks/number-field-5cndyft8.js")),
9148
+ "jx-ui:/behaviors/action-group.ts": () => (__preload("sp6tna8v"), import("./chunks/action-group-sp6tna8v.js")),
9149
+ "jx-ui:/behaviors/popover.ts": () => (__preload("47z3ytva"), import("./chunks/popover-47z3ytva.js")),
9150
+ "jx-ui:/behaviors/select.ts": () => (__preload("2r16ez41"), import("./chunks/select-2r16ez41.js")),
9151
+ "jx-ui:/behaviors/split.ts": () => (__preload("g7nm1rgb"), import("./chunks/split-g7nm1rgb.js")),
9152
+ "jx-ui:/behaviors/swatch-group.ts": () => (__preload("t0n6h2rn"), import("./chunks/swatch-group-t0n6h2rn.js")),
9153
+ "jx-ui:/behaviors/tabs.ts": () => (__preload("wbp1cdws"), import("./chunks/tabs-wbp1cdws.js")),
9154
+ "jx-ui:/behaviors/toolbar.ts": () => (__preload("xbh5bhtr"), import("./chunks/toolbar-xbh5bhtr.js")),
9155
+ "jx-ui:/behaviors/tree.ts": () => (__preload("a73p0pqm"), import("./chunks/tree-a73p0pqm.js")),
9156
+ "jx-ui:/behaviors/tooltip.ts": () => (__preload("eptb614w"), import("./chunks/tooltip-eptb614w.js")),
9157
+ "jx-ui:/behaviors/textfield.ts": () => (__preload("abk6qyee"), import("./chunks/textfield-abk6qyee.js")),
9158
+ "jx-ui:/behaviors/toast.ts": () => (__preload("780pvfbv"), import("./chunks/toast-780pvfbv.js")),
9159
+ "jx-ui:/behaviors/toast-host.ts": () => (__preload("3sqv46sn"), import("./chunks/toast-host-3sqv46sn.js")),
9160
+ "jx-ui:/color.ts": () => (__preload("xgg3kfw7"), import("./chunks/color-xgg3kfw7.js")),
9161
+ "jx-ui:/icons.ts": () => (__preload("yy10wk9r"), import("./chunks/icons-yy10wk9r.js"))
9162
+ };
9163
+
8097
9164
  // src/services/bundle-base.ts
8098
9165
  var base;
8099
9166
  function setBundleBase(entryUrl) {
@@ -8102,6 +9169,9 @@ function setBundleBase(entryUrl) {
8102
9169
 
8103
9170
  // src/canvas/iframe-entry.ts
8104
9171
  setBundleBase(import.meta.url);
9172
+ for (const [specifier, load] of Object.entries(KIT_LOADERS)) {
9173
+ preloadModule(specifier, load);
9174
+ }
8105
9175
  function previewAt(cursor, src, shadowDoc, doc) {
8106
9176
  const targetEl = resolveDropTarget(cursor.x, cursor.y, doc);
8107
9177
  if (!targetEl) {
@@ -8147,8 +9217,8 @@ function layoutHitFor(target) {
8147
9217
  }
8148
9218
  var IN_PLACE_KEYS = new Set(["style", "textContent"]);
8149
9219
  function patchDisturbsActiveEdit(forwardOps) {
8150
- const activePath2 = getActivePath();
8151
- if (!activePath2) {
9220
+ const activePath = getActivePath();
9221
+ if (!activePath) {
8152
9222
  return false;
8153
9223
  }
8154
9224
  for (const op of forwardOps) {
@@ -8160,14 +9230,14 @@ function patchDisturbsActiveEdit(forwardOps) {
8160
9230
  affected = op.path;
8161
9231
  } else if (op.op === "move-child") {
8162
9232
  affected = op.fromParentPath;
8163
- if (isAncestor(affected, activePath2) || isAncestor(op.toParentPath, activePath2)) {
9233
+ if (isAncestor(affected, activePath) || isAncestor(op.toParentPath, activePath)) {
8164
9234
  return true;
8165
9235
  }
8166
9236
  continue;
8167
9237
  } else {
8168
9238
  affected = op.parentPath;
8169
9239
  }
8170
- if (isAncestor(affected, activePath2)) {
9240
+ if (isAncestor(affected, activePath)) {
8171
9241
  return true;
8172
9242
  }
8173
9243
  }
@@ -8184,6 +9254,8 @@ function startCanvasIframe(opts) {
8184
9254
  let shadowDoc = null;
8185
9255
  let renderedGen = -1;
8186
9256
  let currentMode = "design";
9257
+ let popoverOpen = null;
9258
+ let dialogOpen = null;
8187
9259
  let forwardTable = NO_TABLE;
8188
9260
  let renderCtx = null;
8189
9261
  let dragSrc = null;
@@ -8264,8 +9336,18 @@ function startCanvasIframe(opts) {
8264
9336
  const stopImageRetry = installCanvasImageRetry(container);
8265
9337
  const MAX_CANVAS_HEIGHT = 30000;
8266
9338
  let lastPostedHeight = -1;
9339
+ function openPopoverBottom() {
9340
+ const panels = container.querySelectorAll("[data-jx-popover][data-jx-popover-open], dialog[data-jx-dialog-open]");
9341
+ const root = rectOf(container);
9342
+ let bottom = 0;
9343
+ for (const panel of panels) {
9344
+ bottom = Math.max(bottom, rectOf(panel).bottom - root.top);
9345
+ }
9346
+ return bottom;
9347
+ }
8267
9348
  function postContentHeight() {
8268
- const measured = Math.min(container.scrollHeight, MAX_CANVAS_HEIGHT);
9349
+ const content = Math.max(container.scrollHeight, openPopoverBottom());
9350
+ const measured = Math.min(content, MAX_CANVAS_HEIGHT);
8269
9351
  if (measured > 0 && Math.abs(measured - lastPostedHeight) >= 1) {
8270
9352
  lastPostedHeight = measured;
8271
9353
  const root = container.firstElementChild;
@@ -8313,6 +9395,7 @@ function startCanvasIframe(opts) {
8313
9395
  const quiet = sample.fonts && sample.animations === 0 && sample.images === 0;
8314
9396
  quietFrames = quiet ? changed ? 1 : quietFrames + 1 : 0;
8315
9397
  if (quietFrames >= IDLE_QUIET_FRAMES) {
9398
+ postContentHeight();
8316
9399
  return;
8317
9400
  }
8318
9401
  if (Date.now() >= idleDeadline) {
@@ -8436,11 +9519,8 @@ function startCanvasIframe(opts) {
8436
9519
  container.ownerDocument.addEventListener("drop", onNativeDrop, true);
8437
9520
  const off = channel.onMessage((msg) => {
8438
9521
  if (msg.kind === "measure") {
8439
- channel.post({
8440
- hits: measureHits(msg.paths, container.ownerDocument),
8441
- kind: "geometry",
8442
- reqId: msg.reqId
8443
- });
9522
+ const { hidden, hits } = measureHits(msg.paths, container.ownerDocument);
9523
+ channel.post({ hidden, hits, kind: "geometry", reqId: msg.reqId });
8444
9524
  return;
8445
9525
  }
8446
9526
  if (msg.kind === "evalExpr") {
@@ -8449,13 +9529,13 @@ function startCanvasIframe(opts) {
8449
9529
  return;
8450
9530
  }
8451
9531
  if (msg.kind === "patch") {
8452
- const { gen: gen2 } = msg;
8453
- if (gen2 < renderedGen) {
8454
- channel.post({ gen: gen2, kind: "patchError", message: "patch-behind-render" });
9532
+ const { gen } = msg;
9533
+ if (gen < renderedGen) {
9534
+ channel.post({ gen, kind: "patchError", message: "patch-behind-render" });
8455
9535
  return;
8456
9536
  }
8457
- if (gen2 > renderedGen || !shadowDoc || !renderCtx) {
8458
- channel.post({ gen: gen2, kind: "patchError", message: "patch-ahead-of-render" });
9537
+ if (gen > renderedGen || !shadowDoc || !renderCtx) {
9538
+ channel.post({ gen, kind: "patchError", message: "patch-ahead-of-render" });
8459
9539
  return;
8460
9540
  }
8461
9541
  const echoed = new Set((msg.echoPaths ?? []).map((p) => serializeJxPath(p)));
@@ -8467,14 +9547,16 @@ function startCanvasIframe(opts) {
8467
9547
  }
8468
9548
  try {
8469
9549
  applyIframePatch(shadowDoc, msg.forwardOps, container, renderCtx, msg.echoPaths);
9550
+ applyCanvasPopoverOpen(container, popoverOpen);
9551
+ applyCanvasDialogOpen(container, dialogOpen);
8470
9552
  if (caret) {
8471
9553
  restoreDocSelection(container, caret);
8472
9554
  }
8473
- channel.post({ gen: gen2, kind: "patchComplete" });
9555
+ channel.post({ gen, kind: "patchComplete" });
8474
9556
  armIdleWatch();
8475
9557
  } catch (error) {
8476
9558
  channel.post({
8477
- gen: gen2,
9559
+ gen,
8478
9560
  kind: "patchError",
8479
9561
  message: String(error?.message ?? error)
8480
9562
  });
@@ -8534,6 +9616,29 @@ function startCanvasIframe(opts) {
8534
9616
  applyPreviewColorScheme(container.ownerDocument, msg.scheme);
8535
9617
  return;
8536
9618
  }
9619
+ if (msg.kind === "setPopoverOpen") {
9620
+ if (currentMode === "preview") {
9621
+ return;
9622
+ }
9623
+ popoverOpen = msg.path === null ? null : serializeJxPath(msg.path);
9624
+ applyCanvasPopoverOpen(container, popoverOpen);
9625
+ applyCanvasDialogOpen(container, dialogOpen);
9626
+ postContentHeight();
9627
+ return;
9628
+ }
9629
+ if (msg.kind === "setDialogOpen") {
9630
+ if (currentMode === "preview") {
9631
+ return;
9632
+ }
9633
+ dialogOpen = msg.path === null ? null : serializeJxPath(msg.path);
9634
+ applyCanvasDialogOpen(container, dialogOpen);
9635
+ postContentHeight();
9636
+ return;
9637
+ }
9638
+ if (msg.kind === "redefineElement") {
9639
+ redefineElement(msg.doc, msg.base);
9640
+ return;
9641
+ }
8537
9642
  if (msg.kind === "setLocale") {
8538
9643
  const root = container.ownerDocument.documentElement;
8539
9644
  if (msg.locale === null) {
@@ -8566,6 +9671,7 @@ function startCanvasIframe(opts) {
8566
9671
  stopDataScopeWatch?.();
8567
9672
  stopDataScopeWatch = null;
8568
9673
  handle?.dispose();
9674
+ resetDocumentStyles(container.ownerDocument);
8569
9675
  handle = await renderResolvedDocument({
8570
9676
  assets: msg.assets ?? null,
8571
9677
  container,
@@ -8578,11 +9684,18 @@ function startCanvasIframe(opts) {
8578
9684
  pageContentOffset: mapperCtx.pageContentOffset,
8579
9685
  pageContentPrefix: mapperCtx.pageContentPrefix
8580
9686
  },
9687
+ diffMarks: msg.diffMarks ?? null,
8581
9688
  mode: msg.mode,
9689
+ popoverOpen: msg.popoverOpen ? serializeJxPath(msg.popoverOpen) : null,
9690
+ dialogOpen: msg.dialogOpen ? serializeJxPath(msg.dialogOpen) : null,
8582
9691
  siteStyle: msg.siteStyle,
8583
9692
  ...msg.allowAutoRequests ? { allowAutoRequests: true } : {}
8584
9693
  });
8585
9694
  if (gen === latestGen) {
9695
+ popoverOpen = msg.popoverOpen ? serializeJxPath(msg.popoverOpen) : null;
9696
+ dialogOpen = msg.dialogOpen ? serializeJxPath(msg.dialogOpen) : null;
9697
+ applyCanvasPopoverOpen(container, popoverOpen);
9698
+ applyCanvasDialogOpen(container, dialogOpen);
8586
9699
  shadowDoc = rawDoc;
8587
9700
  renderCtx = handle.ctx;
8588
9701
  renderedGen = gen;
@@ -8665,5 +9778,5 @@ export {
8665
9778
  startCanvasIframe
8666
9779
  };
8667
9780
 
8668
- //# debugId=BF2F5E4A39B13F1864756E2164756E21
9781
+ //# debugId=54293E8C2DCDA4AF64756E2164756E21
8669
9782
  //# sourceMappingURL=iframe-entry.js.map