@jxsuite/studio 4.0.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 (613) 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-xp8vnwma.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-nj44jpzj.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-rws7k4br.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-hbtp0eh1.js → studio-25hkdrkw.js} +356 -85
  62. package/dist/chunks/studio-26d7myd1.js +258 -0
  63. package/dist/chunks/{studio-p8j86wag.js → studio-38emantv.js} +22 -5
  64. package/dist/chunks/studio-3gxv60tn.js +422 -0
  65. package/dist/chunks/{studio-8swrjbny.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-gv8vvshc.js → studio-5523bpzt.js} +11 -11
  69. package/dist/chunks/{studio-5q69gfag.js → studio-57mf66w2.js} +1753 -2484
  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-eenfkt4e.js → studio-79y5sz51.js} +52 -38
  78. package/dist/chunks/{studio-4q0wznzf.js → studio-7e11jpa9.js} +461 -145
  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-arfpe389.js +195 -0
  88. package/dist/chunks/{studio-2zkz8evn.js → studio-az3zd49t.js} +473 -281
  89. package/dist/chunks/studio-cpvb2ed1.js +1171 -0
  90. package/dist/chunks/{studio-9r6j5ev1.js → studio-d0300636.js} +5078 -19
  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-4pqqxbrt.js → studio-em9nw8eh.js} +301 -112
  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-hhvs4sdg.js +195 -0
  100. package/dist/chunks/{studio-68n67094.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-kjjsjak4.js → studio-rkstz940.js} +3661 -6136
  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-yxrkyv8a.js → studio-s6z853aq.js} +12108 -11766
  113. package/dist/chunks/{studio-sf7zjgv1.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-htsf0w6m.js → studio-vz68yn9e.js} +31 -154
  118. package/dist/chunks/studio-wqpngpsk.js +174 -0
  119. package/dist/chunks/{studio-eesa1myv.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 +1812 -698
  135. package/dist/manifest.json +7 -0
  136. package/dist/studio.js +52900 -36573
  137. package/dist/workers/editor.worker.js +1040 -1085
  138. package/dist/workers/json.worker.js +1946 -1991
  139. package/dist/workers/ts.worker.js +4960 -5005
  140. package/favicon.ico +0 -0
  141. package/index.html +2 -0
  142. package/package.json +22 -55
  143. package/src/about/about-modal.ts +73 -123
  144. package/src/browse/library-commands.ts +20 -49
  145. package/src/browse/library-layouts.ts +87 -218
  146. package/src/browse/library-pane.ts +406 -438
  147. package/src/canvas/canvas-helpers.ts +0 -49
  148. package/src/canvas/canvas-live-render.ts +25 -2
  149. package/src/canvas/canvas-render.ts +666 -231
  150. package/src/canvas/canvas-surface.ts +0 -1
  151. package/src/canvas/canvas-utils.ts +310 -117
  152. package/src/canvas/dialog-path.ts +76 -0
  153. package/src/canvas/dialog-state.ts +67 -0
  154. package/src/canvas/diff-marks.ts +252 -0
  155. package/src/canvas/diff-toolbar.ts +349 -0
  156. package/src/canvas/diff-view.ts +123 -0
  157. package/src/canvas/edit-width-drag.ts +187 -0
  158. package/src/canvas/edit-width.ts +150 -0
  159. package/src/canvas/iframe-entry.ts +125 -8
  160. package/src/canvas/iframe-host.ts +271 -15
  161. package/src/canvas/iframe-interaction.ts +133 -13
  162. package/src/canvas/iframe-patch.ts +7 -1
  163. package/src/canvas/iframe-position.ts +5 -6
  164. package/src/canvas/iframe-protocol.ts +106 -5
  165. package/src/canvas/iframe-render.ts +373 -5
  166. package/src/canvas/iframe-slash.ts +2 -2
  167. package/src/canvas/iframe-subtree.ts +5 -8
  168. package/src/canvas/path-mapping.ts +25 -3
  169. package/src/canvas/popover-path.ts +106 -0
  170. package/src/canvas/popover-state.ts +155 -0
  171. package/src/canvas/surface-registry.ts +21 -10
  172. package/src/collab/presence-chips.ts +51 -73
  173. package/src/commands/app-commands.ts +10 -0
  174. package/src/commands/budget.ts +12 -0
  175. package/src/commands/command-args.ts +369 -6
  176. package/src/commands/defaults.ts +44 -14
  177. package/src/commands/live-context.ts +11 -5
  178. package/src/commands/reference.ts +12 -2
  179. package/src/commands/registry.ts +165 -8
  180. package/src/content/entry-commands.ts +16 -23
  181. package/src/content/entry-editor.ts +144 -101
  182. package/src/editor/canvas-slash-bridge.ts +2 -2
  183. package/src/editor/context-menu.ts +49 -200
  184. package/src/editor/convert-to-component.ts +42 -82
  185. package/src/editor/convert-to-repeater.ts +132 -173
  186. package/src/editor/inline-edit.ts +11 -0
  187. package/src/editor/shortcuts.ts +65 -26
  188. package/src/editor/slash-menu.ts +150 -157
  189. package/src/files/file-ops.ts +117 -11
  190. package/src/files/files.ts +949 -664
  191. package/src/files/json-layout.ts +474 -0
  192. package/src/files/media-paths.ts +13 -42
  193. package/src/files/media-usage.ts +41 -131
  194. package/src/files/serialize-document.ts +8 -1
  195. package/src/format/convert-file.ts +16 -10
  196. package/src/format/format-host.ts +50 -1
  197. package/src/github/github-auth.ts +71 -29
  198. package/src/github/github-publish.ts +57 -65
  199. package/src/grid/cell-editors.ts +46 -4
  200. package/src/grid/cell-popovers.ts +65 -62
  201. package/src/grid/grid-open.ts +86 -64
  202. package/src/grid/grid-panel.ts +390 -469
  203. package/src/grid/redirects-grid.ts +40 -44
  204. package/src/hosting/document.ts +2 -0
  205. package/src/hosting/layout.ts +10 -0
  206. package/src/i18n/i18n-commands.ts +127 -62
  207. package/src/media/media-pane.ts +83 -133
  208. package/src/new-project/add-repo-modal.ts +125 -176
  209. package/src/new-project/import-tab.ts +201 -250
  210. package/src/new-project/location-fields.ts +101 -165
  211. package/src/new-project/new-project-modal.ts +376 -367
  212. package/src/packages/jxsuite-update.ts +76 -18
  213. package/src/panels/activity-panel.ts +137 -104
  214. package/src/panels/ai-chat/chat-markdown.ts +15 -13
  215. package/src/panels/ai-chat/chat-view.ts +307 -472
  216. package/src/panels/ai-chat/composer.ts +175 -153
  217. package/src/panels/ai-chat/sessions-view.ts +31 -62
  218. package/src/panels/ai-panel.ts +210 -185
  219. package/src/panels/block-action-bar.ts +437 -643
  220. package/src/panels/bottom-dock.ts +112 -47
  221. package/src/panels/chat-panel.ts +19 -14
  222. package/src/panels/data-explorer.ts +141 -102
  223. package/src/panels/data-grid.ts +183 -150
  224. package/src/panels/dnd.ts +75 -20
  225. package/src/panels/editors.ts +26 -19
  226. package/src/panels/elements-panel.ts +243 -186
  227. package/src/panels/empty-state.ts +26 -42
  228. package/src/panels/events-panel.ts +950 -729
  229. package/src/panels/formula-workspace.ts +434 -207
  230. package/src/panels/frontmatter-fields.ts +185 -153
  231. package/src/panels/frontmatter-panel.ts +411 -187
  232. package/src/panels/git-diff-open.ts +148 -0
  233. package/src/panels/git-panel.ts +679 -605
  234. package/src/panels/head-panel.ts +617 -435
  235. package/src/panels/i18n-panel.ts +153 -133
  236. package/src/panels/imports-panel.ts +388 -414
  237. package/src/panels/jump-bar.ts +174 -147
  238. package/src/panels/layers-panel.ts +785 -671
  239. package/src/panels/left-panel.ts +166 -94
  240. package/src/panels/navigator-panels.ts +1 -1
  241. package/src/panels/pane-context.ts +529 -677
  242. package/src/panels/pane-grid.ts +265 -241
  243. package/src/panels/panel-registry.ts +15 -4
  244. package/src/panels/problems-panel.ts +177 -99
  245. package/src/panels/properties-panel.ts +1525 -966
  246. package/src/panels/provenance.ts +31 -113
  247. package/src/panels/quick-search.ts +217 -172
  248. package/src/panels/right-panel.ts +135 -169
  249. package/src/panels/seo-modal.ts +346 -167
  250. package/src/panels/settings-menu.ts +109 -646
  251. package/src/panels/settings-pane.ts +102 -86
  252. package/src/panels/signals-panel.ts +1318 -1172
  253. package/src/panels/statement-editor.ts +556 -428
  254. package/src/panels/style-panel.ts +1367 -630
  255. package/src/panels/style-utils.ts +36 -32
  256. package/src/panels/stylebook-doc.ts +30 -73
  257. package/src/panels/stylebook-layers-panel.ts +202 -109
  258. package/src/panels/stylebook-panel.ts +124 -88
  259. package/src/panels/tab-strip.ts +385 -287
  260. package/src/platforms/cloud.ts +347 -86
  261. package/src/platforms/devserver.ts +13 -0
  262. package/src/publish/deploy-checklist.ts +124 -78
  263. package/src/publish/publish-commands.ts +4 -12
  264. package/src/publish/publish-panel.ts +165 -299
  265. package/src/services/a11y-report.ts +100 -43
  266. package/src/services/ai-command-tools.ts +468 -0
  267. package/src/services/ai-import-tools.ts +50 -12
  268. package/src/services/ai-models.ts +108 -1
  269. package/src/services/ai-session-store.ts +6 -0
  270. package/src/services/ai-system-prompt.ts +110 -18
  271. package/src/services/ai-tools.ts +28 -143
  272. package/src/services/ai-write-report.ts +174 -0
  273. package/src/services/context-manager.ts +12 -1
  274. package/src/services/document-assistant.ts +50 -2
  275. package/src/services/idle.ts +16 -14
  276. package/src/services/live-surfaces.ts +237 -0
  277. package/src/services/model-uri.ts +75 -0
  278. package/src/services/notify.ts +63 -6
  279. package/src/services/popover-report.ts +325 -0
  280. package/src/services/surface-registry.ts +56 -0
  281. package/src/services/tool-executor.ts +17 -0
  282. package/src/settings/contexts-section.ts +301 -299
  283. package/src/settings/contributed-section.ts +361 -222
  284. package/src/settings/css-vars-editor.ts +320 -325
  285. package/src/settings/defs-editor.ts +572 -535
  286. package/src/settings/dependencies-editor.ts +79 -107
  287. package/src/settings/extension-commands.ts +379 -0
  288. package/src/settings/extension-rows.ts +113 -0
  289. package/src/settings/extensions-section.ts +287 -0
  290. package/src/settings/general-settings.ts +130 -181
  291. package/src/settings/head-editor.ts +10 -305
  292. package/src/settings/locales-section.ts +146 -196
  293. package/src/settings/preferences-accounts.ts +193 -12
  294. package/src/settings/preferences-dialog.ts +384 -307
  295. package/src/settings/project-sections.ts +108 -181
  296. package/src/settings/schema-field-ui.ts +11 -399
  297. package/src/settings/section-registry.ts +8 -1
  298. package/src/settings/settings-document.ts +31 -29
  299. package/src/shell/tree.ts +42 -87
  300. package/src/shell.ts +48 -36
  301. package/src/studio.ts +90 -67
  302. package/src/style/token-ref.ts +0 -39
  303. package/src/surfaces/about.json +263 -0
  304. package/src/surfaces/about.ts +163 -0
  305. package/src/surfaces/add-repo.json +486 -0
  306. package/src/surfaces/add-repo.ts +236 -0
  307. package/src/surfaces/ai-chat.json +2185 -0
  308. package/src/surfaces/ai-chat.ts +549 -0
  309. package/src/surfaces/ai-credentials-form.json +332 -0
  310. package/src/surfaces/ai-credentials-form.ts +151 -0
  311. package/src/surfaces/ai-managed-connect.json +108 -0
  312. package/src/surfaces/ai-managed-connect.ts +123 -0
  313. package/src/surfaces/ai-model-picker.json +114 -0
  314. package/src/surfaces/ai-model-picker.ts +139 -0
  315. package/src/surfaces/block-action-bar.json +640 -0
  316. package/src/surfaces/block-action-bar.ts +368 -0
  317. package/src/surfaces/bottom-dock.json +154 -0
  318. package/src/surfaces/bottom-dock.ts +125 -0
  319. package/src/surfaces/canvas-stage.json +444 -0
  320. package/src/surfaces/canvas-stage.ts +253 -0
  321. package/src/surfaces/cf-account-picker.json +300 -0
  322. package/src/surfaces/cf-account-picker.ts +214 -0
  323. package/src/surfaces/commandbar.json +984 -0
  324. package/src/{panels/toolbar.ts → surfaces/commandbar.ts} +414 -389
  325. package/src/surfaces/convert-repeater.json +309 -0
  326. package/src/surfaces/convert-repeater.ts +276 -0
  327. package/src/surfaces/data-actions.json +157 -0
  328. package/src/surfaces/data-actions.ts +115 -0
  329. package/src/surfaces/dialog.json +289 -0
  330. package/src/surfaces/dialog.ts +343 -0
  331. package/src/surfaces/diff-toolbar.json +266 -0
  332. package/src/surfaces/diff-toolbar.ts +139 -0
  333. package/src/surfaces/doc-header.json +739 -0
  334. package/src/surfaces/doc-header.ts +223 -0
  335. package/src/surfaces/empty-state.json +152 -0
  336. package/src/surfaces/empty-state.ts +173 -0
  337. package/src/surfaces/entry-editor.json +281 -0
  338. package/src/surfaces/entry-editor.ts +191 -0
  339. package/src/surfaces/expression-editor.json +977 -0
  340. package/src/surfaces/expression-editor.ts +266 -0
  341. package/src/surfaces/files-panel.json +592 -0
  342. package/src/surfaces/files-panel.ts +301 -0
  343. package/src/surfaces/formula-palette.json +364 -0
  344. package/src/surfaces/formula-palette.ts +340 -0
  345. package/src/surfaces/git-panel.json +1822 -0
  346. package/src/surfaces/git-panel.ts +272 -0
  347. package/src/surfaces/github-auth.json +112 -0
  348. package/src/surfaces/github-auth.ts +139 -0
  349. package/src/surfaces/github-publish.json +206 -0
  350. package/src/surfaces/github-publish.ts +169 -0
  351. package/src/surfaces/grid-cell.json +218 -0
  352. package/src/surfaces/grid-cell.ts +120 -0
  353. package/src/surfaces/grid-open.json +147 -0
  354. package/src/surfaces/grid-open.ts +87 -0
  355. package/src/surfaces/grid-panel.json +706 -0
  356. package/src/surfaces/grid-panel.ts +206 -0
  357. package/src/surfaces/grid-replace.json +179 -0
  358. package/src/surfaces/grid-replace.ts +89 -0
  359. package/src/surfaces/grid-views.json +446 -0
  360. package/src/surfaces/grid-views.ts +172 -0
  361. package/src/surfaces/inspector-dock.json +187 -0
  362. package/src/surfaces/inspector-dock.ts +161 -0
  363. package/src/surfaces/jump-bar.json +243 -0
  364. package/src/surfaces/jump-bar.ts +129 -0
  365. package/src/surfaces/jxsuite-update.json +146 -0
  366. package/src/surfaces/jxsuite-update.ts +149 -0
  367. package/src/surfaces/library-pane.json +1509 -0
  368. package/src/surfaces/library-pane.ts +363 -0
  369. package/src/surfaces/logic-panel.json +1949 -0
  370. package/src/surfaces/logic-panel.ts +369 -0
  371. package/src/surfaces/logic-workspace.json +685 -0
  372. package/src/surfaces/logic-workspace.ts +238 -0
  373. package/src/surfaces/media-browser.json +303 -0
  374. package/src/surfaces/media-browser.ts +145 -0
  375. package/src/surfaces/media-field.json +163 -0
  376. package/src/surfaces/media-field.ts +116 -0
  377. package/src/surfaces/media-pane.json +513 -0
  378. package/src/surfaces/media-pane.ts +197 -0
  379. package/src/surfaces/menu.json +232 -0
  380. package/src/surfaces/menu.ts +375 -0
  381. package/src/surfaces/navigator-dock.json +113 -0
  382. package/src/surfaces/navigator-dock.ts +130 -0
  383. package/src/surfaces/new-project.json +1654 -0
  384. package/src/surfaces/new-project.ts +411 -0
  385. package/src/surfaces/palette.json +535 -0
  386. package/src/surfaces/pane-context.json +1497 -0
  387. package/src/surfaces/pane-context.ts +513 -0
  388. package/src/surfaces/pane-grid.json +188 -0
  389. package/src/surfaces/pane-grid.ts +250 -0
  390. package/src/surfaces/panel-activity.json +563 -0
  391. package/src/surfaces/panel-activity.ts +187 -0
  392. package/src/surfaces/panel-data.json +141 -0
  393. package/src/surfaces/panel-data.ts +156 -0
  394. package/src/surfaces/panel-deploy-checklist.json +283 -0
  395. package/src/surfaces/panel-deploy-checklist.ts +175 -0
  396. package/src/surfaces/panel-elements.json +367 -0
  397. package/src/surfaces/panel-elements.ts +175 -0
  398. package/src/surfaces/panel-i18n.json +569 -0
  399. package/src/surfaces/panel-i18n.ts +212 -0
  400. package/src/surfaces/panel-imports.json +780 -0
  401. package/src/surfaces/panel-imports.ts +209 -0
  402. package/src/surfaces/panel-outline.json +734 -0
  403. package/src/surfaces/panel-outline.ts +326 -0
  404. package/src/surfaces/panel-page.json +1017 -0
  405. package/src/surfaces/panel-page.ts +240 -0
  406. package/src/surfaces/panel-problems.json +497 -0
  407. package/src/surfaces/panel-problems.ts +157 -0
  408. package/src/surfaces/panel-signals.json +1973 -0
  409. package/src/surfaces/panel-signals.ts +436 -0
  410. package/src/surfaces/panel-stylebook-layers.json +317 -0
  411. package/src/surfaces/panel-stylebook-layers.ts +155 -0
  412. package/src/surfaces/preferences.json +850 -0
  413. package/src/surfaces/preferences.ts +332 -0
  414. package/src/surfaces/progress-modal.json +110 -0
  415. package/src/surfaces/progress-modal.ts +150 -0
  416. package/src/surfaces/properties-panel.json +1578 -0
  417. package/src/surfaces/properties-panel.ts +337 -0
  418. package/src/surfaces/publish.json +945 -0
  419. package/src/surfaces/publish.ts +392 -0
  420. package/src/surfaces/push-plan.json +110 -0
  421. package/src/surfaces/push-plan.ts +87 -0
  422. package/src/surfaces/rail.json +255 -0
  423. package/src/surfaces/rail.ts +206 -0
  424. package/src/surfaces/reference-field.json +191 -0
  425. package/src/surfaces/reference-field.ts +168 -0
  426. package/src/surfaces/schema-builder.json +1011 -0
  427. package/src/surfaces/schema-builder.ts +181 -0
  428. package/src/surfaces/schema-form.json +1013 -0
  429. package/src/surfaces/schema-form.ts +287 -0
  430. package/src/surfaces/secret-field.json +60 -0
  431. package/src/surfaces/secret-field.ts +146 -0
  432. package/src/surfaces/seo.json +932 -0
  433. package/src/surfaces/seo.ts +334 -0
  434. package/src/surfaces/settings-contexts.json +538 -0
  435. package/src/surfaces/settings-contexts.ts +196 -0
  436. package/src/surfaces/settings-contributed.json +489 -0
  437. package/src/surfaces/settings-contributed.ts +199 -0
  438. package/src/surfaces/settings-css-vars.json +820 -0
  439. package/src/surfaces/settings-css-vars.ts +199 -0
  440. package/src/surfaces/settings-defs.json +1363 -0
  441. package/src/surfaces/settings-defs.ts +232 -0
  442. package/src/surfaces/settings-deploy.json +108 -0
  443. package/src/surfaces/settings-deploy.ts +135 -0
  444. package/src/surfaces/settings-extensions.json +486 -0
  445. package/src/surfaces/settings-extensions.ts +201 -0
  446. package/src/surfaces/settings-head.json +779 -0
  447. package/src/surfaces/settings-head.ts +397 -0
  448. package/src/surfaces/settings-locales.json +420 -0
  449. package/src/surfaces/settings-locales.ts +137 -0
  450. package/src/surfaces/settings-overview.json +423 -0
  451. package/src/surfaces/settings-overview.ts +218 -0
  452. package/src/surfaces/settings-packages.json +549 -0
  453. package/src/surfaces/settings-packages.ts +158 -0
  454. package/src/surfaces/settings-pane.json +147 -0
  455. package/src/surfaces/settings-pane.ts +150 -0
  456. package/src/surfaces/settings-rawjson.json +104 -0
  457. package/src/surfaces/settings-rawjson.ts +107 -0
  458. package/src/surfaces/shell.json +99 -0
  459. package/src/surfaces/shell.ts +30 -0
  460. package/src/surfaces/slash-menu.json +180 -0
  461. package/src/surfaces/slash-menu.ts +272 -0
  462. package/src/surfaces/statements.json +607 -0
  463. package/src/surfaces/statements.ts +238 -0
  464. package/src/surfaces/statusbar.json +94 -0
  465. package/src/{panels → surfaces}/statusbar.ts +163 -90
  466. package/src/surfaces/style-panel.json +1643 -0
  467. package/src/surfaces/style-panel.ts +338 -0
  468. package/src/surfaces/stylebook-chrome.json +122 -0
  469. package/src/surfaces/stylebook-chrome.ts +122 -0
  470. package/src/surfaces/tab-strip.json +448 -0
  471. package/src/surfaces/tab-strip.ts +200 -0
  472. package/src/surfaces/target-line.json +419 -0
  473. package/src/surfaces/target-line.ts +349 -0
  474. package/src/surfaces/toasts.json +189 -0
  475. package/src/surfaces/welcome.json +571 -0
  476. package/src/surfaces/welcome.ts +338 -0
  477. package/src/tabs/project-config.ts +71 -15
  478. package/src/tabs/tab.ts +52 -1
  479. package/src/types.ts +49 -3
  480. package/src/ui/ai-credentials-form.ts +104 -100
  481. package/src/ui/ai-managed-connect.ts +116 -49
  482. package/src/ui/ai-model-picker.ts +102 -47
  483. package/src/ui/cf-account-picker.ts +135 -0
  484. package/src/ui/color-selector.ts +80 -301
  485. package/src/ui/dynamic-slot.ts +43 -283
  486. package/src/ui/expression-editor.ts +797 -576
  487. package/src/ui/field-input.ts +8 -181
  488. package/src/ui/form-controls.ts +838 -366
  489. package/src/ui/formula-chips.ts +80 -85
  490. package/src/ui/kit.ts +33 -0
  491. package/src/ui/layers.ts +293 -593
  492. package/src/ui/media-picker.ts +203 -284
  493. package/src/ui/panel-resize.ts +251 -64
  494. package/src/ui/popover-surface.ts +153 -0
  495. package/src/ui/progress-modal.ts +22 -60
  496. package/src/ui/regions.ts +13 -7
  497. package/src/ui/schema-form.ts +906 -440
  498. package/src/ui/surface.ts +122 -0
  499. package/src/ui/unit-selector.ts +15 -131
  500. package/src/ui/value-source.ts +14 -0
  501. package/src/ui/virtual-window.ts +88 -9
  502. package/src/utils/canvas-media.ts +72 -0
  503. package/src/utils/edit-display.ts +7 -2
  504. package/src/utils/element-selectors.ts +69 -0
  505. package/src/utils/link-target.ts +2 -2
  506. package/src/utils/studio-utils.ts +0 -10
  507. package/src/view.ts +15 -0
  508. package/src/workspace/pane-derive.ts +36 -14
  509. package/src/workspace/workspace.ts +15 -6
  510. package/styles/canvas.css +72 -467
  511. package/styles/forced-colors.css +48 -82
  512. package/styles/forced-colors.json +41 -0
  513. package/styles/inspector.css +2 -1301
  514. package/styles/overlays.css +96 -2823
  515. package/styles/panels.css +6 -1423
  516. package/styles/shell-frame.css +272 -0
  517. package/styles/shell-frame.json +227 -0
  518. package/styles/shell.css +0 -1532
  519. package/styles/tokens.css +65 -136
  520. package/styles/tokens.json +84 -0
  521. package/dist/chunks/Overlay.dev-723bv0df.js +0 -23
  522. package/dist/chunks/adapter-jkcyhgtr.js +0 -14
  523. package/dist/chunks/cf-settings-45fgyx8y.js +0 -21
  524. package/dist/chunks/components-zmx10t62.js +0 -21
  525. package/dist/chunks/content-source-t88vb2dr.js +0 -49
  526. package/dist/chunks/convert-to-repeater-dhw1nrz9.js +0 -268
  527. package/dist/chunks/editor-cptq5jp1.js +0 -37
  528. package/dist/chunks/entry-commands-6z6bhxg0.js +0 -46
  529. package/dist/chunks/extension-sections-3ydgjbdy.js +0 -311
  530. package/dist/chunks/file-ops-rskmhxyq.js +0 -48
  531. package/dist/chunks/files-0cratsr0.js +0 -92
  532. package/dist/chunks/flow-qbfgrpeh.js +0 -634
  533. package/dist/chunks/focus-trap.esm-ggawf1hy.js +0 -1024
  534. package/dist/chunks/focus-visible-6eg70z18.js +0 -167
  535. package/dist/chunks/format-host-tgcmfs4p.js +0 -43
  536. package/dist/chunks/fs-events-hrrg328g.js +0 -21
  537. package/dist/chunks/git-panel-0yywyk76.js +0 -58
  538. package/dist/chunks/index-zqxmqxmh.js +0 -109
  539. package/dist/chunks/jx-validate-8q2g05x1.js +0 -19
  540. package/dist/chunks/layers-panel-z3tqe5cd.js +0 -67
  541. package/dist/chunks/layers-q75tj2mf.js +0 -45
  542. package/dist/chunks/lit-html-j055mkh8.js +0 -22
  543. package/dist/chunks/monaco-buffer-dqw0xxpx.js +0 -25
  544. package/dist/chunks/notify-yjm79n4s.js +0 -30
  545. package/dist/chunks/parse-24d0gay3.js +0 -19
  546. package/dist/chunks/platform-ba1j1gbh.js +0 -16
  547. package/dist/chunks/publish-panel-54jvhskq.js +0 -28
  548. package/dist/chunks/quick-search-cgfmjwq5.js +0 -65
  549. package/dist/chunks/references-3qx8fkyp.js +0 -29
  550. package/dist/chunks/right-panel-cqp8bc4v.js +0 -46
  551. package/dist/chunks/section-registry-sx1ykvkw.js +0 -30
  552. package/dist/chunks/sp-overlay.dev-yztmtrs1.js +0 -18
  553. package/dist/chunks/sp-popover.dev-n2etmqdp.js +0 -9
  554. package/dist/chunks/sp-progress-circle.dev-hryhj0es.js +0 -15
  555. package/dist/chunks/sp-tooltip.dev-xcvpnqr0.js +0 -15
  556. package/dist/chunks/sp-tray.dev-tkbscm06.js +0 -199
  557. package/dist/chunks/studio-0a5qrh01.js +0 -3
  558. package/dist/chunks/studio-18j3bmcz.js +0 -14
  559. package/dist/chunks/studio-1hbqnt19.js +0 -1823
  560. package/dist/chunks/studio-4rzyrtjz.js +0 -426
  561. package/dist/chunks/studio-5rywrkxz.js +0 -1903
  562. package/dist/chunks/studio-7afd21nw.js +0 -67
  563. package/dist/chunks/studio-7nte2hj4.js +0 -613
  564. package/dist/chunks/studio-8jpzqk5s.js +0 -128
  565. package/dist/chunks/studio-8q517dfr.js +0 -24
  566. package/dist/chunks/studio-9c4k4vhv.js +0 -357
  567. package/dist/chunks/studio-9n4mrmnb.js +0 -184
  568. package/dist/chunks/studio-a0tswy0w.js +0 -58
  569. package/dist/chunks/studio-ahjfdy6e.js +0 -387
  570. package/dist/chunks/studio-ahnzd9rg.js +0 -23
  571. package/dist/chunks/studio-bw5dz6km.js +0 -608
  572. package/dist/chunks/studio-cb12yz9w.js +0 -15055
  573. package/dist/chunks/studio-d1ks410h.js +0 -175
  574. package/dist/chunks/studio-eqq1w638.js +0 -113
  575. package/dist/chunks/studio-ex8zyp98.js +0 -1813
  576. package/dist/chunks/studio-h4rxscfc.js +0 -10
  577. package/dist/chunks/studio-kyh9avvv.js +0 -28
  578. package/dist/chunks/studio-kyk2v92a.js +0 -659
  579. package/dist/chunks/studio-m3hwn7y1.js +0 -120
  580. package/dist/chunks/studio-mmv72a27.js +0 -4344
  581. package/dist/chunks/studio-n8b9wqwy.js +0 -291
  582. package/dist/chunks/studio-pdfjntbk.js +0 -6939
  583. package/dist/chunks/studio-qq6jym04.js +0 -53
  584. package/dist/chunks/studio-r1r7afxx.js +0 -1066
  585. package/dist/chunks/studio-rdx8jcxy.js +0 -83
  586. package/dist/chunks/studio-rn9ta2mz.js +0 -111
  587. package/dist/chunks/studio-t7qb9db8.js +0 -665
  588. package/dist/chunks/studio-tmc5emrw.js +0 -8
  589. package/dist/chunks/studio-txwkm6p9.js +0 -12
  590. package/dist/chunks/studio-v38hmvx1.js +0 -390
  591. package/dist/chunks/studio-vadzgkrz.js +0 -318
  592. package/dist/chunks/studio-wx5609xd.js +0 -341
  593. package/dist/chunks/studio-z6nw2ek2.js +0 -18
  594. package/dist/chunks/studio-zczps70q.js +0 -378
  595. package/dist/chunks/workspace-xpres40v.js +0 -89
  596. package/src/panels/activity-bar.ts +0 -251
  597. package/src/panels/panel-scheduler.ts +0 -219
  598. package/src/panels/style-inputs.ts +0 -237
  599. package/src/panels/target-line.ts +0 -274
  600. package/src/panels/welcome-screen.ts +0 -346
  601. package/src/ui/button-group.ts +0 -102
  602. package/src/ui/choice-field.ts +0 -72
  603. package/src/ui/field-row.ts +0 -249
  604. package/src/ui/formula-palette.ts +0 -213
  605. package/src/ui/icons.ts +0 -52
  606. package/src/ui/jx-theme.ts +0 -130
  607. package/src/ui/spectrum.ts +0 -340
  608. package/src/ui/value-selector.ts +0 -174
  609. package/src/ui/widgets.ts +0 -172
  610. /package/dist/chunks/{javascript-s56a8dpk.css → javascript-4abzjcy9.css} +0 -0
  611. /package/dist/chunks/{jsonMode-zr9sw0c7.css → jsonMode-vvmpmk34.css} +0 -0
  612. /package/dist/chunks/{monaco-setup-pav68602.css → monaco-setup-8vbyqnhr.css} +0 -0
  613. /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
  }
@@ -1499,6 +1566,309 @@ function computed(getterOrOptions, debugOptions, isSSR = false) {
1499
1566
  return cRef;
1500
1567
  }
1501
1568
 
1569
+ // ../runtime/src/css.ts
1570
+ function camelToKebab(s) {
1571
+ return s.replaceAll(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
1572
+ }
1573
+ var MEDIA_TYPES = new Set(["all", "print", "screen", "speech"]);
1574
+ function resolveAtQuery(atKey, mediaQueries) {
1575
+ if (atKey.startsWith("@--")) {
1576
+ return mediaQueries[atKey.slice(1)] ?? atKey.slice(1);
1577
+ }
1578
+ if (atKey.startsWith("@(")) {
1579
+ const inner = atKey.slice(2, -1).trim();
1580
+ return MEDIA_TYPES.has(inner.toLowerCase()) ? inner : atKey.slice(1);
1581
+ }
1582
+ return null;
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
+ }
1665
+ var COLOR_SCHEME_ATTR = "data-color-scheme";
1666
+ function pureSchemeOf(query) {
1667
+ const m = /^\(\s*prefers-color-scheme\s*:\s*(light|dark)\s*\)$/.exec(query.trim());
1668
+ return m?.[1] ?? null;
1669
+ }
1670
+ function schemeSelectors(selector, scheme) {
1671
+ if (selector === ":root" || selector === "html") {
1672
+ return {
1673
+ auto: `${selector}:where(:not([${COLOR_SCHEME_ATTR}]))`,
1674
+ forced: `${selector}:where([${COLOR_SCHEME_ATTR}="${scheme}"])`
1675
+ };
1676
+ }
1677
+ return {
1678
+ auto: `:where(:root:not([${COLOR_SCHEME_ATTR}])) ${selector}`,
1679
+ forced: `:where(:root[${COLOR_SCHEME_ATTR}="${scheme}"]) ${selector}`
1680
+ };
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
+ }
1871
+
1502
1872
  // ../schema/src/intl.ts
1503
1873
  var DEFAULT_FORMAT_LOCALE = "en-US";
1504
1874
  var DEFAULT_TIME_ZONE = "UTC";
@@ -1729,8 +2099,8 @@ function withPageLocale(path, args, state) {
1729
2099
  filled[index] = locale;
1730
2100
  return filled;
1731
2101
  }
1732
- function isBlessedGlobal(ref2) {
1733
- 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));
1734
2104
  }
1735
2105
  function isMutating(op) {
1736
2106
  return MUTATING_OPS.has(op);
@@ -1769,24 +2139,43 @@ function resolveOperand(operand, state, event, iterCtx, trace) {
1769
2139
  trace?.report(trace.path ?? [], operand);
1770
2140
  return operand;
1771
2141
  }
1772
- function resolveExprRef(ref2, state, event, iterCtx) {
1773
- 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") {
1774
2163
  return iterCtx?.acc;
1775
2164
  }
1776
- if (ref2.startsWith("$reduce/")) {
2165
+ if (ref.startsWith("$reduce/")) {
1777
2166
  return iterCtx?.acc;
1778
2167
  }
1779
- if (ref2.startsWith("$args/")) {
1780
- const parts = ref2.slice("$args/".length).split("/");
2168
+ if (ref.startsWith("$args/")) {
2169
+ const parts = ref.slice("$args/".length).split("/");
1781
2170
  const base = iterCtx?.args?.[parts[0]];
1782
2171
  return parts.length > 1 ? getPath(base, parts.slice(1).join("/")) : base;
1783
2172
  }
1784
- if (ref2.startsWith("event#/")) {
1785
- const path = ref2.slice("event#/".length);
2173
+ if (ref.startsWith("event#/")) {
2174
+ const path = ref.slice("event#/".length);
1786
2175
  return getPath(event, path);
1787
2176
  }
1788
- if (ref2.startsWith("$map/")) {
1789
- const parts = ref2.split("/");
2177
+ if (ref.startsWith("$map/")) {
2178
+ const parts = ref.split("/");
1790
2179
  const [, key] = parts;
1791
2180
  let base;
1792
2181
  const map = scopeMap(state);
@@ -1799,23 +2188,23 @@ function resolveExprRef(ref2, state, event, iterCtx) {
1799
2188
  }
1800
2189
  return parts.length > 2 ? getPath(base, parts.slice(2).join("/")) : base;
1801
2190
  }
1802
- if (ref2.startsWith("#/state/")) {
1803
- return readPath(state, ref2.slice("#/state/".length));
2191
+ if (ref.startsWith("#/state/")) {
2192
+ return readPath(state, ref.slice("#/state/".length));
1804
2193
  }
1805
- if (ref2.startsWith("parent#/")) {
1806
- return readPath(state, ref2.slice("parent#/".length));
2194
+ if (ref.startsWith("parent#/")) {
2195
+ return readPath(state, ref.slice("parent#/".length));
1807
2196
  }
1808
- if (ref2.startsWith("window#/")) {
1809
- return getPath(globalThis.window, ref2.slice("window#/".length));
2197
+ if (ref.startsWith("window#/")) {
2198
+ return getPath(globalThis.window, ref.slice("window#/".length));
1810
2199
  }
1811
- if (ref2.startsWith("document#/")) {
1812
- return getPath(globalThis.document, ref2.slice("document#/".length));
2200
+ if (ref.startsWith("document#/")) {
2201
+ return getPath(globalThis.document, ref.slice("document#/".length));
1813
2202
  }
1814
- return readPath(state, ref2) ?? null;
2203
+ return readPath(state, ref) ?? null;
1815
2204
  }
1816
- function resolveWritableRef(ref2, state, _event, iterCtx) {
1817
- if (ref2.startsWith("$map/")) {
1818
- const parts = ref2.split("/");
2205
+ function resolveWritableRef(ref, state, _event, iterCtx) {
2206
+ if (ref.startsWith("$map/")) {
2207
+ const parts = ref.split("/");
1819
2208
  const [, key] = parts;
1820
2209
  let base;
1821
2210
  const map = scopeMap(state);
@@ -1837,8 +2226,8 @@ function resolveWritableRef(ref2, state, _event, iterCtx) {
1837
2226
  obj: scopeMap(state) ?? state
1838
2227
  };
1839
2228
  }
1840
- if (ref2.startsWith("#/state/")) {
1841
- const sub = ref2.slice("#/state/".length);
2229
+ if (ref.startsWith("#/state/")) {
2230
+ const sub = ref.slice("#/state/".length);
1842
2231
  const slash = sub.indexOf("/");
1843
2232
  if (slash === -1) {
1844
2233
  return { key: sub, obj: state };
@@ -1851,7 +2240,7 @@ function resolveWritableRef(ref2, state, _event, iterCtx) {
1851
2240
  }
1852
2241
  return { key: lastKey, obj };
1853
2242
  }
1854
- return { key: ref2, obj: state };
2243
+ return { key: ref, obj: state };
1855
2244
  }
1856
2245
  function evaluateExpression(node, state, event, iterCtx, trace) {
1857
2246
  const result = evaluateNode(node, state, event, iterCtx, trace);
@@ -1898,19 +2287,19 @@ function evaluateNode(node, state, event, iterCtx, trace) {
1898
2287
  }
1899
2288
  const callee = resolveExprRef(calleeRef, state, event, iterCtx);
1900
2289
  if (typeof callee === "function") {
1901
- return callee(...argValues);
2290
+ return callee.apply(calleeOwner(calleeRef, state, event, iterCtx), argValues);
1902
2291
  }
1903
2292
  if (callee && typeof callee === "object" && "$expression" in callee) {
1904
- const def2 = callee;
2293
+ const def = callee;
1905
2294
  const args = {};
1906
- for (const [i, p] of (def2.parameters ?? []).entries()) {
2295
+ for (const [i, p] of (def.parameters ?? []).entries()) {
1907
2296
  const name = typeof p === "string" ? p : p?.name ?? "";
1908
2297
  if (!name) {
1909
2298
  continue;
1910
2299
  }
1911
2300
  args[name] = argValues[i] === undefined && typeof p === "object" && p !== null && "default" in p ? p.default : argValues[i];
1912
2301
  }
1913
- return evaluateExpression(def2.$expression, state, event, { args, callDepth });
2302
+ return evaluateExpression(def.$expression, state, event, { args, callDepth });
1914
2303
  }
1915
2304
  throw new TypeError(`$expression: call target "${calleeRef}" is not callable`);
1916
2305
  }
@@ -2152,10 +2541,10 @@ function isNonRelativeRef(value) {
2152
2541
  function normalizeProjectPath(path) {
2153
2542
  return path.replaceAll("\\", "/").replace(/^\.\//, "").replace(/^\/+/, "").replace(/\/+$/, "");
2154
2543
  }
2155
- function joinProjectPath(dir, ref2) {
2544
+ function joinProjectPath(dir, ref) {
2156
2545
  const base = dir === "" || dir === "." ? [] : normalizeProjectPath(dir).split("/");
2157
2546
  const out = base.filter((segment) => segment !== "" && segment !== ".");
2158
- for (const segment of ref2.replaceAll("\\", "/").split("/")) {
2547
+ for (const segment of ref.replaceAll("\\", "/").split("/")) {
2159
2548
  if (segment === "" || segment === ".") {
2160
2549
  continue;
2161
2550
  }
@@ -2277,6 +2666,12 @@ function statementKind(statement) {
2277
2666
  if ("$switch" in statement) {
2278
2667
  return "switch";
2279
2668
  }
2669
+ if ("stopPropagation" in statement) {
2670
+ return "stopPropagation";
2671
+ }
2672
+ if ("preventDefault" in statement) {
2673
+ return "preventDefault";
2674
+ }
2280
2675
  return "dispatch";
2281
2676
  }
2282
2677
  async function runStatements(statements, state, event, opts = {}) {
@@ -2310,7 +2705,8 @@ async function runStatements(statements, state, event, opts = {}) {
2310
2705
  }
2311
2706
  case "dispatch": {
2312
2707
  const dispatch = statement;
2313
- const target = opts.target ?? event?.currentTarget;
2708
+ const fallback = typeof opts.target === "function" ? opts.target() : opts.target;
2709
+ const target = event?.currentTarget ?? fallback;
2314
2710
  if (!target) {
2315
2711
  break;
2316
2712
  }
@@ -2327,6 +2723,14 @@ async function runStatements(statements, state, event, opts = {}) {
2327
2723
  target.dispatchEvent(new CustomEvent(dispatch.dispatchEvent, init));
2328
2724
  break;
2329
2725
  }
2726
+ case "stopPropagation": {
2727
+ event?.stopPropagation();
2728
+ break;
2729
+ }
2730
+ case "preventDefault": {
2731
+ event?.preventDefault();
2732
+ break;
2733
+ }
2330
2734
  default: {
2331
2735
  break;
2332
2736
  }
@@ -2372,13 +2776,16 @@ function serializeCookie(name, value, options) {
2372
2776
  }
2373
2777
  return parts.join("; ");
2374
2778
  }
2375
-
2376
2779
  // ../runtime/src/runtime.ts
2377
2780
  var _resolveCache = new Map;
2378
- async function resolve(source) {
2781
+ async function resolve(source, ctx) {
2379
2782
  if (typeof source !== "string") {
2380
2783
  return source;
2381
2784
  }
2785
+ const served = ctx?.resolver?.(source);
2786
+ if (served) {
2787
+ return served;
2788
+ }
2382
2789
  if (_resolveCache.has(source)) {
2383
2790
  return _resolveCache.get(source);
2384
2791
  }
@@ -2463,10 +2870,36 @@ var _canvasDelinkAnchors = false;
2463
2870
  function setCanvasDelinkAnchors(on) {
2464
2871
  _canvasDelinkAnchors = on;
2465
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
+ }
2466
2885
  function canvasAttrName(el, key) {
2467
2886
  if (_canvasDelinkAnchors && key === "href" && (el.tagName === "A" || el.tagName === "AREA")) {
2468
2887
  return "data-jx-href";
2469
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
+ }
2470
2903
  return key;
2471
2904
  }
2472
2905
  var _canvasAssetResolver = null;
@@ -2546,71 +2979,84 @@ function boundPropKey(key, val, state) {
2546
2979
  }
2547
2980
  return sub;
2548
2981
  }
2549
- async function buildScope(doc, parentScope = {}, base = location.href) {
2982
+ async function buildScope(doc, parentScope = {}, base = location.href, ctx) {
2983
+ const dispatchRoot = () => ctx?.root ?? null;
2550
2984
  const raw = {};
2551
- for (const [key, val] of Object.entries(parentScope)) {
2552
- raw[key] = val;
2553
- }
2554
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
+ }
2555
3001
  const imports = doc.imports ?? {};
2556
- for (const [, def2] of Object.entries(defs)) {
2557
- if (isPrototypeDef(def2) && !def2.$src) {
2558
- 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];
2559
3005
  if (mapped) {
2560
3006
  if (!mapped.endsWith(".class.json")) {
2561
- 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}"`);
2562
3008
  continue;
2563
3009
  }
2564
- def2.$src = mapped;
3010
+ def.$src = mapped;
2565
3011
  }
2566
3012
  }
2567
3013
  }
2568
- for (const [key, def2] of Object.entries(defs)) {
2569
- if (typeof def2 === "string") {
2570
- if (!def2.includes("${")) {
2571
- 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;
2572
3018
  }
2573
3019
  continue;
2574
3020
  }
2575
- if (typeof def2 === "number" || typeof def2 === "boolean" || def2 === null) {
2576
- raw[key] = def2;
3021
+ if (typeof def === "number" || typeof def === "boolean" || def === null) {
3022
+ raw[key] = def;
2577
3023
  continue;
2578
3024
  }
2579
- if (Array.isArray(def2)) {
2580
- raw[key] = def2;
3025
+ if (Array.isArray(def)) {
3026
+ raw[key] = def;
2581
3027
  continue;
2582
3028
  }
2583
- if (typeof def2 === "object") {
2584
- if (def2.$prototype) {
3029
+ if (typeof def === "object") {
3030
+ if (def.$prototype) {
2585
3031
  continue;
2586
3032
  }
2587
- if (isExpressionDef(def2)) {
3033
+ if (isExpressionDef(def)) {
2588
3034
  continue;
2589
3035
  }
2590
- if (isServerFnDef(def2)) {
3036
+ if (isServerFnDef(def)) {
2591
3037
  continue;
2592
3038
  }
2593
- if ("default" in def2) {
2594
- raw[key] = def2.default;
3039
+ if ("default" in def) {
3040
+ raw[key] = def.default;
2595
3041
  continue;
2596
3042
  }
2597
- if (hasSchemaKeywords(def2)) {
3043
+ if (hasSchemaKeywords(def)) {
2598
3044
  continue;
2599
3045
  }
2600
- raw[key] = def2;
3046
+ raw[key] = def;
2601
3047
  }
2602
3048
  }
2603
3049
  const state = reactive(raw);
2604
- for (const [key, def2] of Object.entries(defs)) {
2605
- if (typeof def2 === "string" && def2.includes("${")) {
2606
- 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));
2607
3053
  }
2608
3054
  }
2609
- for (const [key, def2] of Object.entries(defs)) {
2610
- if (isExpressionDef(def2)) {
2611
- const node = def2.$expression;
2612
- if (isNamedFormulaDef(def2)) {
2613
- 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;
2614
3060
  state[key] = (...argValues) => {
2615
3061
  const args = {};
2616
3062
  for (const [i, p] of params.entries()) {
@@ -2630,11 +3076,11 @@ async function buildScope(doc, parentScope = {}, base = location.href) {
2630
3076
  }
2631
3077
  }
2632
3078
  }
2633
- for (const [key, def2] of Object.entries(defs)) {
2634
- if (hasStructuredBody(def2)) {
2635
- const { body } = def2;
2636
- if (Array.isArray(def2.parameters) && def2.parameters.length > 0) {
2637
- 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;
2638
3084
  state[key] = (...argValues) => {
2639
3085
  const args = {};
2640
3086
  for (const [i, p] of params.entries()) {
@@ -2644,34 +3090,35 @@ async function buildScope(doc, parentScope = {}, base = location.href) {
2644
3090
  }
2645
3091
  args[name] = argValues[i] === undefined && typeof p === "object" && p !== null && "default" in p ? p.default : argValues[i];
2646
3092
  }
2647
- return runStatements(body, state, null, { args });
3093
+ return runStatements(body, state, null, { args, target: dispatchRoot });
2648
3094
  };
2649
3095
  } else {
2650
3096
  const handler = (s, event) => {
2651
- runStatements(body, s, event ?? null);
3097
+ runStatements(body, s, event ?? null, { target: dispatchRoot });
2652
3098
  };
2653
3099
  state[key] = handler;
2654
3100
  }
2655
- } else if (isFunctionDef(def2)) {
2656
- state[key] = await resolveFunction(def2, state, key, base);
3101
+ } else if (isFunctionDef(def)) {
3102
+ state[key] = await resolveFunction(def, state, key, base);
2657
3103
  }
2658
3104
  }
2659
- for (const [key, def2] of Object.entries(defs)) {
2660
- if (isPrototypeDef(def2)) {
2661
- 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);
2662
3108
  }
2663
3109
  }
2664
- if (!_serverFnConfig.skip) {
2665
- for (const [key, def2] of Object.entries(defs)) {
2666
- if (isServerFnDef(def2)) {
2667
- 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);
2668
3114
  }
2669
3115
  }
2670
3116
  }
3117
+ const rootMedia = ctx?.media ?? _rootMedia;
2671
3118
  if (doc.$media) {
2672
3119
  state["$media"] = doc.$media;
2673
- } else if (!state["$media"] && Object.keys(_rootMedia).length > 0) {
2674
- state["$media"] = _rootMedia;
3120
+ } else if (!state["$media"] && Object.keys(rootMedia).length > 0) {
3121
+ state["$media"] = rootMedia;
2675
3122
  }
2676
3123
  return state;
2677
3124
  }
@@ -2715,36 +3162,72 @@ function evaluateAttrTemplate(str, state) {
2715
3162
  return fn(state, $map, $map?.item, $map?.index);
2716
3163
  }
2717
3164
  var _moduleCache = new Map;
2718
- async function resolveFunction(def2, state, key, base) {
2719
- 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) {
2720
3200
  throw new Error(`Jx: '${key}' declares both body and $src — these are mutually exclusive`);
2721
3201
  }
2722
- if (!def2.body && !def2.$src) {
2723
- const params = resolveParamNames(def2);
3202
+ if (!def.body && !def.$src) {
3203
+ const params = resolveParamNames(def);
2724
3204
  const noop = new Function(...params, "");
2725
3205
  Object.defineProperty(noop, "name", {
2726
3206
  configurable: true,
2727
- value: def2.name ?? key
3207
+ value: def.name ?? key
2728
3208
  });
2729
3209
  return noop;
2730
3210
  }
2731
3211
  let fn;
2732
- if (typeof def2.body === "string") {
2733
- const params = resolveParamNames(def2);
2734
- fn = new Function(...params, def2.body);
3212
+ if (typeof def.body === "string") {
3213
+ const params = resolveParamNames(def);
3214
+ fn = new Function(...params, def.body);
2735
3215
  Object.defineProperty(fn, "name", {
2736
3216
  configurable: true,
2737
- value: def2.name ?? key
3217
+ value: def.name ?? key
2738
3218
  });
2739
3219
  } else {
2740
- const src = def2.$src;
3220
+ const src = def.$src;
2741
3221
  if (!src) {
2742
3222
  throw new Error(`Jx: '${key}' has neither body nor $src`);
2743
3223
  }
2744
- const exportName = def2.$export ?? key;
3224
+ const exportName = def.$export ?? key;
2745
3225
  let mod;
2746
- if (_moduleCache.has(src)) {
2747
- 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;
2748
3231
  } else {
2749
3232
  if (base) {
2750
3233
  const resolvedSrc = new URL(src, base).href;
@@ -2764,11 +3247,11 @@ async function resolveFunction(def2, state, key, base) {
2764
3247
  }
2765
3248
  fn = candidate;
2766
3249
  }
2767
- const hasParams = (def2.parameters ?? def2.arguments ?? []).length > 0;
3250
+ const hasParams = (def.parameters ?? def.arguments ?? []).length > 0;
2768
3251
  let isComputed = false;
2769
3252
  if (!hasParams) {
2770
- if (typeof def2.body === "string") {
2771
- isComputed = bodyReturnsValue(def2.body);
3253
+ if (typeof def.body === "string") {
3254
+ isComputed = bodyReturnsValue(def.body);
2772
3255
  } else if (fn) {
2773
3256
  isComputed = fn.length <= 1 && bodyReturnsValue(fn.toString());
2774
3257
  }
@@ -2778,8 +3261,8 @@ async function resolveFunction(def2, state, key, base) {
2778
3261
  }
2779
3262
  return fn;
2780
3263
  }
2781
- function resolveParamNames(def2) {
2782
- const names = def2.parameters ? paramNames(def2.parameters) : def2.arguments ?? [];
3264
+ function resolveParamNames(def) {
3265
+ const names = def.parameters ? paramNames(def.parameters) : def.arguments ?? [];
2783
3266
  return names.length > 0 && names[0] === "state" ? names : ["state", ...names];
2784
3267
  }
2785
3268
  var RESERVED_KEYS = new Set([
@@ -2828,19 +3311,19 @@ function elementNamespace(tagName, inherited) {
2828
3311
  }
2829
3312
  return inherited ?? null;
2830
3313
  }
2831
- function renderNode(def2, state, options) {
3314
+ function renderNode(def, state, options) {
2832
3315
  const path = options?._path ?? [];
2833
- if (typeof def2 === "string" || typeof def2 === "number" || typeof def2 === "boolean") {
2834
- const textNode = document.createTextNode(String(def2));
2835
- 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)) {
2836
3319
  effect(() => {
2837
- textNode.textContent = evaluateTemplate(def2, state);
3320
+ textNode.textContent = evaluateTemplate(def, state);
2838
3321
  });
2839
3322
  }
2840
3323
  return textNode;
2841
3324
  }
2842
3325
  let localState = state;
2843
- for (const [key, val] of Object.entries(def2)) {
3326
+ for (const [key, val] of Object.entries(def)) {
2844
3327
  if (key.startsWith("$") && !RESERVED_KEYS.has(key)) {
2845
3328
  if (localState === state) {
2846
3329
  localState = Object.create(state);
@@ -2848,38 +3331,41 @@ function renderNode(def2, state, options) {
2848
3331
  localState[key] = isRefObj(val) ? resolveRef(val.$ref, state) : val;
2849
3332
  }
2850
3333
  }
2851
- if ("$ref" in def2 && !def2.tagName) {
2852
- const refTarget = String(def2.$ref ?? "");
3334
+ if ("$ref" in def && !def.tagName) {
3335
+ const refTarget = String(def.$ref ?? "");
2853
3336
  if (!warnedRefChildren.has(refTarget)) {
2854
3337
  warnedRefChildren.add(refTarget);
2855
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).`);
2856
3339
  }
2857
3340
  }
2858
- const tagName = resolveTagName(def2.tagName, localState);
3341
+ const tagName = resolveTagName(def.tagName, localState);
2859
3342
  const isCustomEl = tagName.includes("-") && customElements.get(tagName);
2860
- if (def2.$props && isCustomEl) {
2861
- return renderCustomElementWithProps(def2, localState, options, path);
3343
+ if (def.$props && isCustomEl) {
3344
+ return renderCustomElementWithProps(def, localState, options, path);
2862
3345
  }
2863
- if (def2.$props) {
3346
+ if (def.$props) {
2864
3347
  if (tagName.includes("-")) {
2865
- return renderCustomElementWithProps(def2, localState, options, path);
3348
+ return renderCustomElementWithProps(def, localState, options, path);
2866
3349
  }
2867
- const { $props: _$props, ...rest } = def2;
2868
- return renderNode(rest, mergeProps(def2, localState), options);
3350
+ const { $props: _$props, ...rest } = def;
3351
+ return renderNode(rest, mergeProps(def, localState), options);
2869
3352
  }
2870
- if (def2.$switch) {
2871
- return renderSwitch(def2, localState, options);
3353
+ if (def.$switch) {
3354
+ return renderSwitch(def, localState, options);
2872
3355
  }
2873
3356
  const ns = elementNamespace(tagName, options?._ns);
2874
3357
  const childNs = tagName === "foreignObject" ? null : ns;
2875
3358
  const el = ns ? document.createElementNS(ns, tagName) : document.createElement(tagName);
2876
3359
  if (options?.onNodeCreated) {
2877
- options.onNodeCreated(el, path, def2, localState);
3360
+ options.onNodeCreated(el, path, def, localState);
2878
3361
  }
2879
- applyProperties(el, def2, localState);
2880
- applyStyle(el, def2.style ?? {}, localState["$media"] ?? {}, localState);
2881
- applyAttributes(el, def2.attributes ?? {}, localState);
2882
- const kids = def2.children;
3362
+ applyProperties(el, def, localState);
3363
+ if (def.style && tagName.includes("-")) {
3364
+ callSiteStyles.set(el, def.style);
3365
+ }
3366
+ applyStyle(el, def.style ?? {}, localState["$media"] ?? {}, localState);
3367
+ applyAttributes(el, def.attributes ?? {}, localState);
3368
+ const kids = def.children;
2883
3369
  if (isMappedArray(kids)) {
2884
3370
  const arrOpts = options || childNs ? { ...options, _ns: childNs, _path: [...path, "children"] } : undefined;
2885
3371
  renderMappedArrayInto(el, kids, localState, arrOpts);
@@ -2896,49 +3382,58 @@ function renderNode(def2, state, options) {
2896
3382
  }
2897
3383
  return el;
2898
3384
  }
2899
- function applyProperties(el, def2, state) {
2900
- for (const [key, val] of Object.entries(def2)) {
3385
+ function applyProperties(el, def, state) {
3386
+ for (const [key, val] of Object.entries(def)) {
2901
3387
  if (RESERVED_KEYS.has(key)) {
2902
3388
  continue;
2903
3389
  }
2904
3390
  if (key.startsWith("$")) {
2905
3391
  continue;
2906
3392
  }
2907
- if (key.startsWith("on")) {
2908
- if (isRefObj(val)) {
2909
- const handler = resolveRef(val.$ref, state);
2910
- if (typeof handler === "function") {
2911
- const scope = state;
2912
- const handlerFn = handler;
2913
- el.addEventListener(key.slice(2), (e) => handlerFn(scope, e));
2914
- }
2915
- continue;
2916
- }
2917
- if (hasStructuredBody(val)) {
2918
- const { body } = val;
2919
- const scope = state;
2920
- el.addEventListener(key.slice(2), (e) => {
2921
- runStatements(body, scope, e);
2922
- });
2923
- continue;
2924
- }
2925
- if (isFunctionDef(val) && typeof val.body === "string") {
2926
- const params = resolveParamNames(val);
2927
- const fn = new Function(...params, val.body);
2928
- const scope = state;
2929
- el.addEventListener(key.slice(2), (e) => fn(scope, e));
2930
- continue;
2931
- }
2932
- if (isExpressionDef(val)) {
2933
- const node = val.$expression;
2934
- const scope = state;
2935
- el.addEventListener(key.slice(2), (e) => evaluateExpression(node, scope, e));
2936
- continue;
2937
- }
3393
+ if (key.startsWith("on") && bindHandler(el, key, val, state)) {
3394
+ continue;
2938
3395
  }
2939
3396
  bindProperty(el, key, val, state);
2940
3397
  }
2941
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
+ }
2942
3437
  function bindProperty(el, key, val, state) {
2943
3438
  const target = el;
2944
3439
  const boundProp = boundPropKey(key, val, state);
@@ -2952,6 +3447,9 @@ function bindProperty(el, key, val, state) {
2952
3447
  node.setAttribute("class", resolved == null ? "" : String(resolved));
2953
3448
  return;
2954
3449
  }
3450
+ if (target[key] === resolved) {
3451
+ return;
3452
+ }
2955
3453
  target[key] = resolved;
2956
3454
  };
2957
3455
  if (isRefObj(val)) {
@@ -2973,142 +3471,287 @@ function bindProperty(el, key, val, state) {
2973
3471
  }
2974
3472
  write(asAsset(val));
2975
3473
  }
2976
- function applyStyle(el, styleDef, mediaQueries = {}, state = {}) {
2977
- const nested = {};
2978
- const media = {};
2979
- const baseDecls = {};
2980
- const mediaOverriddenProps = new Set;
2981
- for (const [prop, val] of Object.entries(styleDef)) {
2982
- if (prop.startsWith("@") && val && typeof val === "object") {
2983
- for (const k of Object.keys(val)) {
2984
- if (!k.startsWith(":") && !k.startsWith(".") && !k.startsWith("&") && !k.startsWith("[") && !k.startsWith("@")) {
2985
- 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);
2986
3490
  }
2987
3491
  }
2988
- }
2989
- }
2990
- for (const [prop, val] of Object.entries(styleDef)) {
2991
- if (val !== null && typeof val === "object" && !Array.isArray(val)) {
2992
- if (prop.startsWith("@")) {
2993
- media[prop] = val;
2994
- } else {
2995
- 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);
2996
3500
  }
2997
- continue;
2998
- }
2999
- if (prop.startsWith("@") || isNestedSelector(prop)) {
3000
- continue;
3001
- }
3002
- if (val === undefined) {
3003
- 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
+ `);
3004
3521
  }
3005
- const scalar = String(val);
3006
- if (prop.startsWith("--")) {
3007
- if (isTemplateString(val)) {
3008
- effect(() => {
3009
- el.style.setProperty(prop, canvasStyleValue(evaluateTemplate(val, state)));
3010
- });
3011
- } else {
3012
- 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();
3013
3546
  }
3014
- } else if (isTemplateString(val)) {
3015
- effect(() => {
3016
- el.style[prop] = canvasStyleValue(evaluateTemplate(val, state));
3017
- });
3018
- } else if (mediaOverriddenProps.has(prop)) {
3019
- baseDecls[prop] = scalar;
3020
- } else {
3021
- 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 ?? "";
3022
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 {}
3023
3569
  }
3024
- const hasNested = Object.keys(nested).length > 0;
3025
- const hasMedia = Object.keys(media).length > 0;
3026
- const hasBaseDecls = Object.keys(baseDecls).length > 0;
3027
- 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) {
3028
3596
  return;
3029
3597
  }
3030
- const uid = `jx-${Math.random().toString(36).slice(2, 7)}`;
3031
- el.dataset.jx = uid;
3032
- let css = "";
3033
- const baseCSS = toCSSText(baseDecls);
3034
- if (baseCSS) {
3035
- css += `[data-jx="${uid}"] { ${baseCSS} }
3036
- `;
3037
- }
3038
- function emitNested(scope, rules) {
3039
- const props = toCSSText(rules);
3040
- if (props) {
3041
- css += `${scope} { ${props} }
3042
- `;
3043
- }
3044
- for (const [sel, sub] of Object.entries(rules)) {
3045
- if (sub === null || typeof sub !== "object" || Array.isArray(sub)) {
3046
- continue;
3047
- }
3048
- if (sel.startsWith("@")) {
3049
- continue;
3050
- }
3051
- const resolved = sel.startsWith("&") ? sel.replace("&", scope) : sel.startsWith("[") ? `${scope}${sel}` : sel.startsWith(":") || sel.startsWith(".") ? `${scope}${sel}` : `${scope} ${sel}`;
3052
- emitNested(resolved, sub);
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;
3604
+ }
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);
3053
3637
  }
3638
+ } else {
3639
+ releaseInterned(state, state.interned, entry.interned);
3054
3640
  }
3055
- for (const [sel, rules] of Object.entries(nested)) {
3056
- 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}`;
3057
- emitNested(resolved, rules);
3641
+ for (const key of entry.hoisted) {
3642
+ releaseInterned(state, state.hoisted, key);
3058
3643
  }
3059
- function emitMediaNested(atRule, parentSel, obj) {
3060
- for (const [sel, sub] of Object.entries(obj)) {
3061
- if (sub === null || typeof sub !== "object" || Array.isArray(sub)) {
3062
- continue;
3063
- }
3064
- if (sel.startsWith("@")) {
3065
- 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;
3066
3698
  }
3067
- const resolved = sel.startsWith("&") ? sel.replace("&", parentSel) : sel.startsWith("[") ? `${parentSel}${sel}` : sel.startsWith(":") || sel.startsWith(".") ? `${parentSel}${sel}` : `${parentSel} ${sel}`;
3068
- const props = toCSSText(sub);
3069
- if (props) {
3070
- css += `${atRule} { ${resolved} { ${props} } }
3071
- `;
3699
+ if (serial < 0) {
3700
+ ({ serial } = sheetState);
3701
+ sheetState.serial += 1;
3072
3702
  }
3073
- emitMediaNested(atRule, resolved, sub);
3074
- }
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;
3075
3714
  }
3076
- for (const [key, rules] of Object.entries(media)) {
3077
- if (key === "@--") {
3078
- continue;
3079
- }
3080
- const query = resolveAtQuery(key, mediaQueries);
3081
- const atRule = query === null ? key : `@media ${query}`;
3082
- const scope = `[data-jx="${uid}"]`;
3083
- const scheme = query === null ? null : pureSchemeOf(query);
3084
- if (scheme) {
3085
- const { auto, forced } = schemeSelectors(scope, scheme);
3086
- css += `${atRule} { ${auto} { ${toCSSText(rules)} } }
3087
- `;
3088
- emitMediaNested(atRule, auto, rules);
3089
- 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);
3090
3728
  } else {
3091
- css += `${atRule} { ${scope} { ${toCSSText(rules)} } }
3092
- `;
3093
- emitMediaNested(atRule, scope, rules);
3729
+ retainInterned(sheetState, sheetState.interned, uid, texts);
3094
3730
  }
3095
3731
  }
3096
- const tag = document.createElement("style");
3097
- tag.textContent = css;
3098
- tag.dataset.jxOwner = uid;
3099
- document.head.append(tag);
3100
- elementStyleTags.set(el, tag);
3101
- }
3102
- var elementStyleTags = new WeakMap;
3103
- function reapplyStyle(el, styleDef, mediaQueries = {}, state = {}) {
3104
- const prev = elementStyleTags.get(el);
3105
- if (prev) {
3106
- prev.remove();
3107
- 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();
3108
3752
  }
3109
- el.style.cssText = "";
3110
- delete el.dataset.jx;
3111
- applyStyle(el, styleDef ?? {}, mediaQueries, state);
3753
+ elementStyles.set(el, entry);
3754
+ onScopeDispose(() => releaseElementStyles(el, entry), true);
3112
3755
  }
3113
3756
  var ENUMERATED_ATTRS = new Set(["contenteditable", "draggable", "spellcheck"]);
3114
3757
  function booleanAttrValue(name, value) {
@@ -3122,6 +3765,10 @@ function applyAttributes(el, attrs, state) {
3122
3765
  for (const [k, v] of Object.entries(attrs)) {
3123
3766
  const attr = canvasAttrName(el, k);
3124
3767
  const write = (resolved) => {
3768
+ if (resolved === null || resolved === undefined) {
3769
+ el.removeAttribute(attr);
3770
+ return;
3771
+ }
3125
3772
  if (typeof resolved === "boolean") {
3126
3773
  const text = booleanAttrValue(attr, resolved);
3127
3774
  if (text === null) {
@@ -3131,7 +3778,7 @@ function applyAttributes(el, attrs, state) {
3131
3778
  }
3132
3779
  return;
3133
3780
  }
3134
- el.setAttribute(attr, canvasAssetValue(el.tagName, k, String(resolved ?? "")));
3781
+ el.setAttribute(attr, canvasAssetValue(el.tagName, k, String(resolved)));
3135
3782
  };
3136
3783
  if (isRefObj(v)) {
3137
3784
  effect(() => write(resolveRef(v.$ref, state)));
@@ -3146,8 +3793,69 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
3146
3793
  const path = options?._path ?? [];
3147
3794
  const anchor = document.createComment("jx-array");
3148
3795
  parentEl.append(anchor);
3149
- const { items: itemsSrc, map: mapDef, filter: filterRef, sort: sortRef } = arrayDef;
3150
- 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 = () => {
3151
3859
  let items = isRefObj(itemsSrc) ? resolveRef(itemsSrc.$ref, state) : itemsSrc;
3152
3860
  if (Array.isArray(items) && isRefObj(filterRef)) {
3153
3861
  const fn = resolveRef(filterRef.$ref, state);
@@ -3161,30 +3869,65 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
3161
3869
  items = [...items].toSorted(fn);
3162
3870
  }
3163
3871
  }
3164
- if (!Array.isArray(items) || !mapDef) {
3165
- return;
3166
- }
3167
- const scope = effectScope(true);
3168
- const nodes = [];
3169
- scope.run(() => {
3170
- for (const [index, item] of items.entries()) {
3171
- const child = Object.create(state);
3172
- child.$map = { index, item };
3173
- child["$map/item"] = item;
3174
- child["$map/index"] = index;
3175
- const childOpts = options ? { ...options, _path: [...path, "map", index] } : undefined;
3176
- const node = renderNode(mapDef, child, childOpts);
3177
- anchor.before(node);
3178
- 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]);
3179
3881
  }
3180
- });
3181
- onEffectCleanup(() => {
3182
- scope.stop();
3183
- for (const n of nodes) {
3184
- 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;
3185
3896
  }
3186
- });
3897
+ queued = true;
3898
+ queueMicrotask(() => {
3899
+ queued = false;
3900
+ if (!stopped) {
3901
+ runner();
3902
+ }
3903
+ });
3904
+ }
3187
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;
3188
3931
  }
3189
3932
  function resolveTagName(tagName, scope) {
3190
3933
  if (typeof tagName === "string") {
@@ -3200,65 +3943,86 @@ function resolveTagName(tagName, scope) {
3200
3943
  const key = evaluateOperand(expression.target, scope, null);
3201
3944
  return expression.cases[String(key)] ?? expression.default;
3202
3945
  }
3203
- function renderSwitch(def2, state, options) {
3946
+ function renderSwitch(def, state, options) {
3204
3947
  const path = options?._path ?? [];
3205
- const container = document.createElement(resolveTagName(def2.tagName, state));
3948
+ const container = document.createElement(resolveTagName(def.tagName, state));
3206
3949
  if (options?.onNodeCreated) {
3207
- options.onNodeCreated(container, path, def2, state);
3950
+ options.onNodeCreated(container, path, def, state);
3208
3951
  }
3209
- applyProperties(container, def2, state);
3210
- applyStyle(container, def2.style ?? {}, state["$media"] ?? {}, state);
3211
- applyAttributes(container, def2.attributes ?? {}, state);
3952
+ applyProperties(container, def, state);
3953
+ applyStyle(container, def.style ?? {}, state["$media"] ?? {}, state);
3954
+ applyAttributes(container, def.attributes ?? {}, state);
3212
3955
  let generation = 0;
3956
+ let live = null;
3957
+ let renderedKey = null;
3958
+ const retire = () => {
3959
+ live?.stop();
3960
+ live = null;
3961
+ };
3213
3962
  effect(() => {
3214
- container.replaceChildren();
3215
- 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) {
3216
3971
  return;
3217
3972
  }
3218
- const key = resolveRef(def2.$switch.$ref, state);
3219
- const caseDef = def2.cases?.[key];
3973
+ renderedKey = key;
3974
+ retire();
3975
+ container.replaceChildren();
3976
+ generation += 1;
3977
+ const caseDef = def.cases?.[key];
3220
3978
  if (!caseDef) {
3221
3979
  return;
3222
3980
  }
3981
+ const gen = generation;
3982
+ const scope = effectScope(true);
3983
+ live = scope;
3984
+ const childOpts = options ? { ...options, _path: [...path, "cases", key] } : undefined;
3223
3985
  if (isRefObj(caseDef)) {
3224
- generation += 1;
3225
- const gen = generation;
3226
- const { href } = new URL(caseDef.$ref, location.href);
3227
- 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) => {
3228
3988
  if (gen !== generation) {
3229
3989
  return;
3230
3990
  }
3231
- const childScope = await buildScope(doc, {}, href);
3991
+ const childScope = await buildScope(doc, {}, href, options?._ctx);
3232
3992
  if (gen !== generation) {
3233
3993
  return;
3234
3994
  }
3235
3995
  container.replaceChildren();
3236
- const childOpts2 = options ? { ...options, _path: [...path, "cases", key] } : undefined;
3237
- container.append(renderNode(doc, childScope, childOpts2));
3996
+ scope.run(() => container.append(renderNode(doc, childScope, childOpts)));
3238
3997
  }).catch((error) => console.error("Jx $switch: failed to load external case", caseDef.$ref, error));
3239
3998
  return;
3240
3999
  }
3241
- const childOpts = options ? { ...options, _path: [...path, "cases", key] } : undefined;
3242
- container.append(renderNode(caseDef, state, childOpts));
4000
+ pauseTracking();
4001
+ try {
4002
+ scope.run(() => container.append(renderNode(caseDef, state, childOpts)));
4003
+ } finally {
4004
+ resetTracking();
4005
+ }
3243
4006
  });
4007
+ onScopeDispose(retire, true);
3244
4008
  return container;
3245
4009
  }
3246
- async function resolvePrototype(def2, state, key, base) {
3247
- if (def2.$src) {
3248
- 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);
3249
4013
  }
3250
- switch (def2.$prototype) {
4014
+ switch (def.$prototype) {
3251
4015
  case "Request": {
3252
4016
  const s = ref(null);
3253
- const debounceMs = def2.debounce ?? 0;
4017
+ const debounceMs = def.debounce ?? 0;
3254
4018
  let debounceTimer = null;
3255
- if (!def2.manual && !_autoRequestConfig.skip) {
4019
+ if (!def.manual && !(ctx?.skipAutoRequests ?? _autoRequestConfig.skip)) {
3256
4020
  effect(() => {
3257
4021
  let url;
3258
- if (isTemplateString(def2.url)) {
3259
- url = evaluateTemplate(def2.url, state);
4022
+ if (isTemplateString(def.url)) {
4023
+ url = evaluateTemplate(def.url, state);
3260
4024
  } else {
3261
- ({ url } = def2);
4025
+ ({ url } = def);
3262
4026
  }
3263
4027
  if (!url || url === "undefined" || url.includes("undefined")) {
3264
4028
  return;
@@ -3271,11 +4035,11 @@ async function resolvePrototype(def2, state, key, base) {
3271
4035
  }
3272
4036
  });
3273
4037
  const doFetch = () => fetch(url, {
3274
- method: def2.method ?? "GET",
4038
+ method: def.method ?? "GET",
3275
4039
  signal: controller.signal,
3276
- ...def2.headers && { headers: def2.headers },
3277
- ...def2.body && {
3278
- 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
3279
4043
  }
3280
4044
  }).then((r) => r.ok ? r.json() : Promise.reject(r.statusText)).then((d) => {
3281
4045
  s.value = d;
@@ -3296,7 +4060,7 @@ async function resolvePrototype(def2, state, key, base) {
3296
4060
  case "URLSearchParams": {
3297
4061
  return computed(() => {
3298
4062
  const p = {};
3299
- for (const [k, v] of Object.entries(def2)) {
4063
+ for (const [k, v] of Object.entries(def)) {
3300
4064
  if (k !== "$prototype") {
3301
4065
  p[k] = isRefObj(v) ? resolveRef(v.$ref, state) : isTemplateString(v) ? evaluateTemplate(v, state) : v;
3302
4066
  }
@@ -3306,14 +4070,14 @@ async function resolvePrototype(def2, state, key, base) {
3306
4070
  }
3307
4071
  case "LocalStorage":
3308
4072
  case "SessionStorage": {
3309
- const store = def2.$prototype === "LocalStorage" ? localStorage : sessionStorage;
3310
- const k = def2.key ?? key;
4073
+ const store = def.$prototype === "LocalStorage" ? localStorage : sessionStorage;
4074
+ const k = def.key ?? key;
3311
4075
  let init;
3312
4076
  try {
3313
4077
  const s = store.getItem(k);
3314
- init = s !== null ? JSON.parse(s) : def2.default ?? null;
4078
+ init = s !== null ? JSON.parse(s) : def.default ?? null;
3315
4079
  } catch {
3316
- init = def2.default ?? null;
4080
+ init = def.default ?? null;
3317
4081
  }
3318
4082
  const storageState = ref(init);
3319
4083
  effect(() => {
@@ -3331,7 +4095,7 @@ async function resolvePrototype(def2, state, key, base) {
3331
4095
  return storageState;
3332
4096
  }
3333
4097
  case "Cookie": {
3334
- const name = def2.name ?? key;
4098
+ const name = def.name ?? key;
3335
4099
  const read = () => {
3336
4100
  const raw = readCookie(document.cookie, name);
3337
4101
  if (raw === null) {
@@ -3343,9 +4107,9 @@ async function resolvePrototype(def2, state, key, base) {
3343
4107
  return raw;
3344
4108
  }
3345
4109
  };
3346
- const cookieState = ref(read() ?? def2.default ?? null);
4110
+ const cookieState = ref(read() ?? def.default ?? null);
3347
4111
  effect(() => {
3348
- document.cookie = serializeCookie(name, cookieState.value, def2);
4112
+ document.cookie = serializeCookie(name, cookieState.value, def);
3349
4113
  });
3350
4114
  return cookieState;
3351
4115
  }
@@ -3358,7 +4122,7 @@ async function resolvePrototype(def2, state, key, base) {
3358
4122
  keyPath = "id",
3359
4123
  autoIncrement = true,
3360
4124
  indexes = []
3361
- } = def2;
4125
+ } = def;
3362
4126
  if (!database || !store) {
3363
4127
  throw new Error(`Jx: IndexedDB entry '${key}' requires database and store`);
3364
4128
  }
@@ -3388,28 +4152,28 @@ async function resolvePrototype(def2, state, key, base) {
3388
4152
  return idbState;
3389
4153
  }
3390
4154
  case "Set": {
3391
- return new Set(Array.isArray(def2.default) ? def2.default : []);
4155
+ return new Set(Array.isArray(def.default) ? def.default : []);
3392
4156
  }
3393
4157
  case "Map": {
3394
- return new Map(Object.entries(isJsonObject(def2.default) ? def2.default : {}));
4158
+ return new Map(Object.entries(isJsonObject(def.default) ? def.default : {}));
3395
4159
  }
3396
4160
  case "FormData": {
3397
4161
  const fd = new FormData;
3398
- for (const [k, v] of Object.entries(def2.fields ?? {})) {
4162
+ for (const [k, v] of Object.entries(def.fields ?? {})) {
3399
4163
  fd.append(k, v);
3400
4164
  }
3401
4165
  return fd;
3402
4166
  }
3403
4167
  case "Blob": {
3404
- return new Blob(def2.parts ?? [], {
3405
- 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"
3406
4170
  });
3407
4171
  }
3408
4172
  case "ReadableStream": {
3409
4173
  return null;
3410
4174
  }
3411
4175
  default: {
3412
- 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'?`);
3413
4177
  return ref(null);
3414
4178
  }
3415
4179
  }
@@ -3426,17 +4190,20 @@ var EXTERNAL_RESERVED = new Set([
3426
4190
  "arguments",
3427
4191
  "name"
3428
4192
  ]);
3429
- async function resolveExternalPrototype(def2, state, key, base) {
3430
- const src = def2.$src;
4193
+ async function resolveExternalPrototype(def, state, key, base) {
4194
+ const src = def.$src;
3431
4195
  if (!src || !src.endsWith(".class.json")) {
3432
- 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.`);
3433
4197
  }
3434
- return resolveClassJson(def2, state, key, base);
4198
+ return resolveClassJson(def, state, key, base);
3435
4199
  }
3436
- async function importAndInstantiate(def2, src, exportName, base) {
4200
+ async function importAndInstantiate(def, src, exportName, base) {
3437
4201
  let mod;
3438
- if (_moduleCache.has(src)) {
3439
- 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;
3440
4207
  } else {
3441
4208
  try {
3442
4209
  mod = await import(src);
@@ -3458,7 +4225,7 @@ async function importAndInstantiate(def2, src, exportName, base) {
3458
4225
  throw new TypeError(`Jx: "${exportName}" from "${src}" is not a class`);
3459
4226
  }
3460
4227
  const config = {};
3461
- for (const [k, v] of Object.entries(def2)) {
4228
+ for (const [k, v] of Object.entries(def)) {
3462
4229
  if (!EXTERNAL_RESERVED.has(k)) {
3463
4230
  config[k] = v;
3464
4231
  }
@@ -3481,15 +4248,15 @@ async function importAndInstantiate(def2, src, exportName, base) {
3481
4248
  }
3482
4249
  return s;
3483
4250
  }
3484
- async function resolveClassJson(def2, state, key, base) {
3485
- const src = def2.$src;
4251
+ async function resolveClassJson(def, state, key, base) {
4252
+ const src = def.$src;
3486
4253
  if (!src) {
3487
4254
  throw new Error(`Jx: class entry '${key}' has no $src`);
3488
4255
  }
3489
4256
  let classDef;
3490
4257
  const isBareSpecifier = !src.startsWith(".") && !src.startsWith("/") && !src.startsWith("http") && !src.startsWith("file:");
3491
4258
  if (isBareSpecifier) {
3492
- return resolveViaDevProxy(def2, state, key, base);
4259
+ return resolveViaDevProxy(def, state, key, base);
3493
4260
  }
3494
4261
  try {
3495
4262
  const url = base ? new URL(src, base).href : src;
@@ -3499,25 +4266,25 @@ async function resolveClassJson(def2, state, key, base) {
3499
4266
  }
3500
4267
  classDef = await res.json();
3501
4268
  } catch {
3502
- return resolveViaDevProxy(def2, state, key, base);
4269
+ return resolveViaDevProxy(def, state, key, base);
3503
4270
  }
3504
4271
  if (classDef.$implementation) {
3505
4272
  const schemaStr = JSON.stringify(classDef);
3506
4273
  if (schemaStr.includes('"#/$context/')) {
3507
- return resolveViaDevProxy(def2, state, key, base);
4274
+ return resolveViaDevProxy(def, state, key, base);
3508
4275
  }
3509
4276
  const schemaUrl = base ? new URL(src, base).href : new URL(src, location.href).href;
3510
4277
  const implSrc = new URL(classDef.$implementation, schemaUrl).href;
3511
- const exportName = def2.$export ?? classDef.title ?? def2.$prototype;
4278
+ const exportName = def.$export ?? classDef.title ?? def.$prototype;
3512
4279
  try {
3513
- return await importAndInstantiate(def2, implSrc, exportName, base);
4280
+ return await importAndInstantiate(def, implSrc, exportName, base);
3514
4281
  } catch {
3515
- return resolveViaDevProxy(def2, state, key, base);
4282
+ return resolveViaDevProxy(def, state, key, base);
3516
4283
  }
3517
4284
  }
3518
4285
  const DynClass = classFromSchema(classDef);
3519
4286
  const config = {};
3520
- for (const [k, v] of Object.entries(def2)) {
4287
+ for (const [k, v] of Object.entries(def)) {
3521
4288
  if (!EXTERNAL_RESERVED.has(k)) {
3522
4289
  config[k] = v;
3523
4290
  }
@@ -3604,9 +4371,9 @@ function classFromSchema(classDef) {
3604
4371
  const dynCtor = DynClass;
3605
4372
  return dynCtor;
3606
4373
  }
3607
- async function resolveViaDevProxy(def2, state, key, base) {
4374
+ async function resolveViaDevProxy(def, state, key, base) {
3608
4375
  const config = {};
3609
- for (const [k, v] of Object.entries(def2)) {
4376
+ for (const [k, v] of Object.entries(def)) {
3610
4377
  if (!EXTERNAL_RESERVED.has(k)) {
3611
4378
  config[k] = v;
3612
4379
  }
@@ -3615,9 +4382,9 @@ async function resolveViaDevProxy(def2, state, key, base) {
3615
4382
  const doResolve = (resolvedConfig) => fetch(resolveProxyPath("/__jx_resolve__"), {
3616
4383
  body: JSON.stringify({
3617
4384
  $base: base,
3618
- $export: def2.$export,
3619
- $prototype: def2.$prototype,
3620
- $src: def2.$src,
4385
+ $export: def.$export,
4386
+ $prototype: def.$prototype,
4387
+ $src: def.$src,
3621
4388
  ...resolvedConfig
3622
4389
  }),
3623
4390
  headers: { "Content-Type": "application/json" },
@@ -3646,12 +4413,15 @@ async function resolveViaDevProxy(def2, state, key, base) {
3646
4413
  }
3647
4414
  return s;
3648
4415
  }
3649
- async function resolveServerFunction(def2, state, key, base) {
3650
- const src = def2.$src;
3651
- const exportName = def2.$export;
4416
+ async function resolveServerFunction(def, state, key, base) {
4417
+ const src = def.$src;
4418
+ const exportName = def.$export;
3652
4419
  let mod;
3653
- if (_moduleCache.has(src)) {
3654
- 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;
3655
4425
  } else {
3656
4426
  try {
3657
4427
  mod = await import(src);
@@ -3661,10 +4431,10 @@ async function resolveServerFunction(def2, state, key, base) {
3661
4431
  const resolvedSrc = new URL(src, base).href;
3662
4432
  mod = await import(resolvedSrc);
3663
4433
  } catch {
3664
- return resolveServerFunctionViaProxy(def2, state, key, base);
4434
+ return resolveServerFunctionViaProxy(def, state, key, base);
3665
4435
  }
3666
4436
  } else {
3667
- return resolveServerFunctionViaProxy(def2, state, key, base);
4437
+ return resolveServerFunctionViaProxy(def, state, key, base);
3668
4438
  }
3669
4439
  }
3670
4440
  _moduleCache.set(src, mod);
@@ -3677,7 +4447,7 @@ async function resolveServerFunction(def2, state, key, base) {
3677
4447
  throw new TypeError(`Jx: "${exportName}" from "${src}" is not a function`);
3678
4448
  }
3679
4449
  const fn = candidate;
3680
- const rawArgs = def2.arguments ?? {};
4450
+ const rawArgs = def.arguments ?? {};
3681
4451
  const hasReactiveArg = Object.values(rawArgs).some((v) => isRefObj(v));
3682
4452
  const resolveArgs = () => {
3683
4453
  const args = {};
@@ -3700,8 +4470,8 @@ async function resolveServerFunction(def2, state, key, base) {
3700
4470
  }
3701
4471
  return s;
3702
4472
  }
3703
- async function resolveServerFunctionViaProxy(def2, state, key, base) {
3704
- const rawArgs = def2.arguments ?? {};
4473
+ async function resolveServerFunctionViaProxy(def, state, key, base) {
4474
+ const rawArgs = def.arguments ?? {};
3705
4475
  const hasReactiveArg = Object.values(rawArgs).some((v) => isRefObj(v));
3706
4476
  const resolveArgs = () => {
3707
4477
  const args = {};
@@ -3713,8 +4483,8 @@ async function resolveServerFunctionViaProxy(def2, state, key, base) {
3713
4483
  const doResolve = (args) => fetch(resolveProxyPath("/__jx_server__"), {
3714
4484
  body: JSON.stringify({
3715
4485
  $base: base,
3716
- $export: def2.$export,
3717
- $src: def2.$src,
4486
+ $export: def.$export,
4487
+ $src: def.$src,
3718
4488
  arguments: args
3719
4489
  }),
3720
4490
  headers: { "Content-Type": "application/json" },
@@ -3745,8 +4515,8 @@ function resolveRef(refPath, state) {
3745
4515
  if (typeof refPath !== "string") {
3746
4516
  return refPath;
3747
4517
  }
3748
- if (refPath.startsWith("$map/")) {
3749
- const parts = refPath.split("/");
4518
+ if (refPath.startsWith("$map/") || refPath.startsWith("#/$map/")) {
4519
+ const parts = (refPath.startsWith("#/") ? refPath.slice(2) : refPath).split("/");
3750
4520
  const [, key] = parts;
3751
4521
  const map = state.$map;
3752
4522
  const base = map?.[key] ?? state[`$map/${key}`];
@@ -3769,12 +4539,41 @@ function resolveRef(refPath, state) {
3769
4539
  function isRefObj(v) {
3770
4540
  return isRef(v);
3771
4541
  }
3772
- function isNestedSelector(k) {
3773
- return k.startsWith(":") || k.startsWith(".") || k.startsWith("&") || k.startsWith("[");
3774
- }
3775
4542
  function getPath2(obj, path) {
3776
4543
  return readPath(obj, path);
3777
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"];
3778
4577
  var _privatePropWarned = new Set;
3779
4578
  function instanceSupplies(el, key) {
3780
4579
  if (Object.hasOwn(el, key)) {
@@ -3797,9 +4596,9 @@ function refusePrivateProp(key, where) {
3797
4596
  }
3798
4597
  return true;
3799
4598
  }
3800
- function mergeProps(def2, parentState) {
4599
+ function mergeProps(def, parentState) {
3801
4600
  const child = Object.create(parentState);
3802
- for (const [k, v] of Object.entries(def2.$props ?? {})) {
4601
+ for (const [k, v] of Object.entries(def.$props ?? {})) {
3803
4602
  if (refusePrivateProp(k, "$props")) {
3804
4603
  continue;
3805
4604
  }
@@ -3807,46 +4606,32 @@ function mergeProps(def2, parentState) {
3807
4606
  }
3808
4607
  return child;
3809
4608
  }
3810
- function camelToKebab(s) {
3811
- return s.replaceAll(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
3812
- }
3813
- function toCSSText(rules) {
3814
- return Object.entries(rules).filter(([k, v]) => !isNestedSelector(k) && (v === null || typeof v !== "object")).map(([p, v]) => `${camelToKebab(p)}: ${canvasStyleValue(String(v))}`).join("; ");
3815
- }
3816
- var MEDIA_TYPES = new Set(["all", "print", "screen", "speech"]);
3817
- function resolveAtQuery(atKey, mediaQueries) {
3818
- if (atKey.startsWith("@--")) {
3819
- return mediaQueries[atKey.slice(1)] ?? atKey.slice(1);
4609
+ var _rootMedia = {};
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`);
3820
4616
  }
3821
- if (atKey.startsWith("@(")) {
3822
- const inner = atKey.slice(2, -1).trim();
3823
- return MEDIA_TYPES.has(inner.toLowerCase()) ? inner : atKey.slice(1);
4617
+ if (!customElements.get(tagName)) {
4618
+ await defineElement(doc, base);
4619
+ return;
3824
4620
  }
3825
- return null;
3826
- }
3827
- var COLOR_SCHEME_ATTR = "data-color-scheme";
3828
- function pureSchemeOf(query) {
3829
- const m = /^\(\s*prefers-color-scheme\s*:\s*(light|dark)\s*\)$/.exec(query.trim());
3830
- return m?.[1] ?? null;
3831
- }
3832
- function schemeSelectors(selector, scheme) {
3833
- if (selector === ":root" || selector === "html") {
3834
- return {
3835
- auto: `${selector}:where(:not([${COLOR_SCHEME_ATTR}]))`,
3836
- forced: `${selector}:where([${COLOR_SCHEME_ATTR}="${scheme}"])`
3837
- };
4621
+ if (doc.$elements) {
4622
+ await registerElements(doc.$elements, base);
3838
4623
  }
3839
- return {
3840
- auto: `:where(:root:not([${COLOR_SCHEME_ATTR}])) ${selector}`,
3841
- forced: `:where(:root[${COLOR_SCHEME_ATTR}="${scheme}"]) ${selector}`
3842
- };
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 });
3843
4630
  }
3844
- var _rootMedia = {};
3845
- var _elementDefs = new Map;
3846
4631
  function setRootMedia(map) {
3847
4632
  _rootMedia = map ?? {};
3848
4633
  }
3849
- async function registerElements(elements, base) {
4634
+ async function registerElements(elements, base, ctx) {
3850
4635
  for (const entry of elements) {
3851
4636
  if (typeof entry === "string") {
3852
4637
  try {
@@ -3861,7 +4646,7 @@ async function registerElements(elements, base) {
3861
4646
  continue;
3862
4647
  }
3863
4648
  const { href } = new URL(entry.$ref, base);
3864
- const doc = await resolve(href);
4649
+ const doc = await resolve(href, ctx);
3865
4650
  if (!doc.tagName || !doc.tagName.includes("-")) {
3866
4651
  continue;
3867
4652
  }
@@ -3869,7 +4654,7 @@ async function registerElements(elements, base) {
3869
4654
  continue;
3870
4655
  }
3871
4656
  if (doc.$elements) {
3872
- await registerElements(doc.$elements, href);
4657
+ await registerElements(doc.$elements, href, ctx);
3873
4658
  }
3874
4659
  await defineElement(doc, href);
3875
4660
  }
@@ -3899,8 +4684,9 @@ async function defineElement(source, baseUrl) {
3899
4684
  await registerElements(source_.$elements, base);
3900
4685
  }
3901
4686
  _elementDefs.set(tagName, { base, doc: source_ });
3902
- const def2 = source_;
3903
- const observedAttrs = def2.observedAttributes ?? [];
4687
+ const initialDef = source_;
4688
+ const initialBase = base;
4689
+ const observedAttrs = initialDef.observedAttributes ?? [];
3904
4690
  const ElementClass = class extends HTMLElement {
3905
4691
  _jxInitialized = false;
3906
4692
  _state = null;
@@ -3915,7 +4701,15 @@ async function defineElement(source, baseUrl) {
3915
4701
  return;
3916
4702
  }
3917
4703
  this._jxInitialized = true;
3918
- 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
+ }
3919
4713
  const propsAttr = this.dataset.jxProps;
3920
4714
  if (propsAttr) {
3921
4715
  try {
@@ -3924,7 +4718,7 @@ async function defineElement(source, baseUrl) {
3924
4718
  if (refusePrivateProp(key, "data-jx-props")) {
3925
4719
  continue;
3926
4720
  }
3927
- if (key in (def2.state ?? {})) {
4721
+ if (key in (def.state ?? {})) {
3928
4722
  state[key] = val;
3929
4723
  }
3930
4724
  }
@@ -3938,12 +4732,12 @@ async function defineElement(source, baseUrl) {
3938
4732
  this.removeAttribute(name);
3939
4733
  continue;
3940
4734
  }
3941
- if (key in (def2.state ?? {})) {
4735
+ if (key in (def.state ?? {})) {
3942
4736
  state[key] = this.getAttribute(name);
3943
4737
  this.removeAttribute(name);
3944
4738
  }
3945
4739
  }
3946
- for (const key of Object.keys(def2.state ?? {})) {
4740
+ for (const key of Object.keys(def.state ?? {})) {
3947
4741
  if (isPrivateStateKey(key)) {
3948
4742
  continue;
3949
4743
  }
@@ -3951,7 +4745,7 @@ async function defineElement(source, baseUrl) {
3951
4745
  state[key] = this[key];
3952
4746
  }
3953
4747
  }
3954
- for (const key of Object.keys(def2.state ?? {})) {
4748
+ for (const key of Object.keys(def.state ?? {})) {
3955
4749
  if (isPrivateStateKey(key)) {
3956
4750
  continue;
3957
4751
  }
@@ -3968,22 +4762,28 @@ async function defineElement(source, baseUrl) {
3968
4762
  this._state = state;
3969
4763
  const slottedChildren = [...this.childNodes];
3970
4764
  this.replaceChildren();
3971
- if (!this.style.display) {
3972
- this.style.display = "block";
3973
- }
3974
- applyStyle(this, def2.style ?? {}, state["$media"] ?? {}, state);
3975
- applyAttributes(this, def2.attributes ?? {}, state);
3976
- if (!Array.isArray(def2.children) && def2.textContent !== undefined) {
3977
- bindProperty(this, "textContent", def2.textContent, state);
3978
- }
3979
- const children = Array.isArray(def2.children) ? def2.children : [];
3980
- for (const childDef of children) {
3981
- 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;
3982
4782
  }
3983
4783
  distributeSlots(this, slottedChildren);
3984
4784
  const { onMount } = state;
3985
4785
  if (typeof onMount === "function") {
3986
- queueMicrotask(() => onMount(state));
4786
+ queueMicrotask(() => onMount(state, this));
3987
4787
  }
3988
4788
  }
3989
4789
  disconnectedCallback() {
@@ -4000,25 +4800,17 @@ async function defineElement(source, baseUrl) {
4000
4800
  if (!this._state || oldVal === newVal) {
4001
4801
  return;
4002
4802
  }
4003
- const camelKey = name.replaceAll(/-([a-z])/g, (_, c) => c.toUpperCase());
4004
- const current = this._state[camelKey];
4005
- if (typeof current === "number") {
4006
- this._state[camelKey] = Number(newVal);
4007
- } else if (typeof current === "boolean") {
4008
- this._state[camelKey] = newVal !== null && newVal !== "false";
4009
- } else {
4010
- this._state[camelKey] = newVal;
4011
- }
4803
+ absorbAttribute(this._state, name, newVal, declaredDefaults(_elementDefs.get(tagName)?.doc ?? initialDef));
4012
4804
  }
4013
4805
  };
4014
4806
  customElements.define(tagName, ElementClass);
4015
4807
  }
4016
- function renderCustomElementWithProps(def2, state, options, path) {
4017
- const el = document.createElement(resolveTagName(def2.tagName, state));
4808
+ function renderCustomElementWithProps(def, state, options, path) {
4809
+ const el = document.createElement(resolveTagName(def.tagName, state));
4018
4810
  if (options?.onNodeCreated) {
4019
- options.onNodeCreated(el, path ?? [], def2, state);
4811
+ options.onNodeCreated(el, path ?? [], def, state);
4020
4812
  }
4021
- for (const [key, val] of Object.entries(def2.$props ?? {})) {
4813
+ for (const [key, val] of Object.entries(def.$props ?? {})) {
4022
4814
  if (refusePrivateProp(key, "$props")) {
4023
4815
  continue;
4024
4816
  }
@@ -4039,19 +4831,25 @@ function renderCustomElementWithProps(def2, state, options, path) {
4039
4831
  write(val);
4040
4832
  }
4041
4833
  }
4042
- applyStyle(el, def2.style ?? {}, state["$media"] ?? {}, state);
4043
- applyAttributes(el, def2.attributes ?? {}, state);
4044
- 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 : [];
4045
4841
  for (let i = 0;i < children.length; i++) {
4842
+ const child = children[i];
4046
4843
  const childOpts = options && path ? { ...options, _path: [...path, "children", i] } : undefined;
4047
- 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
+ }
4048
4849
  }
4049
4850
  return el;
4050
4851
  }
4051
4852
  function distributeSlots(host, slottedChildren) {
4052
- if (slottedChildren.length === 0) {
4053
- return;
4054
- }
4055
4853
  const slots = host.querySelectorAll("slot");
4056
4854
  if (slots.length === 0) {
4057
4855
  return;
@@ -4072,12 +4870,7 @@ function distributeSlots(host, slottedChildren) {
4072
4870
  for (const slot of slots) {
4073
4871
  const name = slot.getAttribute("name");
4074
4872
  const matches = name ? named.get(name) ?? [] : unnamed;
4075
- if (matches.length > 0) {
4076
- slot.replaceChildren();
4077
- for (const child of matches) {
4078
- slot.append(child);
4079
- }
4080
- }
4873
+ slot.replaceWith(...matches.length > 0 ? matches : [...slot.childNodes]);
4081
4874
  }
4082
4875
  }
4083
4876
 
@@ -4123,14 +4916,18 @@ function mountedRefFor(value, entryDir, mount) {
4123
4916
  }
4124
4917
 
4125
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
+ }
4126
4923
  function wrapsPageContent(path, prefix) {
4127
4924
  if (!prefix) {
4128
4925
  return false;
4129
4926
  }
4130
4927
  return path.length <= prefix.length && path.every((seg, i) => prefix[i] === seg);
4131
4928
  }
4132
- function classifyRenderNode(path, def2, ctx) {
4133
- 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;
4134
4931
  if (marker) {
4135
4932
  const origin = typeof marker === "object" ? marker : {};
4136
4933
  return {
@@ -4149,7 +4946,7 @@ function classifyRenderNode(path, def2, ctx) {
4149
4946
  mappedPath = typeof containerIdx === "number" ? ["children", containerIdx - (ctx.pageContentOffset ?? 0), ...rest.slice(1)] : ["children", ...rest];
4150
4947
  }
4151
4948
  }
4152
- if ((ctx.canvasMode === "design" || ctx.canvasMode === "edit") && ctx.arrayPaths.size > 0) {
4949
+ if (ctx.arrayPaths.size > 0) {
4153
4950
  let changed = true;
4154
4951
  while (changed) {
4155
4952
  changed = false;
@@ -4171,57 +4968,159 @@ function parseJxPath(serialized) {
4171
4968
  return JSON.parse(serialized);
4172
4969
  }
4173
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
+
4174
5075
  // ../site/src/site-style.ts
4175
5076
  var SITE_STYLE_ID = "jx-site-style";
4176
- function toDecls(props, transpose) {
4177
- return Object.entries(props).map(([key, value]) => `${camelToKebab(key)}: ${transpose(String(value))}`).join("; ");
4178
- }
4179
5077
  function buildSiteStyleCSS(siteStyle, mediaQueries, transpose) {
4180
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
+ };
4181
5088
  const rootProps = {};
4182
5089
  const bodyProps = {};
4183
5090
  const condBlocks = [];
5091
+ const selectorBlocks = [];
4184
5092
  for (const [key, value] of Object.entries(siteStyle)) {
4185
5093
  if (value !== null && typeof value === "object" && !Array.isArray(value)) {
4186
5094
  if (key.startsWith("@")) {
4187
5095
  condBlocks.push([key, value]);
5096
+ } else if (!key.startsWith("--")) {
5097
+ selectorBlocks.push([key, value]);
4188
5098
  }
4189
5099
  continue;
4190
5100
  }
4191
- if (key.startsWith(":") || key.startsWith(".") || key.startsWith("[") || key.startsWith("@")) {
5101
+ if (isNestedSelectorKey(key) || key.startsWith("@")) {
4192
5102
  continue;
4193
5103
  }
4194
- if (key.startsWith("--")) {
5104
+ if (key.startsWith("--") || key === "colorScheme" || key === "color-scheme") {
4195
5105
  rootProps[key] = value;
4196
5106
  } else {
4197
5107
  bodyProps[key] = value;
4198
5108
  }
4199
5109
  }
4200
- const rootCSS = toDecls(rootProps, transpose);
4201
- if (rootCSS) {
4202
- rules.push(`:root { ${rootCSS} }`);
4203
- }
4204
- const bodyCSS = toDecls(bodyProps, transpose);
4205
- if (bodyCSS) {
4206
- rules.push(`body { ${bodyCSS} }`);
4207
- }
4208
- for (const [atKey, block] of condBlocks) {
4209
- const query = resolveAtQuery(atKey, mediaQueries);
4210
- if (query === null) {
4211
- 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;
4212
5123
  }
4213
- const scheme = pureSchemeOf(query);
4214
- const emit = (selector, props) => {
4215
- if (!props) {
4216
- return;
4217
- }
4218
- if (scheme) {
4219
- const { auto, forced } = schemeSelectors(selector, scheme);
4220
- rules.push(`@media ${query} { ${auto} { ${props} } }`, `${forced} { ${props} }`);
4221
- } else {
4222
- rules.push(`@media ${query} { ${selector} { ${props} } }`);
4223
- }
4224
- };
4225
5124
  const condRoot = {};
4226
5125
  const condBody = {};
4227
5126
  const condSubs = [];
@@ -4238,14 +5137,14 @@ function buildSiteStyleCSS(siteStyle, mediaQueries, transpose) {
4238
5137
  condBody[k] = v;
4239
5138
  }
4240
5139
  }
4241
- emit(":root", toDecls(condRoot, transpose));
4242
- emit("body", toDecls(condBody, transpose));
5140
+ push({ [atKey]: condRoot }, ":root");
5141
+ push({ [atKey]: condBody }, "body");
4243
5142
  for (const [sel, sub] of condSubs) {
4244
- emit(sel, toDecls(sub, transpose));
5143
+ push({ [atKey]: sub }, sel);
4245
5144
  }
4246
5145
  }
4247
- if (Object.values(mediaQueries).some((q) => pureSchemeOf(q) !== null)) {
4248
- 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 }`);
4249
5148
  }
4250
5149
  return rules.join(`
4251
5150
  `);
@@ -4385,6 +5284,196 @@ function syncEditModeCss(doc, mode) {
4385
5284
  style.textContent = EDIT_PLACEHOLDER_CSS;
4386
5285
  doc.head.append(style);
4387
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
+ }
4388
5477
  function syncPreviewShell(doc, mode) {
4389
5478
  doc.documentElement.toggleAttribute("data-jx-preview", mode === "preview");
4390
5479
  }
@@ -4527,6 +5616,30 @@ function applyPreviewColorScheme(doc, scheme) {
4527
5616
  delete doc.documentElement.dataset.colorScheme;
4528
5617
  }
4529
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
+ }
4530
5643
  function injectHead(doc, assets = null) {
4531
5644
  const head = doc.$head;
4532
5645
  if (!Array.isArray(head)) {
@@ -4569,11 +5682,11 @@ function injectHead(doc, assets = null) {
4569
5682
  function makeStamper(ctx) {
4570
5683
  const islands = [];
4571
5684
  const insideIsland = (path) => islands.some((island) => path.length > island.length && island.every((seg, i) => path[i] === seg));
4572
- return (created, path, def2) => {
5685
+ return (created, path, def) => {
4573
5686
  if (!(created instanceof HTMLElement)) {
4574
5687
  return;
4575
5688
  }
4576
- const isDefinitionRoot = path.length === 0 && def2?.tagName?.includes("-");
5689
+ const isDefinitionRoot = path.length === 0 && def?.tagName?.includes("-");
4577
5690
  if (isDefinitionRoot) {
4578
5691
  created.dataset.jxDefinitionRoot = "";
4579
5692
  }
@@ -4582,7 +5695,7 @@ function makeStamper(ctx) {
4582
5695
  created.contentEditable = "false";
4583
5696
  islands.push(path);
4584
5697
  }
4585
- const classified = classifyRenderNode(path, def2, ctx);
5698
+ const classified = classifyRenderNode(path, def, ctx);
4586
5699
  if (classified.kind === "layout") {
4587
5700
  created.dataset.jxLayoutPath = serializeJxPath(classified.layoutPath);
4588
5701
  if (classified.layoutFile) {
@@ -4633,36 +5746,32 @@ async function renderResolvedDocument(opts) {
4633
5746
  setSkipAutoRequests(opts.mode !== "preview" && !opts.allowAutoRequests);
4634
5747
  setCanvasViewportTranspose(true);
4635
5748
  setCanvasDelinkAnchors(opts.mode !== "preview");
5749
+ setCanvasDelinkPopovers(opts.mode !== "preview");
5750
+ setCanvasDelinkCommands(opts.mode !== "preview");
4636
5751
  setStampPropBindings(opts.mode === "design" || opts.mode === "edit");
4637
5752
  applySiteStyle(opts.siteStyle, opts.doc.$media ?? {});
4638
5753
  injectHead(opts.doc, assets);
4639
5754
  syncEditModeCss(opts.container.ownerDocument, opts.mode);
5755
+ syncCanvasOverlayCss(opts.container.ownerDocument, opts.mode);
4640
5756
  syncPreviewShell(opts.container.ownerDocument, opts.mode);
4641
5757
  syncStylebookCss(opts.container.ownerDocument, opts.mode);
5758
+ syncDiffCss(opts.container.ownerDocument, Boolean(opts.diffMarks?.length));
4642
5759
  setRootMedia(opts.doc.$media ?? {});
4643
5760
  await registerElements2(opts.doc, opts.docBase);
4644
5761
  const $defs = await buildScope(opts.doc, {}, opts.docBase);
4645
5762
  const onNodeCreated = makeStamper(opts.mapperCtx);
4646
5763
  const { result: el, stop } = runScoped(() => renderNode(opts.doc, $defs, { _path: [], onNodeCreated }));
4647
5764
  opts.container.replaceChildren(el);
5765
+ applyCanvasPopoverOpen(opts.container, opts.popoverOpen ?? null);
5766
+ applyCanvasDialogOpen(opts.container, opts.dialogOpen ?? null);
4648
5767
  syncEditableRoot(opts.container, opts.mode);
5768
+ applyDiffMarks(opts.container, opts.diffMarks ?? null);
4649
5769
  return {
4650
5770
  ctx: { defs: $defs, docBase: opts.docBase, mapperCtx: opts.mapperCtx, mode: opts.mode },
4651
5771
  dispose: stop
4652
5772
  };
4653
5773
  }
4654
5774
 
4655
- // src/utils/geometry.ts
4656
- function rectOf(el) {
4657
- return el.getBoundingClientRect();
4658
- }
4659
- function rectOfRange(r) {
4660
- return r.getBoundingClientRect();
4661
- }
4662
- function elementAtPoint(x, y, root = document) {
4663
- return root.elementFromPoint(x, y);
4664
- }
4665
-
4666
5775
  // src/state.ts
4667
5776
  function getNodeAtPath(doc, path) {
4668
5777
  let node = doc;
@@ -4810,41 +5919,35 @@ var elements_meta_default = {
4810
5919
  {
4811
5920
  tag: "strong",
4812
5921
  label: "Bold",
4813
- icon: "sp-icon-text-bold",
4814
5922
  command: "bold"
4815
5923
  },
4816
5924
  {
4817
5925
  tag: "em",
4818
5926
  label: "Italic",
4819
- icon: "sp-icon-text-italic",
4820
5927
  command: "italic"
4821
5928
  },
4822
5929
  {
4823
5930
  tag: "u",
4824
5931
  label: "Underline",
4825
- icon: "sp-icon-text-underline",
4826
5932
  command: "underline"
4827
5933
  },
4828
5934
  {
4829
5935
  tag: "del",
4830
5936
  label: "Strikethrough",
4831
- icon: "sp-icon-text-strikethrough",
4832
5937
  command: "strikethrough"
4833
5938
  },
4834
5939
  {
4835
5940
  tag: "sup",
4836
5941
  label: "Superscript",
4837
- icon: "sp-icon-text-superscript",
4838
5942
  command: "superscript"
4839
5943
  },
4840
5944
  {
4841
5945
  tag: "sub",
4842
5946
  label: "Subscript",
4843
- icon: "sp-icon-text-subscript",
4844
5947
  command: "subscript"
4845
5948
  },
4846
- { tag: "code", label: "Code", icon: "sp-icon-code", command: "code" },
4847
- { tag: "a", label: "Link", icon: "sp-icon-link", command: "link" }
5949
+ { tag: "code", label: "Code", command: "code" },
5950
+ { tag: "a", label: "Link", command: "link" }
4848
5951
  ]
4849
5952
  },
4850
5953
  h1: {
@@ -4854,17 +5957,15 @@ var elements_meta_default = {
4854
5957
  {
4855
5958
  tag: "strong",
4856
5959
  label: "Bold",
4857
- icon: "sp-icon-text-bold",
4858
5960
  command: "bold"
4859
5961
  },
4860
5962
  {
4861
5963
  tag: "em",
4862
5964
  label: "Italic",
4863
- icon: "sp-icon-text-italic",
4864
5965
  command: "italic"
4865
5966
  },
4866
- { tag: "code", label: "Code", icon: "sp-icon-code", command: "code" },
4867
- { tag: "a", label: "Link", icon: "sp-icon-link", command: "link" }
5967
+ { tag: "code", label: "Code", command: "code" },
5968
+ { tag: "a", label: "Link", command: "link" }
4868
5969
  ]
4869
5970
  },
4870
5971
  h2: {
@@ -5087,16 +6188,14 @@ var elements_meta_default = {
5087
6188
  {
5088
6189
  tag: "strong",
5089
6190
  label: "Bold",
5090
- icon: "sp-icon-text-bold",
5091
6191
  command: "bold"
5092
6192
  },
5093
6193
  {
5094
6194
  tag: "em",
5095
6195
  label: "Italic",
5096
- icon: "sp-icon-text-italic",
5097
6196
  command: "italic"
5098
6197
  },
5099
- { tag: "code", label: "Code", icon: "sp-icon-code", command: "code" }
6198
+ { tag: "code", label: "Code", command: "code" }
5100
6199
  ]
5101
6200
  },
5102
6201
  span: {
@@ -5525,7 +6624,7 @@ function findTemplateExpressions(text) {
5525
6624
 
5526
6625
  // src/editor/editable-tags.ts
5527
6626
  var EXCLUDED = new Set(["pre"]);
5528
- 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));
5529
6628
  function isEditableTag(tag, verdicts) {
5530
6629
  const declared = verdicts?.[tag.toLowerCase()];
5531
6630
  return declared ?? BUILTIN_EDITABLE_TAGS.has(tag.toLowerCase());
@@ -5977,18 +7076,64 @@ function nearestHit(target) {
5977
7076
  }
5978
7077
  return measureHit(el, el.dataset.jxPath);
5979
7078
  }
7079
+ function isRendered(el) {
7080
+ const check = el.checkVisibility;
7081
+ return typeof check === "function" ? check.call(el, { checkVisibilityCSS: true }) : true;
7082
+ }
5980
7083
  function measureHits(paths, doc = document) {
5981
- const out = [];
7084
+ const hits = [];
7085
+ const hidden = [];
5982
7086
  for (const path of paths) {
5983
- const serialized = serializeJxPath(path);
5984
- const esc = serialized.replaceAll("\\", String.raw`\\`).replaceAll("'", String.raw`\'`);
5985
- const el = doc.querySelector(`[data-jx-path='${esc}']`);
5986
- if (el) {
7087
+ const el = doc.querySelector(jxPathSelector(serializeJxPath(path)));
7088
+ if (!el) {
7089
+ continue;
7090
+ }
7091
+ if (isRendered(el)) {
5987
7092
  const r = rectOf(el);
5988
- 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);
5989
7096
  }
5990
7097
  }
5991
- 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) });
5992
7137
  }
5993
7138
  function startInteraction(channel, doc = document, deps) {
5994
7139
  let lastHoverKey = null;
@@ -6019,6 +7164,8 @@ function startInteraction(channel, doc = document, deps) {
6019
7164
  kind: "hit"
6020
7165
  });
6021
7166
  }
7167
+ postPopoverInvoke(e.target, channel);
7168
+ postCommandInvoke(e.target, channel);
6022
7169
  };
6023
7170
  const reportHover = (el) => {
6024
7171
  if (isPreview()) {
@@ -6250,112 +7397,6 @@ function scrollDirection(y, viewportH, band = AUTO_SCROLL_BAND) {
6250
7397
  return 0;
6251
7398
  }
6252
7399
 
6253
- // src/canvas/iframe-position.ts
6254
- function isIslandBoundary(el) {
6255
- if (el.dataset.jxDefinitionRoot !== undefined) {
6256
- return false;
6257
- }
6258
- return el.getAttribute("contenteditable") === "false" || el.tagName.includes("-");
6259
- }
6260
- function activeBlockAt(node, isEditable) {
6261
- let el = node instanceof Element ? node : node?.parentElement ?? null;
6262
- while (el) {
6263
- if (el instanceof HTMLElement) {
6264
- if (el.dataset.jxPath && isEditable(el)) {
6265
- return { el, path: parseJxPath(el.dataset.jxPath) };
6266
- }
6267
- if (isIslandBoundary(el)) {
6268
- return null;
6269
- }
6270
- }
6271
- el = el.parentElement;
6272
- }
6273
- return null;
6274
- }
6275
- function elementForPath(container, path) {
6276
- const serialized = serializeJxPath(path);
6277
- const esc = serialized.replaceAll("\\", String.raw`\\`).replaceAll("'", String.raw`\'`);
6278
- const el = container.querySelector(`[data-jx-path='${esc}']`);
6279
- return el instanceof HTMLElement ? el : null;
6280
- }
6281
- function blockTextLength(block) {
6282
- return block.textContent?.length ?? 0;
6283
- }
6284
- function offsetOf(block, node, offset) {
6285
- if (!block.contains(node)) {
6286
- return null;
6287
- }
6288
- const range = block.ownerDocument.createRange();
6289
- range.setStart(block, 0);
6290
- try {
6291
- range.setEnd(node, offset);
6292
- } catch {
6293
- return null;
6294
- }
6295
- return range.toString().length;
6296
- }
6297
- function domPositionAt(block, offset) {
6298
- const target = Math.max(0, Math.min(offset, blockTextLength(block)));
6299
- const walker = block.ownerDocument.createTreeWalker(block, NodeFilter.SHOW_TEXT);
6300
- let seen = 0;
6301
- let last = null;
6302
- let current = walker.nextNode();
6303
- while (current) {
6304
- const len = current.length;
6305
- if (seen + len >= target) {
6306
- return { node: current, offset: target - seen };
6307
- }
6308
- seen += len;
6309
- last = current;
6310
- current = walker.nextNode();
6311
- }
6312
- return last ? { node: last, offset: last.length } : { node: block, offset: 0 };
6313
- }
6314
- function toDocPos(node, offset, isEditable) {
6315
- const block = activeBlockAt(node, isEditable);
6316
- if (!block || !node) {
6317
- return null;
6318
- }
6319
- const charOffset = offsetOf(block.el, node, offset);
6320
- return charOffset === null ? null : { offset: charOffset, path: block.path };
6321
- }
6322
- function toDomPosition(container, pos) {
6323
- const el = elementForPath(container, pos.path);
6324
- return el ? domPositionAt(el, pos.offset) : null;
6325
- }
6326
- function isAtBlockStart(pos) {
6327
- return pos.offset <= 0;
6328
- }
6329
- function samePath(a, b) {
6330
- return serializeJxPath(a.path) === serializeJxPath(b.path);
6331
- }
6332
- function blocksInOrder(container, isEditable) {
6333
- const out = [];
6334
- for (const el of container.querySelectorAll("[data-jx-path]")) {
6335
- if (isEditable(el) && !sealedInIsland(el, container)) {
6336
- out.push(el);
6337
- }
6338
- }
6339
- return out;
6340
- }
6341
- function sealedInIsland(el, container) {
6342
- let cur = el.parentElement;
6343
- while (cur && cur !== container) {
6344
- if (isIslandBoundary(cur)) {
6345
- return true;
6346
- }
6347
- cur = cur.parentElement;
6348
- }
6349
- return false;
6350
- }
6351
- function adjacentBlock(container, path, direction, isEditable) {
6352
- const blocks = blocksInOrder(container, isEditable);
6353
- const key = serializeJxPath(path);
6354
- const index = blocks.findIndex((el) => el.dataset.jxPath === key);
6355
- const neighbour = index === -1 ? undefined : blocks[index + direction];
6356
- return neighbour ? { el: neighbour, path: parseJxPath(neighbour.dataset.jxPath) } : null;
6357
- }
6358
-
6359
7400
  // src/canvas/editable-actions.ts
6360
7401
  var DELETE_BACKWARD = new Set([
6361
7402
  "deleteContentBackward",
@@ -6464,7 +7505,7 @@ function restoreDocSelection(container, range) {
6464
7505
  }
6465
7506
  function startEditableRoot(container, deps) {
6466
7507
  const doc = container.ownerDocument;
6467
- let activeEl2 = null;
7508
+ let activeEl = null;
6468
7509
  let activeKey = null;
6469
7510
  const editingAllowed = () => {
6470
7511
  const mode = deps.getMode?.();
@@ -6479,7 +7520,7 @@ function startEditableRoot(container, deps) {
6479
7520
  };
6480
7521
  const commitTick = () => {
6481
7522
  commitTimer = 0;
6482
- if (!activeEl2 || !deps.onCommitTick) {
7523
+ if (!activeEl || !deps.onCommitTick) {
6483
7524
  return;
6484
7525
  }
6485
7526
  const caret = captureDocSelection(container, deps.isEditableBlock);
@@ -6490,7 +7531,7 @@ function startEditableRoot(container, deps) {
6490
7531
  };
6491
7532
  let composing = false;
6492
7533
  const scheduleCommitTick = () => {
6493
- if (!deps.onCommitTick || !activeEl2 || composing) {
7534
+ if (!deps.onCommitTick || !activeEl || composing) {
6494
7535
  return;
6495
7536
  }
6496
7537
  cancelCommitTick();
@@ -6506,15 +7547,15 @@ function startEditableRoot(container, deps) {
6506
7547
  };
6507
7548
  const forget = () => {
6508
7549
  cancelCommitTick();
6509
- activeEl2 = null;
7550
+ activeEl = null;
6510
7551
  activeKey = null;
6511
7552
  };
6512
7553
  const deactivate = () => {
6513
- if (!activeEl2) {
7554
+ if (!activeEl) {
6514
7555
  return;
6515
7556
  }
6516
7557
  cancelCommitTick();
6517
- activeEl2 = null;
7558
+ activeEl = null;
6518
7559
  activeKey = null;
6519
7560
  deps.onDeactivate();
6520
7561
  };
@@ -6534,7 +7575,7 @@ function startEditableRoot(container, deps) {
6534
7575
  }
6535
7576
  const block = activeBlockAt(focus, deps.isEditableBlock);
6536
7577
  if (!block) {
6537
- if (activeEl2?.contains(focus)) {
7578
+ if (activeEl?.contains(focus)) {
6538
7579
  deps.onSelectionChange?.();
6539
7580
  return;
6540
7581
  }
@@ -6547,7 +7588,7 @@ function startEditableRoot(container, deps) {
6547
7588
  return;
6548
7589
  }
6549
7590
  deactivate();
6550
- activeEl2 = block.el;
7591
+ activeEl = block.el;
6551
7592
  activeKey = key;
6552
7593
  deps.onActivate(block.el, block.path);
6553
7594
  };
@@ -6583,7 +7624,7 @@ function startEditableRoot(container, deps) {
6583
7624
  atBlockStart: resolved ? isAtBlockStart(resolved.from) : false,
6584
7625
  data: e.data ?? "",
6585
7626
  from: resolved?.from ?? null,
6586
- inPropHost: activeEl2 !== null && activeKey === null,
7627
+ inPropHost: activeEl !== null && activeKey === null,
6587
7628
  inputType: e.inputType,
6588
7629
  to: resolved?.to ?? null
6589
7630
  });
@@ -6626,10 +7667,10 @@ function startEditableRoot(container, deps) {
6626
7667
  let el = e.target instanceof Element ? e.target : null;
6627
7668
  while (el && el !== container) {
6628
7669
  if (el.dataset?.jxBoundProp) {
6629
- if (el !== activeEl2) {
7670
+ if (el !== activeEl) {
6630
7671
  deactivate();
6631
7672
  if (deps.onPropActivate(el)) {
6632
- activeEl2 = el;
7673
+ activeEl = el;
6633
7674
  activeKey = null;
6634
7675
  }
6635
7676
  }
@@ -6890,8 +7931,8 @@ function prepareForEditMode(node) {
6890
7931
  propsOut[pk] = templateToEditDisplay(pv);
6891
7932
  }
6892
7933
  } else if (pv && typeof pv === "object" && pv.$ref) {
6893
- const ref2 = pv.$ref;
6894
- const label = ref2.startsWith("#/state/") ? ref2.slice(8) : ref2;
7934
+ const ref = pv.$ref;
7935
+ const label = ref.startsWith("#/state/") ? ref.slice(8) : ref;
6895
7936
  propsOut[pk] = `{${label}}`;
6896
7937
  } else {
6897
7938
  propsOut[pk] = pv;
@@ -6942,8 +7983,8 @@ function prepareForEditMode(node) {
6942
7983
  const isUrlAttr = ak === "href" || ak === "action";
6943
7984
  processed[ak] = isUrlAttr ? "" : templateToEditDisplay(av);
6944
7985
  } else if (av && typeof av === "object" && av.$ref) {
6945
- const ref2 = av.$ref;
6946
- const label = ref2.startsWith("#/state/") ? ref2.slice(8) : ref2;
7986
+ const ref = av.$ref;
7987
+ const label = ref.startsWith("#/state/") ? ref.slice(8) : ref;
6947
7988
  processed[ak] = `{${label}}`;
6948
7989
  } else {
6949
7990
  processed[ak] = av;
@@ -6954,7 +7995,9 @@ function prepareForEditMode(node) {
6954
7995
  if (v && typeof v === "object") {
6955
7996
  const s = {};
6956
7997
  for (const [sk, sv] of Object.entries(v)) {
6957
- s[sk] = typeof sv === "string" && sv.includes("${") ? "" : sv;
7998
+ if (typeof sv !== "string" || !sv.includes("${")) {
7999
+ s[sk] = sv;
8000
+ }
6958
8001
  }
6959
8002
  out.style = s;
6960
8003
  } else {
@@ -6970,8 +8013,8 @@ function prepareForEditMode(node) {
6970
8013
  out[k] = isUrlAttr ? "" : templateToEditDisplay(v);
6971
8014
  }
6972
8015
  } else if (v && typeof v === "object" && v.$ref) {
6973
- const ref2 = v.$ref;
6974
- const label = ref2.startsWith("#/state/") ? ref2.slice(8) : ref2;
8016
+ const ref = v.$ref;
8017
+ const label = ref.startsWith("#/state/") ? ref.slice(8) : ref;
6975
8018
  const isMediaSrc = (k === "src" || k === "poster") && mediaTags.has(obj.tagName || "");
6976
8019
  if (isMediaSrc) {
6977
8020
  needsMediaPlaceholder = true;
@@ -7699,8 +8742,8 @@ function renderSubtreeIframe(shadowDoc, docPath, ctx) {
7699
8742
  if (node === undefined) {
7700
8743
  throw new Error(`iframe-patch-node-not-found:${docPath.join("/")}`);
7701
8744
  }
7702
- const def2 = typeof node === "string" ? node : prepareForEditMode(stripEventHandlers(node));
7703
- 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, {
7704
8747
  _path: docPathToRenderPath(docPath, ctx),
7705
8748
  onNodeCreated: makeStamper(ctx.mapperCtx)
7706
8749
  }));
@@ -7716,11 +8759,7 @@ function disposeSubtree(el) {
7716
8759
  if (!(t instanceof HTMLElement)) {
7717
8760
  continue;
7718
8761
  }
7719
- const tag = elementStyleTags.get(t);
7720
- if (tag) {
7721
- tag.remove();
7722
- elementStyleTags.delete(t);
7723
- }
8762
+ releaseElementStyles(t);
7724
8763
  const stop = elScope.get(t);
7725
8764
  if (stop) {
7726
8765
  stop();
@@ -7868,9 +8907,9 @@ function syncPlaceholderClass(el, node) {
7868
8907
  el.classList.add(placeholder);
7869
8908
  }
7870
8909
  }
7871
- function insertAt(parentEl, node, ref2) {
7872
- if (ref2) {
7873
- ref2.before(node);
8910
+ function insertAt(parentEl, node, ref) {
8911
+ if (ref) {
8912
+ ref.before(node);
7874
8913
  } else {
7875
8914
  parentEl.append(node);
7876
8915
  }
@@ -7944,7 +8983,10 @@ function editModeStyle(style) {
7944
8983
  }
7945
8984
  const out = {};
7946
8985
  for (const [k, v] of Object.entries(style)) {
7947
- out[k] = typeof v === "string" && v.includes("${") ? "" : v;
8986
+ if (typeof v === "string" && v.includes("${")) {
8987
+ continue;
8988
+ }
8989
+ out[k] = v;
7948
8990
  }
7949
8991
  return out;
7950
8992
  }
@@ -7957,8 +8999,8 @@ function textDisplayValue(node) {
7957
8999
  return v.includes("${") ? templateToEditDisplay(v) : v;
7958
9000
  }
7959
9001
  if (typeof v === "object" && v.$ref) {
7960
- const ref2 = String(v.$ref);
7961
- 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;
7962
9004
  return `{${label}}`;
7963
9005
  }
7964
9006
  return String(v);
@@ -8093,6 +9135,32 @@ function serializeDataScope(defs) {
8093
9135
  return out;
8094
9136
  }
8095
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
+
8096
9164
  // src/services/bundle-base.ts
8097
9165
  var base;
8098
9166
  function setBundleBase(entryUrl) {
@@ -8101,6 +9169,9 @@ function setBundleBase(entryUrl) {
8101
9169
 
8102
9170
  // src/canvas/iframe-entry.ts
8103
9171
  setBundleBase(import.meta.url);
9172
+ for (const [specifier, load] of Object.entries(KIT_LOADERS)) {
9173
+ preloadModule(specifier, load);
9174
+ }
8104
9175
  function previewAt(cursor, src, shadowDoc, doc) {
8105
9176
  const targetEl = resolveDropTarget(cursor.x, cursor.y, doc);
8106
9177
  if (!targetEl) {
@@ -8146,8 +9217,8 @@ function layoutHitFor(target) {
8146
9217
  }
8147
9218
  var IN_PLACE_KEYS = new Set(["style", "textContent"]);
8148
9219
  function patchDisturbsActiveEdit(forwardOps) {
8149
- const activePath2 = getActivePath();
8150
- if (!activePath2) {
9220
+ const activePath = getActivePath();
9221
+ if (!activePath) {
8151
9222
  return false;
8152
9223
  }
8153
9224
  for (const op of forwardOps) {
@@ -8159,14 +9230,14 @@ function patchDisturbsActiveEdit(forwardOps) {
8159
9230
  affected = op.path;
8160
9231
  } else if (op.op === "move-child") {
8161
9232
  affected = op.fromParentPath;
8162
- if (isAncestor(affected, activePath2) || isAncestor(op.toParentPath, activePath2)) {
9233
+ if (isAncestor(affected, activePath) || isAncestor(op.toParentPath, activePath)) {
8163
9234
  return true;
8164
9235
  }
8165
9236
  continue;
8166
9237
  } else {
8167
9238
  affected = op.parentPath;
8168
9239
  }
8169
- if (isAncestor(affected, activePath2)) {
9240
+ if (isAncestor(affected, activePath)) {
8170
9241
  return true;
8171
9242
  }
8172
9243
  }
@@ -8183,6 +9254,8 @@ function startCanvasIframe(opts) {
8183
9254
  let shadowDoc = null;
8184
9255
  let renderedGen = -1;
8185
9256
  let currentMode = "design";
9257
+ let popoverOpen = null;
9258
+ let dialogOpen = null;
8186
9259
  let forwardTable = NO_TABLE;
8187
9260
  let renderCtx = null;
8188
9261
  let dragSrc = null;
@@ -8263,8 +9336,18 @@ function startCanvasIframe(opts) {
8263
9336
  const stopImageRetry = installCanvasImageRetry(container);
8264
9337
  const MAX_CANVAS_HEIGHT = 30000;
8265
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
+ }
8266
9348
  function postContentHeight() {
8267
- 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);
8268
9351
  if (measured > 0 && Math.abs(measured - lastPostedHeight) >= 1) {
8269
9352
  lastPostedHeight = measured;
8270
9353
  const root = container.firstElementChild;
@@ -8312,6 +9395,7 @@ function startCanvasIframe(opts) {
8312
9395
  const quiet = sample.fonts && sample.animations === 0 && sample.images === 0;
8313
9396
  quietFrames = quiet ? changed ? 1 : quietFrames + 1 : 0;
8314
9397
  if (quietFrames >= IDLE_QUIET_FRAMES) {
9398
+ postContentHeight();
8315
9399
  return;
8316
9400
  }
8317
9401
  if (Date.now() >= idleDeadline) {
@@ -8435,11 +9519,8 @@ function startCanvasIframe(opts) {
8435
9519
  container.ownerDocument.addEventListener("drop", onNativeDrop, true);
8436
9520
  const off = channel.onMessage((msg) => {
8437
9521
  if (msg.kind === "measure") {
8438
- channel.post({
8439
- hits: measureHits(msg.paths, container.ownerDocument),
8440
- kind: "geometry",
8441
- reqId: msg.reqId
8442
- });
9522
+ const { hidden, hits } = measureHits(msg.paths, container.ownerDocument);
9523
+ channel.post({ hidden, hits, kind: "geometry", reqId: msg.reqId });
8443
9524
  return;
8444
9525
  }
8445
9526
  if (msg.kind === "evalExpr") {
@@ -8448,13 +9529,13 @@ function startCanvasIframe(opts) {
8448
9529
  return;
8449
9530
  }
8450
9531
  if (msg.kind === "patch") {
8451
- const { gen: gen2 } = msg;
8452
- if (gen2 < renderedGen) {
8453
- 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" });
8454
9535
  return;
8455
9536
  }
8456
- if (gen2 > renderedGen || !shadowDoc || !renderCtx) {
8457
- 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" });
8458
9539
  return;
8459
9540
  }
8460
9541
  const echoed = new Set((msg.echoPaths ?? []).map((p) => serializeJxPath(p)));
@@ -8466,14 +9547,16 @@ function startCanvasIframe(opts) {
8466
9547
  }
8467
9548
  try {
8468
9549
  applyIframePatch(shadowDoc, msg.forwardOps, container, renderCtx, msg.echoPaths);
9550
+ applyCanvasPopoverOpen(container, popoverOpen);
9551
+ applyCanvasDialogOpen(container, dialogOpen);
8469
9552
  if (caret) {
8470
9553
  restoreDocSelection(container, caret);
8471
9554
  }
8472
- channel.post({ gen: gen2, kind: "patchComplete" });
9555
+ channel.post({ gen, kind: "patchComplete" });
8473
9556
  armIdleWatch();
8474
9557
  } catch (error) {
8475
9558
  channel.post({
8476
- gen: gen2,
9559
+ gen,
8477
9560
  kind: "patchError",
8478
9561
  message: String(error?.message ?? error)
8479
9562
  });
@@ -8533,6 +9616,29 @@ function startCanvasIframe(opts) {
8533
9616
  applyPreviewColorScheme(container.ownerDocument, msg.scheme);
8534
9617
  return;
8535
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
+ }
8536
9642
  if (msg.kind === "setLocale") {
8537
9643
  const root = container.ownerDocument.documentElement;
8538
9644
  if (msg.locale === null) {
@@ -8565,6 +9671,7 @@ function startCanvasIframe(opts) {
8565
9671
  stopDataScopeWatch?.();
8566
9672
  stopDataScopeWatch = null;
8567
9673
  handle?.dispose();
9674
+ resetDocumentStyles(container.ownerDocument);
8568
9675
  handle = await renderResolvedDocument({
8569
9676
  assets: msg.assets ?? null,
8570
9677
  container,
@@ -8577,11 +9684,18 @@ function startCanvasIframe(opts) {
8577
9684
  pageContentOffset: mapperCtx.pageContentOffset,
8578
9685
  pageContentPrefix: mapperCtx.pageContentPrefix
8579
9686
  },
9687
+ diffMarks: msg.diffMarks ?? null,
8580
9688
  mode: msg.mode,
9689
+ popoverOpen: msg.popoverOpen ? serializeJxPath(msg.popoverOpen) : null,
9690
+ dialogOpen: msg.dialogOpen ? serializeJxPath(msg.dialogOpen) : null,
8581
9691
  siteStyle: msg.siteStyle,
8582
9692
  ...msg.allowAutoRequests ? { allowAutoRequests: true } : {}
8583
9693
  });
8584
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);
8585
9699
  shadowDoc = rawDoc;
8586
9700
  renderCtx = handle.ctx;
8587
9701
  renderedGen = gen;
@@ -8664,5 +9778,5 @@ export {
8664
9778
  startCanvasIframe
8665
9779
  };
8666
9780
 
8667
- //# debugId=1D7D4718E26F550F64756E2164756E21
9781
+ //# debugId=54293E8C2DCDA4AF64756E2164756E21
8668
9782
  //# sourceMappingURL=iframe-entry.js.map