@jxsuite/studio 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/canvas.html +21 -0
- package/dist/chunks/Overlay.dev-qfjzkms8.js +23 -0
- package/dist/chunks/{Overlay.dev-cszx7yn5.js.map → Overlay.dev-qfjzkms8.js.map} +1 -1
- package/dist/chunks/{adapter-z8fkmbmv.js → adapter-qfnesn5v.js} +2 -2
- package/dist/chunks/{cf-settings-mmyv436d.js → cf-settings-73sh5z4p.js} +3 -3
- package/dist/chunks/{components-799jpvhm.js → components-2bpqp4mq.js} +5 -7
- package/dist/chunks/{components-799jpvhm.js.map → components-2bpqp4mq.js.map} +1 -1
- package/dist/chunks/content-source-34gnkbnn.js +38 -0
- package/dist/chunks/content-source-34gnkbnn.js.map +9 -0
- package/dist/chunks/convert-to-repeater-t8kxre5s.js +258 -0
- package/dist/chunks/convert-to-repeater-t8kxre5s.js.map +10 -0
- package/dist/chunks/extension-sections-6mqydz35.js +301 -0
- package/dist/chunks/extension-sections-6mqydz35.js.map +11 -0
- package/dist/chunks/files-8kn321h1.js +70 -0
- package/dist/chunks/files-8kn321h1.js.map +9 -0
- package/dist/chunks/{format-host-8jxwts2p.js → format-host-mkwsmt8d.js} +3 -3
- package/dist/chunks/git-panel-tjbr191d.js +51 -0
- package/dist/chunks/git-panel-tjbr191d.js.map +9 -0
- package/dist/chunks/{index-baeg2x3y.js → index-7pxchcce.js} +4 -3
- package/dist/chunks/{index-baeg2x3y.js.map → index-7pxchcce.js.map} +3 -3
- package/dist/chunks/{jx-validate-qx8degj7.js → jx-validate-v6qgknrs.js} +3 -3
- package/dist/chunks/layers-panel-87pb25km.js +58 -0
- package/dist/chunks/layers-panel-87pb25km.js.map +9 -0
- package/dist/chunks/{monaco-setup-zjdp9zdw.js → monaco-setup-e0yh25j4.js} +4 -75
- package/dist/chunks/{monaco-setup-zjdp9zdw.js.map → monaco-setup-e0yh25j4.js.map} +3 -4
- package/dist/chunks/publish-panel-m0fcgdrt.js +21 -0
- package/dist/chunks/publish-panel-m0fcgdrt.js.map +9 -0
- package/dist/chunks/quick-search-rhs6cbsb.js +53 -0
- package/dist/chunks/quick-search-rhs6cbsb.js.map +9 -0
- package/dist/chunks/right-panel-zpdxd98t.js +37 -0
- package/dist/chunks/right-panel-zpdxd98t.js.map +9 -0
- package/dist/chunks/section-registry-zmckaxf4.js +30 -0
- package/dist/chunks/section-registry-zmckaxf4.js.map +9 -0
- package/dist/chunks/sp-overlay.dev-9ran0sfq.js +18 -0
- package/dist/chunks/sp-overlay.dev-9ran0sfq.js.map +9 -0
- package/dist/chunks/sp-popover.dev-rebmdncr.js +9 -0
- package/dist/chunks/sp-popover.dev-rebmdncr.js.map +9 -0
- package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js +15 -0
- package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js.map +9 -0
- package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js +15 -0
- package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js.map +9 -0
- package/dist/chunks/{sp-tray.dev-pb2fsd65.js → sp-tray.dev-ey59vfh7.js} +10 -8
- package/dist/chunks/{sp-tray.dev-pb2fsd65.js.map → sp-tray.dev-ey59vfh7.js.map} +2 -2
- package/dist/chunks/{studio-9qr6fq7p.js → studio-0rqqhrdy.js} +10 -378
- package/dist/chunks/{studio-9qr6fq7p.js.map → studio-0rqqhrdy.js.map} +4 -14
- package/dist/chunks/{studio-5x6tqqec.js → studio-2sj1jj3v.js} +10 -8
- package/dist/chunks/{studio-5x6tqqec.js.map → studio-2sj1jj3v.js.map} +2 -2
- package/dist/chunks/{studio-h3fw0wn8.js → studio-3fk1ac9z.js} +6 -4
- package/dist/chunks/{studio-h3fw0wn8.js.map → studio-3fk1ac9z.js.map} +2 -2
- package/dist/chunks/studio-41exgzhq.js +6690 -0
- package/dist/chunks/studio-41exgzhq.js.map +38 -0
- package/dist/chunks/{studio-7v2bpweq.js → studio-4mqb9a0j.js} +6 -4
- package/dist/chunks/{studio-7v2bpweq.js.map → studio-4mqb9a0j.js.map} +2 -2
- package/dist/chunks/studio-50k77cca.js +1787 -0
- package/dist/chunks/studio-50k77cca.js.map +18 -0
- package/dist/chunks/{studio-56v3zwk6.js → studio-6a0h7sne.js} +10 -8
- package/dist/chunks/{studio-56v3zwk6.js.map → studio-6a0h7sne.js.map} +2 -2
- package/dist/chunks/studio-6f0am8f2.js +53 -0
- package/dist/chunks/studio-6f0am8f2.js.map +10 -0
- package/dist/chunks/studio-6nmjc5qk.js +7002 -0
- package/dist/chunks/studio-6nmjc5qk.js.map +32 -0
- package/dist/chunks/studio-7afd21nw.js +67 -0
- package/dist/chunks/studio-7afd21nw.js.map +10 -0
- package/dist/chunks/{studio-xze4zrs1.js → studio-7bmdvzne.js} +2 -2
- package/dist/chunks/studio-7bmdvzne.js.map +10 -0
- package/dist/chunks/studio-8jpzqk5s.js +128 -0
- package/dist/chunks/studio-8jpzqk5s.js.map +10 -0
- package/dist/chunks/studio-94m77tgk.js +1482 -0
- package/dist/chunks/studio-94m77tgk.js.map +13 -0
- package/dist/chunks/studio-9je6w5sq.js +1000 -0
- package/dist/chunks/studio-9je6w5sq.js.map +16 -0
- package/dist/chunks/{studio-w7c6kvk7.js → studio-a7pzveq1.js} +2 -2
- package/dist/chunks/{studio-gs6kqdt1.js → studio-adn0z1k3.js} +14 -8
- package/dist/chunks/{studio-gs6kqdt1.js.map → studio-adn0z1k3.js.map} +3 -3
- package/dist/chunks/{studio-kr88ryr7.js → studio-bsxxx3x2.js} +17 -15
- package/dist/chunks/{studio-kr88ryr7.js.map → studio-bsxxx3x2.js.map} +7 -6
- package/dist/chunks/studio-bw5dz6km.js +608 -0
- package/dist/chunks/studio-bw5dz6km.js.map +21 -0
- package/dist/chunks/studio-c6s5getc.js +4232 -0
- package/dist/chunks/studio-c6s5getc.js.map +39 -0
- package/dist/chunks/studio-cjm7fdjf.js +451 -0
- package/dist/chunks/studio-cjm7fdjf.js.map +14 -0
- package/dist/chunks/{studio-cx91mnh8.js → studio-ckwz4d3x.js} +53 -53
- package/dist/chunks/{studio-cx91mnh8.js.map → studio-ckwz4d3x.js.map} +5 -5
- package/dist/chunks/studio-dg7zyt5x.js +28 -0
- package/dist/chunks/studio-dg7zyt5x.js.map +10 -0
- package/dist/chunks/studio-dzcyvvvz.js +166 -0
- package/dist/chunks/studio-dzcyvvvz.js.map +10 -0
- package/dist/chunks/{studio-7kqe41sa.js → studio-evkr5d3b.js} +15 -7
- package/dist/chunks/{studio-7kqe41sa.js.map → studio-evkr5d3b.js.map} +5 -4
- package/dist/chunks/studio-f12h6177.js +411 -0
- package/dist/chunks/studio-f12h6177.js.map +13 -0
- package/dist/chunks/studio-hbp1s8m9.js +1817 -0
- package/dist/chunks/studio-hbp1s8m9.js.map +14 -0
- package/dist/chunks/studio-k2sxjph5.js +15295 -0
- package/dist/chunks/studio-k2sxjph5.js.map +235 -0
- package/dist/chunks/studio-myje51t3.js +385 -0
- package/dist/chunks/studio-myje51t3.js.map +12 -0
- package/dist/chunks/studio-na6rwzhw.js +353 -0
- package/dist/chunks/studio-na6rwzhw.js.map +11 -0
- package/dist/chunks/{studio-4k0m4fmp.js → studio-p471gg5n.js} +126 -3
- package/dist/chunks/studio-p471gg5n.js.map +14 -0
- package/dist/chunks/{studio-9bjwf0d4.js → studio-rgwcpast.js} +5 -46
- package/dist/chunks/{studio-9bjwf0d4.js.map → studio-rgwcpast.js.map} +4 -5
- package/dist/chunks/{studio-esrewxap.js → studio-s519zc99.js} +3 -3
- package/dist/chunks/studio-sas7mt3k.js +75 -0
- package/dist/chunks/studio-sas7mt3k.js.map +10 -0
- package/dist/chunks/studio-t5wqwzdh.js +74 -0
- package/dist/chunks/studio-t5wqwzdh.js.map +10 -0
- package/dist/chunks/{studio-9qpspwfn.js → studio-temv5bw4.js} +5 -5
- package/dist/chunks/{studio-9qpspwfn.js.map → studio-temv5bw4.js.map} +1 -1
- package/dist/chunks/{studio-qkvt37c0.js → studio-tr20m8g8.js} +669 -18
- package/dist/chunks/studio-tr20m8g8.js.map +9 -0
- package/dist/chunks/{studio-v7jkjqng.js → studio-v96qfnww.js} +5514 -4291
- package/dist/chunks/studio-v96qfnww.js.map +54 -0
- package/dist/chunks/studio-vcetc91k.js +659 -0
- package/dist/chunks/studio-vcetc91k.js.map +10 -0
- package/dist/chunks/{studio-jm0z592w.js → studio-vmymjefp.js} +2972 -4937
- package/dist/chunks/studio-vmymjefp.js.map +98 -0
- package/dist/chunks/{studio-bghqfmea.js → studio-wwseqyw0.js} +2 -2
- package/dist/chunks/studio-x9hmy5kr.js +390 -0
- package/dist/chunks/studio-x9hmy5kr.js.map +10 -0
- package/dist/chunks/studio-xa0ce0n7.js +335 -0
- package/dist/chunks/studio-xa0ce0n7.js.map +10 -0
- package/dist/chunks/studio-xm3dbxvn.js +378 -0
- package/dist/chunks/studio-xm3dbxvn.js.map +19 -0
- package/dist/chunks/{studio-nqw433kv.js → studio-xmvbhg31.js} +2 -2
- package/dist/chunks/studio-zv37yrfa.js +1054 -0
- package/dist/chunks/studio-zv37yrfa.js.map +13 -0
- package/dist/chunks/{ws-client-q7hkz3j9.js → ws-client-654ts66j.js} +6 -4
- package/dist/chunks/ws-client-654ts66j.js.map +11 -0
- package/dist/iframe-entry.js +668 -230
- package/dist/studio.js +21080 -32585
- package/index.html +35 -4685
- package/package.json +17 -15
- package/src/about/about-modal.ts +42 -11
- package/src/browse/library-commands.ts +240 -0
- package/src/browse/library-layouts.ts +369 -0
- package/src/browse/library-model.ts +396 -0
- package/src/browse/library-pane.ts +1049 -0
- package/src/browse/library-preview.ts +252 -0
- package/src/browse/library-source.ts +150 -0
- package/src/canvas/canvas-helpers.ts +33 -9
- package/src/canvas/canvas-live-render.ts +45 -29
- package/src/canvas/canvas-patcher.ts +151 -31
- package/src/canvas/canvas-perf.ts +46 -7
- package/src/canvas/canvas-render.ts +1092 -220
- package/src/canvas/canvas-surface.ts +240 -0
- package/src/canvas/canvas-utils.ts +1166 -124
- package/src/canvas/iframe-drop.ts +2 -1
- package/src/canvas/iframe-entry.ts +241 -4
- package/src/canvas/iframe-host.ts +1226 -143
- package/src/canvas/iframe-inline-edit.ts +31 -0
- package/src/canvas/iframe-interaction.ts +76 -16
- package/src/canvas/iframe-keys.ts +107 -45
- package/src/canvas/iframe-overlay.ts +38 -1
- package/src/canvas/iframe-protocol.ts +137 -2
- package/src/canvas/iframe-render.ts +70 -2
- package/src/canvas/iframe-slash.ts +6 -0
- package/src/canvas/path-mapping.ts +56 -6
- package/src/canvas/surface-registry.ts +292 -0
- package/src/collab/collab-commands.ts +244 -0
- package/src/collab/collab-session.ts +198 -32
- package/src/collab/collab-state.ts +28 -2
- package/src/collab/presence-chips.ts +100 -9
- package/src/commands/active-registry.ts +42 -0
- package/src/commands/app-commands.ts +176 -0
- package/src/commands/budget.ts +158 -0
- package/src/commands/command-args.ts +253 -0
- package/src/commands/context.ts +387 -0
- package/src/commands/defaults.ts +580 -0
- package/src/commands/keymap.ts +571 -0
- package/src/commands/levels.ts +345 -0
- package/src/commands/live-context.ts +193 -0
- package/src/commands/reference.ts +227 -0
- package/src/commands/registry.ts +293 -0
- package/src/component-props.ts +3 -2
- package/src/content/draft-state.ts +106 -0
- package/src/content/entry-commands.ts +282 -0
- package/src/content/entry-editor.ts +327 -0
- package/src/content/entry-fields.ts +116 -0
- package/src/content/entry-model.ts +175 -0
- package/src/editor/canvas-context-menu.ts +17 -11
- package/src/editor/canvas-slash-bridge.ts +11 -4
- package/src/editor/context-menu.ts +804 -204
- package/src/editor/convert-to-component.ts +31 -10
- package/src/editor/convert-to-repeater.ts +3 -2
- package/src/editor/inline-edit-apply.ts +5 -5
- package/src/editor/inline-edit.ts +86 -50
- package/src/editor/insert-zone-action.ts +1 -1
- package/src/editor/shortcuts.ts +1043 -329
- package/src/editor/slash-menu.ts +1 -0
- package/src/files/elements.ts +166 -0
- package/src/files/file-ops.ts +178 -31
- package/src/files/files.ts +898 -268
- package/src/files/fs-events.ts +21 -0
- package/src/files/media-meta.ts +203 -0
- package/src/files/media-paths.ts +141 -0
- package/src/files/media-upload.ts +7 -3
- package/src/files/media-usage.ts +189 -0
- package/src/github/github-auth.ts +235 -33
- package/src/github/github-publish.ts +80 -21
- package/src/grid/grid-controller.ts +152 -12
- package/src/grid/grid-layout.ts +225 -20
- package/src/grid/grid-open.ts +120 -0
- package/src/grid/grid-panel.ts +554 -39
- package/src/grid/grid-source.ts +27 -1
- package/src/grid/redirects-grid.ts +599 -0
- package/src/grid/redirects.ts +398 -0
- package/src/grid/sources/content-source.ts +108 -2
- package/src/i18n/i18n-commands.ts +322 -0
- package/src/new-project/add-repo-modal.ts +8 -10
- package/src/new-project/import-tab.ts +7 -0
- package/src/new-project/location-fields.ts +9 -1
- package/src/new-project/new-project-modal.ts +221 -245
- package/src/packages/jxsuite-update.ts +97 -48
- package/src/packages/pull-package-sync.ts +18 -9
- package/src/page-params.ts +2 -1
- package/src/panels/activity-bar.ts +152 -91
- package/src/panels/activity-panel.ts +481 -0
- package/src/panels/ai-chat/chat-markdown.ts +8 -3
- package/src/panels/ai-chat/chat-view.ts +245 -18
- package/src/panels/ai-chat/composer.ts +31 -5
- package/src/panels/ai-chat/sessions-view.ts +17 -10
- package/src/panels/ai-panel.ts +279 -53
- package/src/panels/block-action-bar.ts +1115 -224
- package/src/panels/bottom-dock.ts +337 -0
- package/src/panels/canvas-dnd-bridge.ts +37 -8
- package/src/panels/chat-panel.ts +29 -12
- package/src/panels/data-explorer.ts +254 -112
- package/src/panels/data-grid.ts +10 -4
- package/src/panels/dnd.ts +28 -51
- package/src/panels/editors.ts +434 -107
- package/src/panels/elements-panel.ts +66 -2
- package/src/panels/empty-state.ts +112 -0
- package/src/panels/events-panel.ts +596 -82
- package/src/panels/formula-workspace.ts +408 -218
- package/src/panels/frontmatter-fields.ts +51 -10
- package/src/panels/frontmatter-panel.ts +357 -79
- package/src/panels/git-panel.ts +375 -164
- package/src/panels/head-panel.ts +791 -85
- package/src/panels/i18n-panel.ts +592 -0
- package/src/panels/imports-panel.ts +95 -85
- package/src/panels/jump-bar.ts +584 -0
- package/src/panels/layers-panel.ts +1106 -328
- package/src/panels/left-panel.ts +109 -204
- package/src/panels/navigator-panels.ts +131 -0
- package/src/panels/overlays.ts +7 -2
- package/src/panels/pane-context.ts +1477 -0
- package/src/panels/pane-grid.ts +406 -0
- package/src/panels/panel-registry.ts +340 -0
- package/src/panels/panel-scheduler.ts +75 -0
- package/src/panels/problems-panel.ts +234 -0
- package/src/panels/properties-panel.ts +946 -1139
- package/src/panels/provenance.ts +258 -0
- package/src/panels/quick-search.ts +791 -122
- package/src/panels/right-panel.ts +228 -102
- package/src/panels/seo-modal.ts +395 -0
- package/src/panels/settings-pane.ts +203 -0
- package/src/panels/signals-panel.ts +354 -137
- package/src/panels/statement-editor.ts +41 -25
- package/src/panels/statusbar.ts +342 -106
- package/src/panels/style-panel.ts +974 -463
- package/src/panels/style-utils.ts +3 -3
- package/src/panels/stylebook-doc.ts +4 -2
- package/src/panels/stylebook-layers-panel.ts +3 -2
- package/src/panels/stylebook-panel.ts +51 -26
- package/src/panels/tab-strip.ts +1058 -78
- package/src/panels/target-line.ts +274 -0
- package/src/panels/toolbar.ts +631 -484
- package/src/panels/welcome-screen.ts +301 -198
- package/src/platform-errors.ts +26 -3
- package/src/platform.ts +96 -2
- package/src/platforms/cloud.ts +71 -8
- package/src/platforms/devserver.ts +92 -29
- package/src/publish/deploy-checklist.ts +383 -0
- package/src/publish/pages-service.ts +10 -1
- package/src/publish/publish-commands.ts +218 -0
- package/src/publish/publish-panel.ts +110 -16
- package/src/recent-projects.ts +3 -2
- package/src/services/a11y-report.ts +505 -0
- package/src/services/ai-models.ts +30 -1
- package/src/services/ai-project-tools.ts +29 -10
- package/src/services/ai-system-prompt.ts +53 -14
- package/src/services/ai-tools.ts +39 -3
- package/src/services/ai-writes.ts +154 -0
- package/src/services/announce.ts +97 -0
- package/src/services/automation.ts +424 -175
- package/src/services/cem-export.ts +9 -4
- package/src/services/clock.ts +61 -0
- package/src/services/document-assistant.ts +36 -8
- package/src/services/idle.ts +179 -0
- package/src/services/import-client.ts +26 -0
- package/src/services/monaco-buffer.ts +627 -0
- package/src/services/monaco-lazy.ts +36 -0
- package/src/services/notify.ts +271 -0
- package/src/services/profile.ts +155 -0
- package/src/services/references.ts +0 -0
- package/src/services/token-lint.ts +3 -2
- package/src/services/tool-executor.ts +53 -7
- package/src/services/trusted-types.ts +123 -0
- package/src/settings/contexts-section.ts +427 -0
- package/src/settings/contributed-section.ts +149 -11
- package/src/settings/css-vars-editor.ts +306 -349
- package/src/settings/defs-editor.ts +93 -34
- package/src/settings/dependencies-editor.ts +7 -7
- package/src/settings/extension-sections.ts +37 -5
- package/src/settings/general-settings.ts +204 -121
- package/src/settings/locales-section.ts +347 -0
- package/src/settings/preferences-accounts.ts +140 -0
- package/src/settings/preferences-dialog.ts +620 -0
- package/src/settings/preferences-keymap.ts +270 -0
- package/src/settings/project-sections.ts +260 -0
- package/src/settings/section-registry.ts +169 -0
- package/src/settings/settings-document.ts +385 -0
- package/src/shell.ts +1549 -0
- package/src/site-context.ts +45 -20
- package/src/state.ts +14 -275
- package/src/store.ts +88 -43
- package/src/studio.ts +790 -346
- package/src/style/live-preview.ts +36 -0
- package/src/style/project-styles.ts +349 -0
- package/src/style/token-ref.ts +123 -0
- package/src/tabs/patch-ops.ts +16 -4
- package/src/tabs/project-config.ts +416 -0
- package/src/tabs/selection.ts +323 -0
- package/src/tabs/tab.ts +182 -47
- package/src/tabs/transact.ts +209 -28
- package/src/types.ts +68 -13
- package/src/ui/ai-credentials-form.ts +39 -35
- package/src/ui/ai-managed-connect.ts +7 -1
- package/src/ui/dynamic-slot.ts +224 -81
- package/src/ui/expression-editor.ts +71 -63
- package/src/ui/field-input.ts +4 -6
- package/src/ui/field-row.ts +215 -38
- package/src/ui/form-controls.ts +194 -7
- package/src/ui/layers.ts +492 -69
- package/src/ui/media-picker.ts +115 -25
- package/src/ui/panel-resize.ts +109 -91
- package/src/ui/progress-modal.ts +131 -50
- package/src/ui/regions.ts +462 -0
- package/src/ui/schema-form.ts +229 -45
- package/src/ui/spectrum.ts +24 -8
- package/src/ui/timing.ts +49 -0
- package/src/ui/value-selector.ts +20 -0
- package/src/ui/value-source.ts +348 -0
- package/src/ui/virtual-window.ts +400 -0
- package/src/utils/edit-display.ts +3 -2
- package/src/utils/inherited-style.ts +67 -37
- package/src/view.ts +64 -78
- package/src/workspace/pane-derive.ts +1258 -0
- package/src/workspace/session.ts +317 -0
- package/src/workspace/workspace.ts +1345 -23
- package/styles/canvas.css +653 -0
- package/styles/forced-colors.css +106 -0
- package/styles/inspector.css +1454 -0
- package/styles/overlays.css +2704 -0
- package/styles/panels.css +1701 -0
- package/styles/shell.css +1423 -0
- package/styles/tokens.css +151 -0
- package/dist/chunks/Overlay.dev-cszx7yn5.js +0 -22
- package/dist/chunks/extension-sections-qr3drkkw.js +0 -531
- package/dist/chunks/extension-sections-qr3drkkw.js.map +0 -12
- package/dist/chunks/files-j8a1t06k.js +0 -50
- package/dist/chunks/files-j8a1t06k.js.map +0 -9
- package/dist/chunks/git-panel-xtq5z81x.js +0 -28
- package/dist/chunks/git-panel-xtq5z81x.js.map +0 -9
- package/dist/chunks/layers-panel-ancn2wpq.js +0 -26
- package/dist/chunks/layers-panel-ancn2wpq.js.map +0 -9
- package/dist/chunks/settings-modal-17ttr96g.js +0 -29
- package/dist/chunks/settings-modal-17ttr96g.js.map +0 -9
- package/dist/chunks/sp-overlay.dev-earn5as8.js +0 -17
- package/dist/chunks/sp-overlay.dev-earn5as8.js.map +0 -9
- package/dist/chunks/sp-popover.dev-frxtfejn.js +0 -8
- package/dist/chunks/sp-popover.dev-frxtfejn.js.map +0 -9
- package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js +0 -14
- package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js.map +0 -9
- package/dist/chunks/sp-tooltip.dev-a9fywesm.js +0 -21
- package/dist/chunks/sp-tooltip.dev-a9fywesm.js.map +0 -10
- package/dist/chunks/studio-0xgs7xrs.js +0 -429
- package/dist/chunks/studio-0xgs7xrs.js.map +0 -13
- package/dist/chunks/studio-4d8hzcz5.js +0 -3427
- package/dist/chunks/studio-4d8hzcz5.js.map +0 -26
- package/dist/chunks/studio-4k0m4fmp.js.map +0 -13
- package/dist/chunks/studio-9smfzqhc.js +0 -19
- package/dist/chunks/studio-9smfzqhc.js.map +0 -10
- package/dist/chunks/studio-jm0z592w.js.map +0 -115
- package/dist/chunks/studio-m2t4mdg5.js +0 -1854
- package/dist/chunks/studio-m2t4mdg5.js.map +0 -18
- package/dist/chunks/studio-n4p11dfy.js +0 -853
- package/dist/chunks/studio-n4p11dfy.js.map +0 -12
- package/dist/chunks/studio-qkvt37c0.js.map +0 -9
- package/dist/chunks/studio-sjh1wt1a.js +0 -3744
- package/dist/chunks/studio-sjh1wt1a.js.map +0 -22
- package/dist/chunks/studio-v7jkjqng.js.map +0 -46
- package/dist/chunks/studio-xq0t7n5t.js +0 -140
- package/dist/chunks/studio-xq0t7n5t.js.map +0 -10
- package/dist/chunks/studio-xze4zrs1.js.map +0 -10
- package/dist/chunks/studio-yfcstdzy.js +0 -399
- package/dist/chunks/studio-yfcstdzy.js.map +0 -12
- package/dist/chunks/studio-zp7jncs8.js +0 -469
- package/dist/chunks/studio-zp7jncs8.js.map +0 -14
- package/dist/chunks/ws-client-q7hkz3j9.js.map +0 -11
- package/src/browse/browse-modal.ts +0 -69
- package/src/browse/browse.ts +0 -904
- package/src/canvas/canvas-diff.ts +0 -216
- package/src/canvas/nested-site-style.ts +0 -58
- package/src/new-project/design-fields.ts +0 -264
- package/src/new-project/templates.ts +0 -61
- package/src/panels/tab-bar.ts +0 -548
- package/src/settings/settings-modal.ts +0 -203
- /package/dist/chunks/{adapter-z8fkmbmv.js.map → adapter-qfnesn5v.js.map} +0 -0
- /package/dist/chunks/{cf-settings-mmyv436d.js.map → cf-settings-73sh5z4p.js.map} +0 -0
- /package/dist/chunks/{format-host-8jxwts2p.js.map → format-host-mkwsmt8d.js.map} +0 -0
- /package/dist/chunks/{jx-validate-qx8degj7.js.map → jx-validate-v6qgknrs.js.map} +0 -0
- /package/dist/chunks/{studio-w7c6kvk7.js.map → studio-a7pzveq1.js.map} +0 -0
- /package/dist/chunks/{studio-esrewxap.js.map → studio-s519zc99.js.map} +0 -0
- /package/dist/chunks/{studio-bghqfmea.js.map → studio-wwseqyw0.js.map} +0 -0
- /package/dist/chunks/{studio-nqw433kv.js.map → studio-xmvbhg31.js.map} +0 -0
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/site-context.ts", "../src/canvas/canvas-origin.ts", "../src/utils/edit-display.ts", "../src/page-params.ts", "../src/component-props.ts", "../../schema/src/asset-paths.ts", "../src/canvas/content-assets.ts", "../src/canvas/canvas-live-render.ts", "../src/panels/shared.ts", "../src/editor/inline-format.ts", "../src/editor/editable-tags.ts", "../src/editor/inline-edit.ts", "../src/utils/geometry.ts", "../src/canvas/canvas-helpers.ts", "../src/canvas/canvas-utils.ts", "../../../node_modules/@atlaskit/pragmatic-drag-and-drop/dist/esm/public-utils/element/disable-native-drag-preview.js", "../../../node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js", "../../../node_modules/@babel/runtime/helpers/esm/objectWithoutProperties.js", "../../../node_modules/@atlaskit/pragmatic-drag-and-drop-hitbox/dist/esm/internal/memoize.js", "../../../node_modules/@atlaskit/pragmatic-drag-and-drop-hitbox/dist/esm/tree-item.js", "../../runtime/src/expression.ts", "../../runtime/src/statements.ts", "../../runtime/src/runtime.ts", "../src/panels/component-preview.ts", "../src/panels/dnd.ts", "../src/canvas/iframe-channel.ts", "../src/canvas/preview-navigate.ts", "../src/editor/content-slice.ts", "../src/editor/inline-edit-apply.ts", "../src/canvas/iframe-overlay.ts", "../src/canvas/path-mapping.ts", "../src/panels/drag-ghost.ts", "../src/format/constraints.ts", "../src/canvas/iframe-host.ts", "../src/files/media-upload.ts", "../src/services/code-services.ts", "../src/services/cem-export.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"/// <reference lib=\"dom\" />\n/**\n * Site context helpers - merge site-level definitions with file-level.\n *\n * When a project has a project.json, its $media and style cascade into every file. File-level\n * definitions merge on top (file wins on conflict).\n */\n\nimport { projectState, requireProjectState, setProjectState } from \"./store\";\nimport { getPlatform } from \"./platform\";\nimport { setWorkspaceProject, workspace } from \"./workspace/workspace\";\n\nimport type {\n JxElement,\n JxHeadEntry,\n JxMutableNode,\n JxStyle,\n ProjectConfig,\n} from \"@jxsuite/schema/types\";\n\n/**\n * Merge site $media with document $media. Document keys win on conflict.\n *\n * @param {Record<string, string> | undefined} docMedia - The current document's $media (may be\n * undefined)\n * @returns {Record<string, string>}\n */\nexport function getEffectiveMedia(docMedia?: Record<string, string>) {\n const siteMedia = projectState?.projectConfig?.$media;\n if (!siteMedia) {\n return docMedia || {};\n }\n if (!docMedia) {\n return { ...siteMedia };\n }\n return { ...siteMedia, ...docMedia };\n}\n\n/**\n * Merge site style with document style. Document keys win on conflict. Nested selector objects\n * (e.g. `& li`) are shallow-merged individually.\n *\n * @param {JxStyle | undefined} docStyle - The current document's style (may be undefined)\n * @returns {JxStyle}\n */\nexport function getEffectiveStyle(docStyle?: JxStyle) {\n const siteStyle = projectState?.projectConfig?.style;\n if (!siteStyle) {\n return docStyle || {};\n }\n if (!docStyle) {\n return { ...siteStyle };\n }\n const merged = { ...siteStyle };\n for (const [k, v] of Object.entries(docStyle)) {\n merged[k] =\n typeof v === \"object\" && v !== null && typeof merged[k] === \"object\" && merged[k] !== null\n ? { ...(merged[k] as JxStyle), ...(v as JxStyle) }\n : v;\n }\n return merged;\n}\n\n/**\n * Merge site imports with document imports. Document keys win on conflict.\n *\n * @param {Record<string, string> | undefined} docImports - The current document's imports (may be\n * undefined)\n * @returns {Record<string, string>}\n */\nexport function getEffectiveImports(docImports?: Record<string, string>) {\n const siteImports = projectState?.projectConfig?.imports;\n if (!siteImports) {\n return docImports || {};\n }\n if (!docImports) {\n return { ...siteImports };\n }\n return { ...siteImports, ...docImports };\n}\n\n/**\n * Merge site $elements with document $elements. Union with dedup by $ref or string value.\n *\n * @param {(JxElement | string)[]} [docElements] - The current document's $elements (may be\n * undefined)\n * @returns {(JxElement | string)[]}\n */\nexport function getEffectiveElements(docElements?: (JxElement | string)[]) {\n const siteElements = projectState?.projectConfig?.$elements;\n if (!siteElements?.length) {\n return docElements || [];\n }\n if (!docElements?.length) {\n return [...siteElements];\n }\n const seen = new Set<string>();\n const merged: (JxElement | string)[] = [];\n for (const entry of [...siteElements, ...docElements]) {\n const key = typeof entry === \"string\" ? entry : entry?.$ref;\n if (key && !seen.has(key)) {\n seen.add(key);\n merged.push(entry);\n }\n }\n return merged;\n}\n\n/**\n * Merge site $head with document $head. Union with dedup by href/src.\n *\n * @param {JxHeadEntry[]} [docHead] - The current document's $head (may be undefined)\n * @returns {JxHeadEntry[]}\n */\nexport function getEffectiveHead(docHead?: JxHeadEntry[]) {\n const siteHead = projectState?.projectConfig?.$head;\n if (!siteHead?.length) {\n return docHead || [];\n }\n if (!docHead?.length) {\n return [...siteHead];\n }\n const seen = new Set<string>();\n const merged: JxHeadEntry[] = [];\n for (const entry of [...siteHead, ...docHead]) {\n const key =\n String(entry?.attributes?.href || entry?.attributes?.src || \"\") || JSON.stringify(entry);\n if (!seen.has(key)) {\n seen.add(key);\n merged.push(entry);\n }\n }\n return merged;\n}\n\n// ─── Layout resolution ──────────────────────────────────────────────────────\n\nconst layoutCache = new Map<string, JxMutableNode>();\n\nexport function invalidateLayoutCache() {\n layoutCache.clear();\n}\n\n/**\n * Determine the effective layout path for a document.\n *\n * @param {string | false | undefined} docLayout - The document's $layout value (string path, false,\n * or undefined)\n * @returns {string | null} The layout path, or null if no layout applies\n */\nexport function getEffectiveLayoutPath(docLayout: string | false | undefined) {\n if (docLayout === false) {\n return null;\n }\n const defaultLayout = projectState?.projectConfig?.defaults?.layout;\n return docLayout || defaultLayout || null;\n}\n\n/**\n * Resolve a layout document by path. Fetches and caches the parsed JSON.\n *\n * @param {string} layoutPath - Relative path to the layout file (e.g., \"./layouts/base.json\")\n * @returns {Promise<JxMutableNode | null>} The parsed layout document, or null on failure\n */\nexport async function resolveLayoutDoc(layoutPath: string) {\n const normalized = layoutPath.replace(/^\\.\\//, \"\");\n if (layoutCache.has(normalized)) {\n return structuredClone(layoutCache.get(normalized) as JxMutableNode);\n }\n\n try {\n const platform = getPlatform();\n const content = await platform.readFile(normalized);\n const doc = JSON.parse(content) as JxMutableNode;\n layoutCache.set(normalized, doc);\n return structuredClone(doc);\n } catch {\n return null;\n }\n}\n\n/**\n * Distribute page children into a layout document's <slot> elements. Returns the merged document\n * with page content injected into slots.\n *\n * @param {JxMutableNode} layoutDoc - Deep-cloned layout document\n * @param {JxMutableNode} pageDoc - The page document\n * @returns {JxMutableNode} The merged document\n */\nexport function distributePageIntoLayout(layoutDoc: JxMutableNode, pageDoc: JxMutableNode) {\n const pageChildren = pageDoc.children ?? [];\n const children = Array.isArray(pageChildren) ? pageChildren : [];\n\n const named = new Map<string, JxMutableNode[]>();\n const defaults: (JxMutableNode | string)[] = [];\n\n for (const child of children) {\n const slotName = typeof child === \"object\" ? child.attributes?.slot : undefined;\n if (typeof child === \"object\" && typeof slotName === \"string\" && slotName) {\n if (!named.has(slotName)) {\n named.set(slotName, []);\n }\n named.get(slotName)!.push(child);\n } else {\n defaults.push(child);\n }\n }\n\n fillSlots(layoutDoc, named, defaults);\n\n if (pageDoc.state) {\n layoutDoc.state = { ...layoutDoc.state, ...pageDoc.state };\n }\n if (pageDoc.$media) {\n layoutDoc.$media = { ...layoutDoc.$media, ...pageDoc.$media };\n }\n if (pageDoc.style) {\n layoutDoc.style = { ...layoutDoc.style, ...pageDoc.style };\n }\n if (pageDoc.attributes) {\n layoutDoc.attributes = { ...layoutDoc.attributes, ...pageDoc.attributes };\n }\n\n return layoutDoc;\n}\n\nfunction fillSlots(\n node: JxMutableNode,\n named: Map<string, JxMutableNode[]>,\n defaults: (JxMutableNode | string)[],\n) {\n if (!node || typeof node !== \"object\") {\n return;\n }\n if (!Array.isArray(node.children)) {\n return;\n }\n\n const newChildren: (JxMutableNode | string)[] = [];\n for (const child of node.children) {\n if (child && typeof child === \"object\" && child.tagName === \"slot\") {\n const slotName = child.attributes?.name;\n if (typeof slotName === \"string\" && slotName && named.has(slotName)) {\n newChildren.push(...named.get(slotName)!);\n named.delete(slotName);\n } else if (!slotName && defaults.length > 0) {\n newChildren.push(...defaults);\n } else if (Array.isArray(child.children)) {\n newChildren.push(...child.children);\n }\n } else {\n if (typeof child !== \"string\") {\n fillSlots(child, named, defaults);\n }\n newChildren.push(child);\n }\n }\n node.children = newChildren as JxMutableNode[];\n}\n\n/**\n * Update the project's project.json with a partial patch and persist to disk. A patch touching\n * `extensions` invalidates the format/extensions caches and refreshes the editor's per-project\n * schemas plus the contributed settings sections — the enabled-extension surface just changed.\n *\n * @param {Partial<ProjectConfig>} patch - Fields to merge into the current projectConfig\n */\nexport async function updateSiteConfig(patch: Partial<ProjectConfig>) {\n const platform = getPlatform();\n const config = {\n ...requireProjectState().projectConfig,\n ...patch,\n } as ProjectConfig;\n await platform.writeFile(\"project.json\", JSON.stringify(config, null, 2));\n setProjectState({ ...requireProjectState(), projectConfig: config });\n setWorkspaceProject(workspace.projectRoot, config);\n if (\"extensions\" in patch) {\n const { loadFormats, refreshExtensionUi, refreshFormats } =\n await import(\"./format/format-host\");\n refreshFormats();\n void loadFormats();\n refreshExtensionUi(platform);\n }\n}\n",
|
|
6
|
-
"/// <reference lib=\"dom\" />\n/**\n * Canvas origin derivation. The canvas iframe may load same-origin (dev server / chromium /\n * electrobun gate-off, where the platform canvasUrl is a relative path) or cross-origin (electrobun\n * loopback, where canvasUrl is an absolute http://127.0.0.1:<port> URL).\n *\n * CanvasBaseOrigin() returns the origin the canvas document lives on, so callers that build\n * absolute asset/doc URLs target the right server. For a relative canvasUrl this resolves to\n * location.origin — IDENTITY for the same-origin paths, so dev/chromium/electrobun-gate-off are\n * byte-identical to before.\n */\n\nimport { getPlatform, hasPlatform } from \"../platform\";\n\n/**\n * The origin serving the canvas document. When the platform registers an absolute canvasUrl\n * (electrobun loopback), this is that URL's origin; otherwise it falls back to the parent's own\n * origin (a relative canvasUrl resolves against location.href to location.origin).\n */\nexport function canvasBaseOrigin(): string {\n const canvasUrl = hasPlatform() ? getPlatform().canvasUrl : undefined;\n if (canvasUrl) {\n return new URL(canvasUrl, location.href).origin;\n }\n return location.origin;\n}\n\n/**\n * Build an absolute loopback-origin src for a PROJECT asset path referenced by a PARENT-realm\n * (shell) preview <img>. On the views:// shell a relative \"/images/foo.png\" resolves to\n * views://studio/images/foo.png, which the browser fetches immediately on paint — a stray request\n * the desktop MutationObserver only rewrites asynchronously. Rendering the src loopback-absolute up\n * front eliminates that race for direct-parent <img> sites.\n *\n * Guarded: this ONLY rewrites when a real cross-origin http(s) loopback is registered (electrobun\n * loopback, canvasUrl set to an absolute http URL) whose origin differs from location.origin.\n * Otherwise — dev server, chromium, electrobun gate-off, and the pre-activate window — it returns\n * the ORIGINAL relative path unchanged, keeping those cases byte-identical (an absolute\n * ${location.origin}/... on the shell would just reintroduce views://... — the exact bug).\n *\n * Only for PROJECT asset srcs; NEVER call it for shell-packaged views:// assets (sp-icons, bundled\n * chrome). Already-absolute inputs (data:/blob:/http/views://) are returned untouched, so it is\n * safe for user-typed media values too.\n *\n * @param {string} path — a project asset path (relative, e.g. \"/public/logo.png\" or \"logo.png\") or\n * an already-absolute URL.\n * @returns {string} The loopback-absolute src when a cross-origin loopback is active, else `path`.\n */\nexport function loopbackAssetSrc(path: string): string {\n if (\n path.startsWith(\"data:\") ||\n path.startsWith(\"blob:\") ||\n path.startsWith(\"http\") ||\n path.startsWith(\"views://\")\n ) {\n return path;\n }\n const origin = canvasBaseOrigin();\n // Only rewrite when a real cross-origin http(s) loopback is registered. When canvasBaseOrigin()\n // Yields location.origin (the views:// shell / dev / chromium / gate-off) an absolute rewrite\n // Would produce views://... on the shell, so fall back to the relative path unchanged.\n if ((origin.startsWith(\"http:\") || origin.startsWith(\"https:\")) && origin !== location.origin) {\n return `${origin}/${path.replace(/^\\.?\\//, \"\")}`;\n }\n return path;\n}\n",
|
|
7
|
-
"/// <reference lib=\"dom\" />\n/**\n * Edit-mode display transforms — extracted from studio.js (Phase 4i). Pure stateless functions that\n * convert document trees for visual editing (template expressions, $map, $switch, empty\n * placeholders).\n */\n\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\n\nconst mediaTags = new Set([\"img\", \"video\", \"source\", \"iframe\", \"audio\"]);\nconst TRANSPARENT_PX =\n \"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\";\n// A neutral, visible gray placeholder for image-like bindings in edit mode (e.g. a component `image`\n// Prop bound to ${...}). The component renders <img src={prop}> internally, so a transparent pixel\n// Would collapse to nothing — a gray SVG box reads as an intentional placeholder instead.\nconst PLACEHOLDER_IMG =\n \"data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='32'%20height='32'%3E%3Crect%20width='32'%20height='32'%20fill='%23d0d0d0'/%3E%3C/svg%3E\";\n\n// Prop/attribute names that feed an <img>/background, so a ${...} binding would otherwise render a\n// Broken image in edit mode. Matched by exact name or common camelCase suffix (featuredImage, heroBg).\nconst IMAGE_KEY_RE =\n /(src|poster|image|bg|background|icon|logo|photo|avatar|thumbnail|cover|banner)$/i;\nfunction isImageUrlKey(key: string): boolean {\n return IMAGE_KEY_RE.test(key);\n}\n\nconst textTags = new Set([\n \"p\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"blockquote\",\n \"li\",\n \"dt\",\n \"dd\",\n \"th\",\n \"td\",\n \"span\",\n \"strong\",\n \"em\",\n \"small\",\n \"mark\",\n \"code\",\n \"abbr\",\n \"q\",\n \"sub\",\n \"sup\",\n \"time\",\n \"a\",\n \"button\",\n \"label\",\n \"legend\",\n \"caption\",\n \"summary\",\n \"pre\",\n \"option\",\n]);\n\nconst containerTags = new Set([\n \"div\",\n \"section\",\n \"article\",\n \"aside\",\n \"header\",\n \"footer\",\n \"main\",\n \"nav\",\n \"figure\",\n \"figcaption\",\n \"details\",\n \"fieldset\",\n \"form\",\n \"ul\",\n \"ol\",\n \"dl\",\n \"table\",\n]);\n\n/** All placeholder classes prepareForEditMode may add to an empty element. */\nexport const EMPTY_PLACEHOLDER_CLASSES = [\n \"empty-text-placeholder\",\n \"empty-container-placeholder\",\n] as const;\n\n/**\n * The empty-placeholder class prepareForEditMode would add for this node, or null. Used by the\n * canvas patcher to keep placeholder classes in sync when patching text without a full render.\n *\n * @param {JxMutableNode} node\n */\nexport function computeEmptyPlaceholderClass(node: JxMutableNode): string | null {\n if (!node.tagName || node.textContent || node.innerHTML) {\n return null;\n }\n // Layout-originated nodes ($__layout, set by markLayoutNodes) are read-only in page context;\n // Edit affordances like \"Click here to add text\" don't apply to them.\n if (node.$__layout) {\n return null;\n }\n if (Array.isArray(node.children) && node.children.length > 0) {\n return null;\n }\n if (textTags.has(node.tagName)) {\n return \"empty-text-placeholder\";\n }\n if (containerTags.has(node.tagName)) {\n return \"empty-container-placeholder\";\n }\n return null;\n}\n\n/**\n * Convert a template string to a displayable expression for edit mode. Replaces ${expr} with ❮ expr\n * ❯ so the runtime renders it as literal text.\n *\n * @param {string} str\n */\nexport function templateToEditDisplay(str: string) {\n return str.replaceAll(/\\$\\{([^}]+)\\}/g, \"\\u276A $1 \\u276B\");\n}\n\n/**\n * Reverse templateToEditDisplay: walk all text nodes in `el` and replace ❪ expr ❫ back to ${expr}\n * so the user edits raw template syntax.\n *\n * @param {HTMLElement} el\n */\nexport function restoreTemplateExpressions(el: HTMLElement) {\n const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);\n while (walker.nextNode()) {\n const node = walker.currentNode as Text;\n if (node.data.includes(\"\\u276A\")) {\n node.data = node.data.replaceAll(/\\u276A\\s*(.*?)\\s*\\u276B/g, \"${$1}\");\n }\n }\n}\n\n/**\n * Build the edit-mode visual for a mapped array: a `<div class=\"repeater-perimeter\">` wrapping a\n * single prepared instance of the map template. Always one element (an empty perimeter when the\n * template is missing) so the array keeps a 1:1 DOM node at its sibling index. The perimeter is an\n * edit-only device — it is never compiled or rendered in preview.\n *\n * @param {JxMutableNode} arrayObj\n * @returns {Record<string, unknown>}\n */\nfunction arrayToPerimeter(arrayObj: JxMutableNode): Record<string, unknown> {\n const template = arrayObj.map;\n return {\n children:\n template && typeof template === \"object\"\n ? [prepareForEditMode(template as JxMutableNode)]\n : [],\n className: \"repeater-perimeter\",\n tagName: \"div\",\n };\n}\n\n/**\n * Prepare a document for edit-mode rendering. Replaces template strings with readable literal text,\n * $prototype:Array with placeholders, and $ref bindings with display labels. Preserves state so the\n * runtime can still initialise scope.\n *\n * @param {JxMutableNode} node\n * @returns {JxMutableNode}\n */\nexport function prepareForEditMode(node: JxMutableNode): JxMutableNode {\n if (!node || typeof node !== \"object\") {\n return node;\n }\n if (Array.isArray(node)) {\n // Arrays of nodes round-trip element-wise; the array itself is not a node.\n return (node as JxMutableNode[]).map((n) => prepareForEditMode(n)) as unknown as JxMutableNode;\n }\n\n // A mapped-array node itself → its edit-mode perimeter (e.g. when the patcher re-renders an\n // Array node directly). Members inside a children array funnel here via the children branch.\n if ((node as Record<string, unknown>).$prototype === \"Array\") {\n return arrayToPerimeter(node) as unknown as JxMutableNode;\n }\n\n const /** @type {Record<string, unknown>} */ obj = node as Record<string, unknown>;\n\n const out: Record<string, unknown> = {};\n let needsMediaPlaceholder = false;\n const isMediaElement = mediaTags.has((obj.tagName as string) || \"\");\n\n // Check if this media element lacks a resolvable src (top-level or in attributes)\n if (isMediaElement) {\n const attrs = obj.attributes as Record<string, unknown> | undefined;\n const topSrc = obj.src;\n const attrSrc = attrs?.src;\n const topPoster = obj.poster;\n const attrPoster = attrs?.poster;\n const hasSrc = (topSrc && topSrc !== \"\") || (attrSrc && attrSrc !== \"\");\n const hasPoster = (topPoster && topPoster !== \"\") || (attrPoster && attrPoster !== \"\");\n if (!hasSrc && !hasPoster) {\n needsMediaPlaceholder = true;\n }\n }\n\n for (const [k, v] of Object.entries(obj)) {\n if (k === \"state\" || k === \"$media\" || k === \"$elements\") {\n out[k] = v; // Preserve as-is for runtime resolution\n } else if (k === \"$props\" && v && typeof v === \"object\") {\n // Process $props values: convert template strings to display format\n const propsOut: Record<string, unknown> = {};\n for (const [pk, pv] of Object.entries(v)) {\n if (typeof pv === \"string\" && pv.includes(\"${\")) {\n // Image-like prop → neutral placeholder (the component renders it as an <img src>); link\n // Targets → inert \"\"; everything else → the readable ❪ expr ❫ binding text.\n if (isImageUrlKey(pk)) {\n propsOut[pk] = PLACEHOLDER_IMG;\n } else if (pk === \"href\" || pk === \"action\") {\n propsOut[pk] = \"\";\n } else {\n propsOut[pk] = templateToEditDisplay(pv);\n }\n } else if (pv && typeof pv === \"object\" && (pv as Record<string, unknown>).$ref) {\n const ref = (pv as Record<string, unknown>).$ref as string;\n const label = ref.startsWith(\"#/state/\") ? ref.slice(8) : ref;\n propsOut[pk] = `{${label}}`;\n } else {\n propsOut[pk] = pv;\n }\n }\n out[k] = propsOut;\n } else if (k === \"children\") {\n if (Array.isArray(v)) {\n // Each member recurses; array pseudo-elements become a single repeater-perimeter element\n // (via the top-level array case) so they stay a 1:1 DOM node among their siblings.\n out.children = v.map((c) => prepareForEditMode(c as JxMutableNode));\n } else if (\n v &&\n typeof v === \"object\" &&\n (v as Record<string, unknown>).$prototype === \"Array\"\n ) {\n // Legacy whole-children repeater → a single perimeter as the sole child.\n out.children = [prepareForEditMode(v as JxMutableNode)];\n } else {\n out.children = prepareForEditMode(v as JxMutableNode);\n }\n } else if (k === \"cases\" && obj.$switch && v && typeof v === \"object\") {\n // Replace $switch cases with a placeholder showing the first case or a label\n const caseKeys = Object.keys(v);\n if (caseKeys.length > 0) {\n const firstCase = (v as Record<string, unknown>)[caseKeys[0]!];\n out.children =\n firstCase && typeof firstCase === \"object\" && !(firstCase as Record<string, unknown>).$ref\n ? [prepareForEditMode(firstCase as JxMutableNode)]\n : [\n {\n style: {\n background: \"color-mix(in srgb, var(--danger) 8%, transparent)\",\n border: \"1px dashed color-mix(in srgb, var(--danger) 40%, transparent)\",\n borderRadius: \"4px\",\n color: \"var(--danger)\",\n fontFamily: \"'JetBrains Mono', 'SF Mono', 'Fira Code', monospace\",\n fontSize: \"11px\",\n fontStyle: \"italic\",\n padding: \"6px 10px\",\n },\n tagName: \"div\",\n textContent: `[$switch: ${caseKeys.join(\" | \")}]`,\n },\n ];\n }\n } else if (k === \"attributes\" && isMediaElement && v && typeof v === \"object\") {\n // Process attributes for media elements: replace src/poster with transparent pixel\n const attrs = v as Record<string, unknown>;\n const processed: Record<string, unknown> = {};\n for (const [ak, av] of Object.entries(attrs)) {\n if (ak === \"src\" || ak === \"poster\") {\n if (typeof av === \"string\" && av !== \"\" && !av.includes(\"${\")) {\n processed[ak] = av;\n } else {\n needsMediaPlaceholder = true;\n processed[ak] = TRANSPARENT_PX;\n }\n } else if (typeof av === \"string\" && av.includes(\"${\")) {\n const isUrlAttr = ak === \"href\" || ak === \"action\";\n processed[ak] = isUrlAttr ? \"\" : templateToEditDisplay(av);\n } else if (av && typeof av === \"object\" && (av as Record<string, unknown>).$ref) {\n const ref = (av as Record<string, unknown>).$ref as string;\n const label = ref.startsWith(\"#/state/\") ? ref.slice(8) : ref;\n processed[ak] = `{${label}}`;\n } else {\n processed[ak] = av;\n }\n }\n out.attributes = processed;\n } else if (k === \"style\") {\n // Replace template strings in style values with empty strings\n if (v && typeof v === \"object\") {\n const s: Record<string, unknown> = {};\n for (const [sk, sv] of Object.entries(v)) {\n s[sk] = typeof sv === \"string\" && sv.includes(\"${\") ? \"\" : sv;\n }\n out.style = s;\n } else {\n out.style = v;\n }\n } else if (typeof v === \"string\" && v.includes(\"${\")) {\n // Template string in a display property → show raw expression\n const isMediaSrc =\n (k === \"src\" || k === \"poster\") && mediaTags.has((obj.tagName as string) || \"\");\n if (isMediaSrc) {\n needsMediaPlaceholder = true;\n out[k] = TRANSPARENT_PX;\n } else {\n const isUrlAttr = k === \"src\" || k === \"href\" || k === \"poster\" || k === \"action\";\n out[k] = isUrlAttr ? \"\" : templateToEditDisplay(v);\n }\n } else if (v && typeof v === \"object\" && (v as Record<string, unknown>).$ref) {\n // $ref binding → show ref path as literal text\n const ref = (v as Record<string, unknown>).$ref as string;\n const label = ref.startsWith(\"#/state/\") ? ref.slice(8) : ref;\n const isMediaSrc =\n (k === \"src\" || k === \"poster\") && mediaTags.has((obj.tagName as string) || \"\");\n if (isMediaSrc) {\n needsMediaPlaceholder = true;\n out[k] = TRANSPARENT_PX;\n } else {\n out[k] = `{${label}}`;\n }\n } else {\n // Empty src/poster on media elements → use transparent pixel placeholder\n if (\n (k === \"src\" || k === \"poster\") &&\n v === \"\" &&\n mediaTags.has((obj.tagName as string) || \"\")\n ) {\n needsMediaPlaceholder = true;\n out[k] = TRANSPARENT_PX;\n } else {\n out[k] = prepareForEditMode(v as JxMutableNode);\n }\n }\n }\n\n // Mark empty elements with placeholder classes for design-mode visibility\n const placeholderClass = computeEmptyPlaceholderClass(out as JxMutableNode);\n if (placeholderClass) {\n out.className = out.className ? `${out.className} ${placeholderClass}` : placeholderClass;\n }\n\n // Media elements with missing/dynamic src get a placeholder class\n if (needsMediaPlaceholder) {\n const cls = (out.className as string) || \"\";\n if (!cls.includes(\"empty-media-placeholder\")) {\n out.className = cls ? `${cls} empty-media-placeholder` : \"empty-media-placeholder\";\n }\n }\n\n return out;\n}\n",
|
|
8
|
-
"/// <reference lib=\"dom\" />\n/**\n * Dynamic route-param helpers for the tab-bar's $params picker.\n *\n * A page like `pages/products/[sku].json` declares its candidate values in a `$paths` block (spec\n * §4.3). At build time the compiler expands those into concrete routes (`resolvePathEntries` in\n * `@jxsuite/compiler`); in the studio the same shapes are resolved live so the author can pick one\n * value to render. The chosen values are substituted into the canvas render document\n * (`substitutePreviewParams`), which mirrors what the compiler's context injection produces for the\n * matching built page.\n */\n\nimport { getPlatform } from \"./platform\";\nimport { loadExtensions } from \"./format/format-host\";\nimport type { JxMutableNode, JxPathsDef } from \"@jxsuite/schema/types\";\n\n/** Param name → candidate values, in `$paths` declaration order. */\nexport type ParamValues = Record<string, string[]>;\n\n/** Bracket route segments: `[param]` (named) and `[...param]` (catch-all). */\nconst PARAM_SEGMENT = /\\[\\.\\.\\.(\\w+)\\]|\\[(\\w+)\\]/g;\n\n/**\n * Param names declared by a document path's bracket segments, e.g. `pages/products/[sku].json` →\n * `[\"sku\"]`. Mirrors the compiler's `fileToRoute` parsing.\n *\n * @param {string | null | undefined} documentPath\n * @returns {string[]}\n */\nexport function dynamicRouteParams(documentPath: string | null | undefined) {\n if (!documentPath) {\n return [];\n }\n const params: string[] = [];\n for (const match of documentPath.matchAll(PARAM_SEGMENT)) {\n params.push((match[1] ?? match[2])!);\n }\n return params;\n}\n\n/**\n * URL pattern for a page document path, mirroring the compiler's `fileToRoute`:\n * `pages/products/[sku].json` → `/products/:sku`, `pages/index.json` → `/`.\n *\n * @param {string | null | undefined} documentPath\n * @returns {string}\n */\nexport function documentUrlPattern(documentPath: string | null | undefined) {\n if (!documentPath) {\n return \"/\";\n }\n let urlPath = documentPath\n .replace(/^\\.\\//, \"\")\n .replace(/^pages\\//, \"\")\n .replace(/\\.[^/.]+$/, \"\");\n if (urlPath.endsWith(\"/index\")) {\n urlPath = urlPath.slice(0, -6) || \"/\";\n } else if (urlPath === \"index\") {\n urlPath = \"/\";\n }\n if (!urlPath.startsWith(\"/\")) {\n urlPath = `/${urlPath}`;\n }\n return urlPath.replaceAll(PARAM_SEGMENT, (_match, spread: string, named: string) =>\n spread ? \"*\" : `:${named}`,\n );\n}\n\n/**\n * The `$paths` declaration of an open document. JSON pages carry it on the document root;\n * format-class pages (markdown) keep it in the frontmatter.\n *\n * @param {{ document?: unknown; frontmatter?: Record<string, unknown> }} doc\n * @returns {JxPathsDef | null}\n */\nexport function pagePathsDef(doc: {\n document?: JxMutableNode | null;\n frontmatter?: Record<string, unknown> | null;\n}) {\n const fromDoc = (doc.document as { $paths?: JxPathsDef } | null | undefined)?.$paths;\n const fromFrontmatter = doc.frontmatter?.$paths as JxPathsDef | undefined;\n return fromDoc ?? fromFrontmatter ?? null;\n}\n\nconst valueCache = new Map<string, Promise<ParamValues>>();\n\n/** Drop all cached enumerations (e.g. after content files change). */\nexport function invalidateParamValues() {\n valueCache.clear();\n}\n\n/**\n * Enumerate candidate values for each param declared by a `$paths` block. Results are cached per\n * (documentPath, $paths) pair; failures are not cached so a transient backend error retries on the\n * next call.\n *\n * @param {string | null | undefined} documentPath - Cache key component\n * @param {JxPathsDef | null} pathsDef\n * @returns {Promise<ParamValues>}\n */\nexport function loadParamValues(\n documentPath: string | null | undefined,\n pathsDef: JxPathsDef | null,\n) {\n if (!pathsDef) {\n return Promise.resolve({} as ParamValues);\n }\n const key = `${documentPath ?? \"\"}::${JSON.stringify(pathsDef)}`;\n let pending = valueCache.get(key);\n if (!pending) {\n pending = resolveParamValues(pathsDef).catch((error: unknown) => {\n valueCache.delete(key);\n console.warn(\"page-params: failed to enumerate $paths values:\", error);\n return {} as ParamValues;\n });\n valueCache.set(key, pending);\n }\n return pending;\n}\n\n/**\n * Resolve one `$paths` shape to values, mirroring the compiler's `resolvePathEntries`.\n *\n * @param {JxPathsDef} pathsDef\n * @returns {Promise<ParamValues>}\n */\nasync function resolveParamValues(pathsDef: JxPathsDef): Promise<ParamValues> {\n // Legacy: array of param objects — group values per param key\n if (Array.isArray(pathsDef)) {\n const out: ParamValues = {};\n for (const entry of pathsDef) {\n for (const [param, value] of Object.entries(entry)) {\n pushValue(out, param, value);\n }\n }\n return out;\n }\n\n // Content type-based: { contentType: \"blog\", param: \"slug\", field: \"id\" } — an open extension\n // Discriminator member on JxPathsDef, so narrow to string. Resolved through the backend's\n // ContentCollection pipeline (the same one the canvas's ContentEntry uses), so every offered\n // Value is guaranteed to resolve in preview.\n if (\n \"contentType\" in pathsDef &&\n typeof pathsDef.contentType === \"string\" &&\n pathsDef.contentType\n ) {\n const param = pathsDef.param ?? \"slug\";\n const field = pathsDef.field ?? \"id\";\n const entries = (await resolveContentCollection(pathsDef.contentType)) as {\n id?: unknown;\n data?: Record<string, unknown>;\n }[];\n const out: ParamValues = { [param]: [] };\n if (!Array.isArray(entries)) {\n return out;\n }\n for (const entry of entries) {\n pushValue(out, param, field === \"id\" ? entry.id : (entry.data?.[field] ?? entry.id));\n }\n return out;\n }\n\n // Explicit values: { values: [\"en\", \"fr\"], param: \"lang\" }\n if (\"values\" in pathsDef && Array.isArray(pathsDef.values)) {\n const param = pathsDef.param ?? \"value\";\n const out: ParamValues = { [param]: [] };\n for (const value of pathsDef.values) {\n pushValue(out, param, value);\n }\n return out;\n }\n\n // Data file ref: { \"$ref\": \"./data/products.json\", param: \"id\", field: \"sku\" } — `$ref` also\n // Reaches here as an open discriminator key, so narrow to a non-empty string.\n if (\"$ref\" in pathsDef && typeof pathsDef.$ref === \"string\" && pathsDef.$ref) {\n const param = pathsDef.param ?? \"id\";\n const field = pathsDef.field ?? \"id\";\n const content = await getPlatform().readFile(pathsDef.$ref.replace(/^\\.\\//, \"\"));\n const data = JSON.parse(content) as unknown;\n const out: ParamValues = { [param]: [] };\n if (!Array.isArray(data)) {\n return out;\n }\n for (const item of data as Record<string, unknown>[]) {\n pushValue(out, param, item?.[field] ?? item?.id ?? item);\n }\n return out;\n }\n\n return {};\n}\n\n/**\n * The `$src` of the ContentCollection class from the enabled extensions payload — whichever\n * extension's manifest declares a class named `ContentCollection` (its backend-resolved descriptor\n * path feeds `/__jx_resolve__` directly). Platforms without an extensions payload fall back to the\n * historical parser-package specifier.\n *\n * @returns {Promise<string>}\n */\nasync function contentCollectionSrc(): Promise<string> {\n const extensions = await loadExtensions();\n for (const ext of extensions) {\n const cls = ext.classes?.find((c) => c.name === \"ContentCollection\");\n if (cls) {\n return cls.path;\n }\n }\n return \"@jxsuite/parser/ContentCollection.class.json\";\n}\n\n/**\n * Resolve a ContentCollection for a content type via the PAL, falling back to a plain dev-proxy\n * fetch on platforms that predate `resolveClass`.\n *\n * @param {string} contentType\n * @returns {Promise<unknown>}\n */\nasync function resolveContentCollection(contentType: string) {\n const body = {\n $prototype: \"ContentCollection\",\n $src: await contentCollectionSrc(),\n contentType,\n };\n const platform = getPlatform();\n if (platform.resolveClass) {\n return platform.resolveClass(body);\n }\n return fetch(\"/__jx_resolve__\", {\n body: JSON.stringify(body),\n headers: { \"content-type\": \"application/json\" },\n method: \"POST\",\n }).then((res) => {\n if (!res.ok) {\n throw new Error(`Class resolution failed: ${res.status}`);\n }\n return res.json() as Promise<unknown>;\n });\n}\n\n/**\n * @param {ParamValues} out\n * @param {string} param\n * @param {unknown} value\n */\nfunction pushValue(out: ParamValues, param: string, value: unknown) {\n if (value === null || value === undefined || value === \"\") {\n return;\n }\n const str = String(value);\n const list = (out[param] ??= []);\n if (!list.includes(str)) {\n list.push(str);\n }\n}\n\n/**\n * Substitute chosen param values into a canvas render document:\n *\n * - Every `{ \"$ref\": \"#/$params/<name>\" }` value with a chosen `<name>` becomes the literal string\n * (the exact dereference `ContentEntry.resolve()` performs against `route._pathParams`), and\n * - `state.$page` is injected mirroring the compiler's `injectContext`, so `${state.$page.params.x}`\n * template expressions render.\n *\n * Pure: returns a rebuilt tree. The design/edit render doc shares node references with the tab's\n * source document (stripEventHandlers/prepareForEditMode shallow-rebuild), so in-place mutation\n * here would corrupt the document being edited and saved.\n *\n * @param {JxMutableNode} renderDoc\n * @param {Record<string, string>} params\n * @param {string | null | undefined} documentPath\n * @returns {JxMutableNode}\n */\nexport function substitutePreviewParams(\n renderDoc: JxMutableNode,\n params: Record<string, string>,\n documentPath: string | null | undefined,\n): JxMutableNode {\n if (Object.keys(params).length === 0) {\n return renderDoc;\n }\n const doc = substituteParamRefs(renderDoc, params) as JxMutableNode & {\n state?: Record<string, unknown>;\n title?: unknown;\n };\n doc.state ??= {};\n doc.state.$page = {\n params: { ...params },\n title: typeof doc.title === \"string\" ? doc.title : \"\",\n url: documentUrlPattern(documentPath),\n };\n return doc;\n}\n\n/**\n * State keys whose entries are class prototypes ($prototype + $src) referencing a route param.\n * These are the entries `substitutePreviewParams` rewrites, and the ones `resolveParamBoundState`\n * bakes.\n *\n * @param {Record<string, unknown> | null | undefined} state - The ORIGINAL document state (with\n * `$ref`s intact — substitution removes the marker)\n * @returns {string[]}\n */\nexport function paramBoundStateKeys(state: Record<string, unknown> | null | undefined) {\n if (!state) {\n return [];\n }\n return Object.keys(state).filter((key) => {\n const entry = state[key] as Record<string, unknown> | null;\n return (\n entry &&\n typeof entry === \"object\" &&\n typeof entry.$prototype === \"string\" &&\n typeof entry.$src === \"string\" &&\n JSON.stringify(entry).includes('\"#/$params/')\n );\n });\n}\n\n/**\n * Resolve substituted class-prototype state entries through the backend and bake the values into\n * `renderDoc.state` — compiler parity: the built site resolves ContentEntry/ContentCollection\n * BEFORE templates run. Without baking, the iframe runtime resolves these entries asynchronously\n * (null on the first render pass), so preview templates like `${state.product.data.title}`\n * dereference null and abort the whole render.\n *\n * Failures leave the entry in place (the runtime's own async resolution remains the fallback).\n *\n * @param {JxMutableNode} renderDoc - The substituted render doc (mutated in place — it is the fresh\n * rebuild from substitutePreviewParams, never the source doc)\n * @param {string[]} keys - From paramBoundStateKeys(originalDoc.state)\n * @param {string | undefined} docBase - Document base URL for relative-$src rebasing\n */\nexport async function resolveParamBoundState(\n renderDoc: JxMutableNode,\n keys: string[],\n docBase?: string,\n) {\n if (keys.length === 0) {\n return;\n }\n const platform = getPlatform();\n if (!platform.resolveClass) {\n return;\n }\n const { state } = renderDoc as { state?: Record<string, unknown> };\n if (!state) {\n return;\n }\n await Promise.all(\n keys.map(async (key) => {\n const entry = state[key];\n if (!entry || typeof entry !== \"object\") {\n return;\n }\n try {\n state[key] = await platform.resolveClass!({\n ...(entry as Record<string, unknown>),\n ...(docBase ? { $base: docBase } : {}),\n });\n } catch (error) {\n console.warn(`page-params: failed to resolve state.${key} for preview:`, error);\n }\n }),\n );\n}\n\n/**\n * @param {unknown} node\n * @param {Record<string, string>} params\n * @returns {unknown} — a rebuilt copy with matched param refs replaced by literals\n */\nfunction substituteParamRefs(node: unknown, params: Record<string, string>): unknown {\n const replaced = paramRefValue(node, params);\n if (replaced !== null) {\n return replaced;\n }\n if (!node || typeof node !== \"object\") {\n return node;\n }\n if (Array.isArray(node)) {\n return node.map((item) => substituteParamRefs(item, params));\n }\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(node)) {\n out[key] = substituteParamRefs(value, params);\n }\n return out;\n}\n\n/**\n * The chosen literal for a `{ \"$ref\": \"#/$params/<name>\" }` value, or null when the value is not a\n * param ref (or no value was chosen for it).\n *\n * @param {unknown} value\n * @param {Record<string, string>} params\n * @returns {string | null}\n */\nfunction paramRefValue(value: unknown, params: Record<string, string>) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return null;\n }\n const ref = (value as { $ref?: unknown }).$ref;\n if (typeof ref !== \"string\" || !ref.startsWith(\"#/$params/\")) {\n return null;\n }\n return params[ref.slice(\"#/$params/\".length)] ?? null;\n}\n",
|
|
9
|
-
"/**\n * Component test props (M6) — the previewParams mirror for component docs. A non-instantiated\n * component definition renders on the canvas with its state defaults; \"test values\" let the author\n * pick per-prop values that the canvas render seeds into the definition's state, so templates,\n * dataScope snapshots, and live/snapshot expression previews all see real data.\n *\n * Pure and DOM-free: {@link componentPropEntries} derives the editable prop rows from the doc's\n * state (the same plain-data entries the CEM export publishes as fields), and\n * {@link substitutePreviewProps} rebuilds a render doc with chosen values seeded — never mutating\n * the source document (the substitutePreviewParams contract).\n */\n\nimport type { JsonValue } from \"./types\";\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\n\n/** One editable prop row: the state key and its current default value (undefined = none). */\nexport interface ComponentPropEntry {\n name: string;\n value: JsonValue | undefined;\n}\n\n/** Whether the doc is a component definition (a custom-element root) rather than a page. */\nexport function isComponentDoc(doc: JxMutableNode | null | undefined): boolean {\n return typeof doc?.tagName === \"string\" && doc.tagName.includes(\"-\");\n}\n\n/**\n * Classify a state entry as a prop (plain data the CEM export publishes as a field): naked\n * literals/arrays/objects and expanded/typed signal defs — never expressions, computeds, functions,\n * templates, or $prototype data sources (overriding those would clobber behavior, the boundPropKey\n * rule).\n */\nfunction propShape(def: unknown): \"literal\" | \"signal\" | null {\n if (def === null || typeof def === \"number\" || typeof def === \"boolean\") {\n return \"literal\";\n }\n if (typeof def === \"string\") {\n return def.includes(\"${\") ? null : \"literal\"; // Template strings render computed values.\n }\n if (Array.isArray(def)) {\n return \"literal\";\n }\n if (typeof def === \"object\") {\n const d = def as Record<string, unknown>;\n if (d.$expression || d.$compute || d.$prototype || d.$handler) {\n return null;\n }\n // An expanded signal ({default}) or a typed prop def ({type}/schema keywords) seeds through\n // Its `default`; any other plain object is a Shape-1 naked value.\n return \"default\" in d || \"type\" in d ? \"signal\" : \"literal\";\n }\n return null;\n}\n\n/**\n * The component's editable prop entries, derived from the doc's state — non-private plain-data\n * entries with their current default values (the CEM-export \"field\" subset).\n */\nexport function componentPropEntries(doc: JxMutableNode | null | undefined): ComponentPropEntry[] {\n const state = (doc?.state ?? {}) as Record<string, unknown>;\n const out: ComponentPropEntry[] = [];\n for (const [name, def] of Object.entries(state)) {\n if (name.startsWith(\"#\")) {\n continue; // Private entries are not props (the CEM-export rule).\n }\n const shape = propShape(def);\n if (!shape) {\n continue;\n }\n const value =\n shape === \"signal\"\n ? ((def as { default?: JsonValue }).default as JsonValue | undefined)\n : (def as JsonValue);\n out.push({ name, value });\n }\n return out;\n}\n\n/**\n * Rebuild `renderDoc` with the chosen test-prop values seeded into its state: a literal entry is\n * replaced by the value; a signal/typed entry keeps its metadata and gets the value as `default`\n * (exactly what buildScope reads). Pure — returns a shallow rebuild; the render doc shares node\n * references with the tab's source document, so in-place mutation would corrupt the edited doc.\n */\nexport function substitutePreviewProps(\n renderDoc: JxMutableNode,\n props: Record<string, JsonValue>,\n): JxMutableNode {\n const state = { ...((renderDoc.state ?? {}) as Record<string, unknown>) };\n let seeded = false;\n for (const [name, value] of Object.entries(props)) {\n const shape = propShape(state[name]);\n if (!shape) {\n continue; // Unknown/behavioral entries are never overridden by a stale test value.\n }\n state[name] =\n shape === \"signal\" ? { ...(state[name] as Record<string, unknown>), default: value } : value;\n seeded = true;\n }\n if (!seeded) {\n return renderDoc;\n }\n return { ...renderDoc, state } as JxMutableNode;\n}\n",
|
|
10
|
-
"/**\n * Deterministic mapping from Function-def `$src` module specifiers to bundled asset URLs, plus the\n * asset-mount math that publishes files living outside the project root at a stable site URL.\n * Shared between the compiler's sidecar bundler (which writes the bundle) and extension `lower()`\n * implementations (which emit the URL into client code) so neither needs to depend on the other.\n *\n * The mapping is intentionally hash-free: the same specifier always yields the same URL, letting\n * lowered defs reference bundles the compiler produces later in the build. Distinct specifiers that\n * collide on a slug are rejected by the bundler at build time.\n *\n * Pure string math only — no node imports — so browser hosts can import this module.\n */\n\n/** Prefix for npm package specifiers in `$src` (spec §12): `npm:<pkg>[/subpath]`. */\nexport const NPM_SPECIFIER_PREFIX = \"npm:\";\n\n/** URL directory (under the site root) where bundled sidecars are written. */\nexport const SIDECAR_ASSET_DIR = \"/assets/\";\n\n/** True when a `$src` specifier names an npm package rather than a project file. */\nexport function isNpmSpecifier(specifier: string): boolean {\n return specifier.startsWith(NPM_SPECIFIER_PREFIX);\n}\n\n/**\n * Map a Function-def `$src` specifier to its bundled asset URL.\n *\n * `npm:@jxsuite/search/client` → `/assets/jxsuite-search-client.js` `./lib/search-helpers.ts` →\n * `/assets/lib-search-helpers.js`\n */\nexport function sidecarAssetPath(specifier: string): string {\n let base = specifier;\n if (isNpmSpecifier(base)) {\n base = base.slice(NPM_SPECIFIER_PREFIX.length);\n }\n base = base\n .replace(/^\\.\\//, \"\")\n .replace(/\\.(js|ts|mjs|mts)$/, \"\")\n .replaceAll(\"@\", \"\")\n .replaceAll(/[/\\\\]+/g, \"-\")\n .replaceAll(/[^\\w.-]/g, \"-\")\n .replaceAll(/-+/g, \"-\")\n .replaceAll(/^-|-$/g, \"\");\n return `${SIDECAR_ASSET_DIR}${base}.js`;\n}\n\n// ─── Asset mounts (specs/extensions.md §8.5) ─────────────────────────────────\n\n/**\n * A site URL prefix backed by a real directory. Extensions declaring the `assets` capability return\n * mounts so hosts can publish files that live outside the project root (an external content\n * source's co-located images) without knowing anything about the section that owns them.\n */\nexport interface AssetMount {\n /** Site-absolute URL prefix, e.g. `/content/docs` (no trailing slash). */\n urlPrefix: string;\n /** Absolute directory the prefix maps onto. */\n dir: string;\n}\n\n/** Normalize a path or prefix for comparison: forward slashes, no trailing slash. */\nfunction normalizeDir(value: string): string {\n const forward = value.replaceAll(\"\\\\\", \"/\");\n return forward.length > 1 && forward.endsWith(\"/\") ? forward.slice(0, -1) : forward;\n}\n\n/** Normalize a mount's URL prefix: leading slash, no trailing slash. */\nexport function normalizeAssetPrefix(prefix: string): string {\n const forward = normalizeDir(prefix);\n return forward.startsWith(\"/\") ? forward : `/${forward}`;\n}\n\n/** Mounts sorted so the most specific (longest) candidate matches first. */\nfunction bySpecificity(mounts: readonly AssetMount[], key: \"dir\" | \"urlPrefix\"): AssetMount[] {\n return [...mounts].toSorted((a, b) => b[key].length - a[key].length);\n}\n\n/** True when `path` is `dir` itself or sits underneath it (both already normalized). */\nfunction isUnder(path: string, dir: string): boolean {\n return path === dir || path.startsWith(`${dir}/`);\n}\n\n/**\n * Map an absolute file path to its mounted site URL, or null when no mount contains it. Path\n * segments are percent-encoded so the URL survives HTML attributes; `resolveAssetUrl` reverses it.\n *\n * @param {readonly AssetMount[]} mounts\n * @param {string} absolutePath - Absolute filesystem path\n * @returns {string | null}\n */\nexport function assetUrlFor(mounts: readonly AssetMount[], absolutePath: string): string | null {\n const path = normalizeDir(absolutePath);\n for (const mount of bySpecificity(mounts, \"dir\")) {\n const dir = normalizeDir(mount.dir);\n if (!isUnder(path, dir) || path === dir) {\n continue;\n }\n const rest = path.slice(dir.length + 1);\n const encoded = rest\n .split(\"/\")\n .map((segment) => encodeURIComponent(segment))\n .join(\"/\");\n return `${normalizeAssetPrefix(mount.urlPrefix)}/${encoded}`;\n }\n return null;\n}\n\n/**\n * Map a mounted site URL back to its absolute file path, or null when it matches no mount. Query\n * and hash are dropped, the path is decoded ONCE (a still-encoded dot or slash after that decode is\n * a bypass attempt and is rejected), and `.`/`..` segments are refused outright — so the result can\n * never escape the mount directory.\n *\n * @param {readonly AssetMount[]} mounts\n * @param {string} url - Site-absolute URL (e.g. `/content/docs/images/hero.png`)\n * @returns {string | null}\n */\nexport function resolveAssetUrl(mounts: readonly AssetMount[], url: string): string | null {\n const pathname = url.split(\"#\")[0]!.split(\"?\")[0]!;\n if (!pathname.startsWith(\"/\")) {\n return null;\n }\n let decoded: string;\n try {\n decoded = decodeURIComponent(pathname);\n } catch {\n return null;\n }\n if (/%2e|%2f/i.test(decoded)) {\n return null;\n }\n for (const mount of bySpecificity(mounts, \"urlPrefix\")) {\n const prefix = normalizeAssetPrefix(mount.urlPrefix);\n if (!decoded.startsWith(`${prefix}/`)) {\n continue;\n }\n const rest = decoded.slice(prefix.length + 1);\n const segments = rest.split(\"/\");\n if (segments.some((s) => s === \"\" || s === \".\" || s === \"..\")) {\n return null;\n }\n return `${normalizeDir(mount.dir)}/${segments.join(\"/\")}`;\n }\n return null;\n}\n\n/** Characters that terminate a URL inside markup: quotes, whitespace, CSS `url()` parens, `<>`. */\nconst URL_TERMINATOR = String.raw`\"'\\s<>()\\\\`;\n\n/**\n * Collect every mounted URL referenced by a compiled artifact (HTML, CSS, JSON-LD). Scanning output\n * text rather than the document tree catches references wherever they came from — markdown images,\n * hand-authored pages, `$head` metadata, `url()` in stylesheets — with no per-attribute knowledge.\n *\n * @param {string} text - Compiled HTML or CSS\n * @param {readonly AssetMount[]} mounts\n * @returns {string[]} Unique mounted URLs, in first-seen order\n */\nexport function collectAssetUrls(text: string, mounts: readonly AssetMount[]): string[] {\n const found = new Set<string>();\n for (const mount of mounts) {\n const prefix = normalizeAssetPrefix(mount.urlPrefix);\n const pattern = new RegExp(\n `${prefix.replaceAll(/[.*+?^${}()|[\\]\\\\]/g, String.raw`\\$&`)}/[^${URL_TERMINATOR}]+`,\n \"g\",\n );\n for (const match of text.matchAll(pattern)) {\n const url = match[0].split(\"#\")[0]!.split(\"?\")[0]!;\n // A trailing slash names a directory, not a file — prose quoting the mount prefix\n // (\"published under /content/docs/images/\") is a mention, not a reference.\n if (!url.endsWith(\"/\")) {\n found.add(url);\n }\n }\n }\n return [...found].filter(Boolean);\n}\n",
|
|
11
|
-
"/**\n * Content-relative asset references, resolved for the canvas.\n *\n * A content entry references media relative to ITSELF — `` — so the file\n * reads correctly in a plain markdown editor and so collections sourced outside the project root\n * still reach their media (specs/site-architecture.md §9.3). On the built site the collection\n * loader rewrites those refs onto the content type's asset mount,\n * `/content/<type>/images/hero.png`.\n *\n * Studio opens an entry as a STANDALONE document, so that loader never runs and the canvas would\n * render the authored path verbatim — which the browser resolves against `canvas.html`, not the\n * entry. This module applies the same mount mapping to the render document so the canvas previews\n * the URL production actually serves.\n *\n * The URL math is `assetUrlFor` from `@jxsuite/schema/asset-paths` — the same function the loader\n * and the compiler use — so the three cannot drift. It is pure string containment, which works\n * unchanged on the project-relative paths Studio deals in.\n *\n * The SOURCE document is never touched: the authored relative ref is what gets serialized back to\n * disk, and the properties panel shows the author what they wrote.\n *\n * One deliberate divergence from the loader: it declines to rewrite a ref whose target does not\n * exist (`existsSync`), leaving an unresolvable path alone rather than changing its meaning. The\n * browser has no filesystem, so this rewrites optimistically. A missing file is broken either way;\n * pointing at the mount URL is the more informative failure, and it is the URL the built site would\n * have attempted.\n *\n * @docs studio/projects/media\n */\n\nimport { assetUrlFor } from \"@jxsuite/schema/asset-paths\";\nimport { projectState } from \"../store\";\nimport { activeTab } from \"../workspace/workspace\";\nimport type { AssetMount } from \"@jxsuite/schema/asset-paths\";\nimport type { ContentSectionEntry } from \"../types\";\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\n\n/** Node keys whose value is a media reference. Mirrors `ASSET_KEYS` in the content loader. */\nconst ASSET_KEYS = [\"src\", \"poster\"] as const;\n\n/** Content type names safe in a URL path segment. Mirrors `SAFE_TYPE_NAME` in the content loader. */\nconst SAFE_TYPE_NAME = /^[\\w.~-]+$/;\n\n/** The project.json section key content types live under; also their URL namespace. */\nconst SECTION_KEY = \"content\";\n\n/**\n * A value that is already a URL, a template, or a fragment — never a content-relative file. Mirrors\n * `isNonRelativeRef` in the content loader.\n */\nfunction isNonRelativeRef(value: string): boolean {\n return (\n value === \"\" ||\n value.startsWith(\"/\") ||\n value.startsWith(\"#\") ||\n value.includes(\"${\") ||\n /^[a-z][\\w+.-]*:/i.test(value)\n );\n}\n\n/** Strip `./` and any trailing slash from a configured `source`, the way collectionDirs does. */\nfunction normalizeSource(source: string): string {\n return source.replaceAll(\"\\\\\", \"/\").replace(/^\\.\\//, \"\").replace(/\\/+$/, \"\");\n}\n\n/**\n * Resolve `ref` against `dir` in a pure, POSIX-ish way — no `node:path`, and no leading-slash\n * assumption, because Studio's paths are project-relative. Returns null when the result would climb\n * above the project root (`../` past the top), which can never name a mounted file.\n */\nexport function resolveRelativePath(dir: string, ref: string): string | null {\n const segments = dir === \"\" || dir === \".\" ? [] : dir.replaceAll(\"\\\\\", \"/\").split(\"/\");\n const out = segments.filter((s) => s !== \"\" && s !== \".\");\n for (const segment of ref.replaceAll(\"\\\\\", \"/\").split(\"/\")) {\n if (segment === \"\" || segment === \".\") {\n continue;\n }\n if (segment === \"..\") {\n if (out.length === 0) {\n return null; // Escapes the project root.\n }\n out.pop();\n continue;\n }\n out.push(segment);\n }\n return out.join(\"/\");\n}\n\n/** The directory portion of a project-relative file path (`\"\"` for a root-level file). */\nexport function dirOf(path: string): string {\n const normalized = path.replaceAll(\"\\\\\", \"/\");\n const slash = normalized.lastIndexOf(\"/\");\n return slash === -1 ? \"\" : normalized.slice(0, slash);\n}\n\n/**\n * The asset mount for the content type that owns `documentPath`, or null when the document is not a\n * directory-backed content entry.\n *\n * Only in-project sources can match: an entry Studio can address project-relatively is by\n * definition inside the project, and a source pointing elsewhere (`../../docs`) names files the\n * file tree cannot reach in the first place.\n */\nexport function contentMountFor(\n documentPath: string | null | undefined,\n content: Record<string, ContentSectionEntry> | null | undefined,\n): AssetMount | null {\n if (!documentPath || !content) {\n return null;\n }\n const path = documentPath.replaceAll(\"\\\\\", \"/\").replace(/^\\.\\//, \"\");\n let best: AssetMount | null = null;\n for (const [name, def] of Object.entries(content)) {\n if (!def?.source || !SAFE_TYPE_NAME.test(name)) {\n continue;\n }\n const dir = normalizeSource(def.source);\n // A single-file source is not a collection directory — its siblings are not its assets.\n if (dir === \"\" || dir.startsWith(\"..\") || /\\.[a-z0-9]+$/i.test(dir)) {\n continue;\n }\n if (path.startsWith(`${dir}/`) && (!best || dir.length > best.dir.length)) {\n best = { dir, urlPrefix: `/${SECTION_KEY}/${name}` };\n }\n }\n return best;\n}\n\n/**\n * The mounted URL for one authored reference, or null to leave it as written. A ref is rewritten\n * only when it is relative and lands inside the collection directory — anything else (an absolute\n * URL, a project-root path, a bound template, a `../` escape out of the collection) keeps the\n * meaning it already had.\n */\nexport function mountedRefFor(value: string, entryDir: string, mount: AssetMount): string | null {\n if (isNonRelativeRef(value)) {\n return null;\n }\n const bare = value.split(\"#\")[0]!.split(\"?\")[0]!;\n let decoded: string;\n try {\n decoded = decodeURIComponent(bare);\n } catch {\n return null;\n }\n const target = resolveRelativePath(entryDir, decoded);\n if (target === null) {\n return null;\n }\n const url = assetUrlFor([mount], target);\n if (!url) {\n return null; // Outside the collection — not the mount's to publish.\n }\n return `${url}${value.slice(bare.length)}`;\n}\n\n/**\n * Rewrite one node's media refs, returning the node unchanged when nothing applies.\n *\n * PURE REBUILD: a node with a rewritten ref is replaced by a shallow copy, and so is every ancestor\n * on the path to it. Untouched subtrees keep their original references, so the render doc still\n * shares the vast majority of its nodes with the source doc.\n */\nfunction rewriteNode(node: JxMutableNode, entryDir: string, mount: AssetMount): JxMutableNode {\n const record = node as unknown as Record<string, unknown>;\n /** Accumulated changed keys; stays null (and the node is returned as-is) when nothing applies. */\n let patch: Record<string, unknown> | null = null;\n\n for (const key of ASSET_KEYS) {\n const value = record[key];\n if (typeof value === \"string\") {\n const rewritten = mountedRefFor(value, entryDir, mount);\n if (rewritten) {\n patch ??= {};\n patch[key] = rewritten;\n }\n }\n }\n\n const attributes = record.attributes as Record<string, unknown> | undefined;\n if (attributes) {\n let nextAttrs: Record<string, unknown> | null = null;\n for (const key of ASSET_KEYS) {\n const value = attributes[key];\n if (typeof value === \"string\") {\n const rewritten = mountedRefFor(value, entryDir, mount);\n if (rewritten) {\n nextAttrs ??= { ...attributes };\n nextAttrs[key] = rewritten;\n }\n }\n }\n if (nextAttrs) {\n patch ??= {};\n patch.attributes = nextAttrs;\n }\n }\n\n const children = record.children as unknown[] | undefined;\n if (Array.isArray(children)) {\n let nextChildren: unknown[] | null = null;\n for (const [i, child] of children.entries()) {\n if (!child || typeof child !== \"object\") {\n continue;\n }\n const rewrittenChild = rewriteNode(child as JxMutableNode, entryDir, mount);\n if (rewrittenChild !== child) {\n nextChildren ??= [...children];\n nextChildren[i] = rewrittenChild;\n }\n }\n if (nextChildren) {\n patch ??= {};\n patch.children = nextChildren;\n }\n }\n\n return patch ? ({ ...node, ...patch } as JxMutableNode) : node;\n}\n\n/**\n * Map a content entry's relative media refs onto its content type's asset mount, for rendering.\n *\n * Returns `doc` itself when the document is not a content entry or carries no rewritable ref, so\n * the common case costs one walk and allocates nothing.\n */\nexport function rewriteContentAssets(\n doc: JxMutableNode,\n documentPath: string | null | undefined,\n content: Record<string, ContentSectionEntry> | null | undefined,\n): JxMutableNode {\n const mount = contentMountFor(documentPath, content);\n if (!mount) {\n return doc;\n }\n return rewriteNode(doc, dirOf(documentPath!.replaceAll(\"\\\\\", \"/\").replace(/^\\.\\//, \"\")), mount);\n}\n\n/**\n * The src a PARENT-REALM preview (a media-picker thumbnail) should load for an authored value.\n *\n * The canvas gets its mapping through {@link rewriteContentAssets} on the render doc, but panel\n * chrome renders in the parent document, where a content-relative value would resolve against\n * `index.html` and 404 exactly as it did in the canvas. Same mapping, same rule — resolved against\n * the ACTIVE tab, which is the entry whose field is being edited.\n *\n * Non-content documents and already-absolute values pass through untouched.\n */\nexport function previewAssetSrc(value: string): string {\n if (!value) {\n return value;\n }\n const documentPath = activeTab.value?.documentPath;\n const mount = contentMountFor(\n documentPath,\n projectState?.projectConfig?.content as Record<string, ContentSectionEntry> | undefined,\n );\n if (!mount) {\n return value;\n }\n return mountedRefFor(value, dirOf(documentPath!), mount) ?? value;\n}\n",
|
|
12
|
-
"/// <reference lib=\"dom\" />\n/// <reference lib=\"dom.iterable\" />\n/**\n * Canvas live render — extracted from studio.js (Phase 4p). Async runtime rendering pipeline that\n * builds live canvas DOM using @jxsuite/runtime. Handles element registration, scope building, path\n * mapping ($map remapping), site-level style injection, and $head element injection.\n */\n\nimport { projectState, stripEventHandlers } from \"../store\";\nimport { activeTab } from \"../workspace/workspace\";\nimport { toRaw } from \"../reactivity\";\nimport {\n distributePageIntoLayout,\n getEffectiveElements,\n getEffectiveHead,\n getEffectiveImports,\n getEffectiveLayoutPath,\n getEffectiveMedia,\n resolveLayoutDoc,\n} from \"../site-context\";\nimport { canvasBaseOrigin } from \"./canvas-origin\";\nimport { componentRegistry, computeRelativePath } from \"../files/components\";\nimport { prepareForEditMode } from \"../utils/edit-display\";\nimport {\n paramBoundStateKeys,\n resolveParamBoundState,\n substitutePreviewParams,\n} from \"../page-params\";\nimport { isComponentDoc, substitutePreviewProps } from \"../component-props\";\nimport { rewriteContentAssets } from \"./content-assets\";\n\nimport type { JxElement, JxMutableNode } from \"@jxsuite/schema/types\";\nimport type { ComponentEntry } from \"../files/components.js\";\nimport type { ContentSectionEntry } from \"../types\";\nimport type { WireMapperCtx } from \"./iframe-protocol\";\n\nlet _ctx: { getCanvasMode: () => string } | null = null;\n\n/**\n * Walk the merged document tree to find where page children were distributed into the layout slot.\n * Returns the `prefix` path to the container whose children hold the page content (first container\n * with a non-$__layout child), plus the `offset` — the index of the first page-content child within\n * that container's children array. The offset is non-zero when the layout places sibling nodes\n * (e.g. a `<noscript>`) before the `<slot>`, which shifts every page child's render index relative\n * to its page-document index. The path mapper subtracts this offset so canvas paths line up with\n * the page document (and thus the layers panel).\n *\n * @param {JxMutableNode} node\n * @param {(string | number)[]} [path]\n * @returns {{ prefix: (string | number)[]; offset: number } | null}\n */\nfunction findPageContentPrefix(\n node: JxMutableNode,\n path: (string | number)[] = [],\n): { prefix: (string | number)[]; offset: number } | null {\n if (!node || typeof node !== \"object\") {\n return null;\n }\n if (Array.isArray(node.children)) {\n const firstPageIdx = node.children.findIndex(\n (child) => child && typeof child === \"object\" && !child.$__layout,\n );\n if (firstPageIdx !== -1) {\n return { offset: firstPageIdx, prefix: [...path, \"children\"] };\n }\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n if (child && typeof child === \"object\" && child.$__layout) {\n const found = findPageContentPrefix(child, [...path, \"children\", i]);\n if (found) {\n return found;\n }\n }\n }\n }\n return null;\n}\n\n/**\n * Recursively mark all nodes in a layout doc tree with $__layout: true so we can identify which\n * rendered DOM elements came from the layout vs page content.\n */\nfunction markLayoutNodes(node: JxMutableNode) {\n if (!node || typeof node !== \"object\") {\n return;\n }\n node.$__layout = true;\n if (Array.isArray(node.children)) {\n for (const child of node.children) {\n if (typeof child === \"string\") {\n continue;\n }\n markLayoutNodes(child);\n }\n }\n if (node.$elements) {\n for (const el of node.$elements) {\n if (typeof el !== \"string\") {\n markLayoutNodes(el as JxMutableNode);\n }\n }\n }\n}\n\n/**\n * Initialize the canvas live render module.\n *\n * @param {{\n * getCanvasMode: () => string;\n * }} ctx\n */\nexport function initCanvasLiveRender(ctx: { getCanvasMode: () => string }) {\n _ctx = ctx;\n}\n\n/**\n * Resolve a document into the form the iframe canvas renders: layout-distributed, edit-transformed,\n * with components/imports/$media/$head merged in, plus the path-mapper context and site style. This\n * is the \"parent resolves, iframe renders\" split — the realm-specific work (defineElement,\n * injecting $head/site-style into the DOM, buildScope/renderNode) happens inside the iframe from\n * this result.\n */\nexport async function resolveCanvasDocument(doc: JxMutableNode): Promise<{\n renderDoc: JxMutableNode;\n docBase: string | undefined;\n mapperCtx: WireMapperCtx;\n siteStyle: Record<string, unknown> | null;\n}> {\n const tab = activeTab.value;\n const S = { documentPath: tab?.documentPath, mode: tab?.doc.mode };\n const canvasMode = _ctx!.getCanvasMode();\n\n let renderDoc =\n canvasMode === \"preview\"\n ? structuredClone(toRaw(doc))\n : prepareForEditMode(stripEventHandlers(doc));\n\n let layoutWrapped = false;\n const isPage =\n S.documentPath &&\n projectState?.isSiteProject &&\n (S.documentPath.startsWith(\"pages/\") || S.documentPath.startsWith(\"./pages/\"));\n let pageContentPrefix: (string | number)[] | null = null;\n let pageContentOffset = 0;\n\n // Layout wrapping obeys the tab-bar's \"show layout elements\" toggle (default on); with it off,\n // The page renders alone — the unwrapped path is identical to a non-layout page.\n if (isPage && tab?.session.ui.showLayout !== false) {\n const layoutPath = getEffectiveLayoutPath(doc.$layout);\n if (layoutPath) {\n const layoutDoc = (await resolveLayoutDoc(layoutPath)) as JxMutableNode | null;\n if (layoutDoc) {\n markLayoutNodes(layoutDoc);\n const pageForSlots = canvasMode === \"preview\" ? structuredClone(toRaw(doc)) : renderDoc;\n const merged = distributePageIntoLayout(layoutDoc, pageForSlots);\n renderDoc =\n canvasMode === \"preview\" ? merged : prepareForEditMode(stripEventHandlers(merged));\n layoutWrapped = true;\n const pageContent = findPageContentPrefix(merged);\n pageContentPrefix = pageContent?.prefix ?? null;\n pageContentOffset = pageContent?.offset ?? 0;\n }\n }\n }\n\n const root = projectState?.projectRoot || \"\";\n const docPrefix = root ? `${root}/` : \"\";\n const docBase = S.documentPath\n ? `${canvasBaseOrigin()}/${docPrefix}${S.documentPath}`\n : undefined;\n\n // Substitute chosen dynamic route params ({$ref: \"#/$params/x\"} → literal), inject state.$page,\n // And bake the substituted class-prototype state entries via the backend resolver — in every\n // Mode, so ContentEntry state is real data for preview templates AND the design/edit data\n // Explorer. Pure rebuild: renderDoc shares node references with the tab's source document\n // (posted as shadowDoc), whose $refs must survive for editing/serialization.\n if (isPage && tab) {\n const { previewParams } = tab.session.ui;\n if (previewParams && Object.keys(previewParams).length > 0) {\n const boundKeys = paramBoundStateKeys(\n (doc as { state?: Record<string, unknown> }).state ?? null,\n );\n renderDoc = substitutePreviewParams(renderDoc, previewParams, S.documentPath);\n await resolveParamBoundState(renderDoc, boundKeys, docBase);\n }\n }\n\n // Component definition docs (non-page): seed chosen test-prop values into the render doc's state\n // So a non-instantiated component previews with real data — templates, dataScope snapshots, and\n // Live/snapshot expression previews all see the values (M6, the previewParams mirror). Pure\n // Rebuild for the same reason as substitutePreviewParams above.\n if (!isPage && tab && isComponentDoc(renderDoc)) {\n const { previewProps } = tab.session.ui;\n if (previewProps && Object.keys(previewProps).length > 0) {\n renderDoc = substitutePreviewProps(renderDoc, previewProps);\n }\n }\n\n // A content entry references its media relative to ITSELF; the built site serves those files from\n // The content type's asset mount. Studio opens the entry standalone, so the collection loader that\n // Normally performs that mapping never runs — do it here, on the RENDER doc only, so the canvas\n // Previews the URL production serves while the source doc keeps the authored relative ref.\n renderDoc = rewriteContentAssets(\n renderDoc,\n S.documentPath,\n projectState?.projectConfig?.content as Record<string, ContentSectionEntry> | undefined,\n );\n\n const arrayPaths = new Set<string>();\n if (canvasMode === \"design\" || canvasMode === \"edit\") {\n (function findArrayPaths(node: JxMutableNode, path: (string | number)[]) {\n if (!node || typeof node !== \"object\") {\n return;\n }\n if ((node as unknown as { $prototype?: string }).$prototype === \"Array\") {\n arrayPaths.add(path.join(\"/\"));\n const mapDef = (node as JxMutableNode).map;\n if (mapDef && typeof mapDef === \"object\") {\n findArrayPaths(mapDef, [...path, \"map\"]);\n }\n return;\n }\n if (Array.isArray(node.children)) {\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n if (typeof child === \"string\") {\n continue;\n }\n findArrayPaths(child!, [...path, \"children\", i]);\n }\n } else if (\n node.children &&\n typeof node.children === \"object\" &&\n (node.children as unknown as { $prototype?: string }).$prototype === \"Array\"\n ) {\n findArrayPaths(node.children as JxMutableNode, [...path, \"children\"]);\n }\n if (node.$switch && node.cases) {\n for (const [k, v] of Object.entries(node.cases)) {\n findArrayPaths(v, [...path, \"cases\", k]);\n }\n }\n })(doc, []);\n }\n\n // Component auto-discovery (content mode, wrapped layout, or a layout opened on its own) —\n // Mirrors the legacy render path. A directly-opened layout is neither a page (so it never\n // Sets layoutWrapped) nor content mode (a plain .json file skips the mode-setting parse),\n // So it needs its own gate; scoping to layouts/ avoids the single-component-edit path, where\n // The doc's own root tag would otherwise inject a $ref to itself.\n const isLayoutDoc =\n S.documentPath != null &&\n (S.documentPath.startsWith(\"layouts/\") || S.documentPath.startsWith(\"./layouts/\"));\n const effectiveElements = getEffectiveElements(renderDoc.$elements as (JxElement | string)[]);\n if ((S.mode === \"content\" || layoutWrapped || isLayoutDoc) && componentRegistry.length > 0) {\n const existingRefs = new Set(\n effectiveElements.map((e: JxElement | string) => (typeof e === \"string\" ? e : e?.$ref)),\n );\n const collectTags = (node: JxMutableNode): Set<string> => {\n const tags = new Set<string>();\n if (!node || typeof node !== \"object\") {\n return tags;\n }\n if (node.tagName) {\n tags.add(node.tagName);\n }\n if (Array.isArray(node.children)) {\n for (const child of node.children) {\n if (typeof child !== \"string\") {\n for (const t of collectTags(child)) {\n tags.add(t);\n }\n }\n }\n }\n return tags;\n };\n for (const tag of collectTags(renderDoc)) {\n const comp = componentRegistry.find((c: ComponentEntry) => c.tagName === tag);\n if (comp && comp.source !== \"npm\" && comp.path) {\n const relPath = computeRelativePath(S.documentPath ?? null, comp.path);\n if (!existingRefs.has(relPath)) {\n effectiveElements.push({ $ref: relPath });\n existingRefs.add(relPath);\n }\n }\n }\n }\n if (effectiveElements.length > 0) {\n renderDoc.$elements = effectiveElements as (string | JxMutableNode | { $ref: string })[];\n }\n renderDoc.imports = getEffectiveImports(renderDoc.imports);\n // The effective-media/head getters return the merged value or undefined. Optional properties\n // Cannot be assigned undefined under exactOptionalPropertyTypes, so clear them by deleting the key\n // When the getter yields nothing.\n const media = getEffectiveMedia(renderDoc.$media);\n if (media === undefined) {\n delete renderDoc.$media;\n } else {\n renderDoc.$media = media as NonNullable<JxMutableNode[\"$media\"]>;\n }\n const head = getEffectiveHead(renderDoc.$head);\n if (head === undefined) {\n delete renderDoc.$head;\n } else {\n renderDoc.$head = head as NonNullable<JxMutableNode[\"$head\"]>;\n }\n\n return {\n docBase,\n mapperCtx: {\n arrayPaths: [...arrayPaths],\n canvasMode,\n layoutWrapped,\n pageContentOffset,\n pageContentPrefix,\n },\n renderDoc,\n siteStyle: (projectState?.projectConfig?.style as Record<string, unknown>) ?? null,\n };\n}\n",
|
|
13
|
-
"/// <reference lib=\"dom\" />\n/**\n * Shared panel utilities — portable helpers extracted from studio.js. These functions depend only\n * on store.js / state.js exports (no circular deps).\n */\n\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\n\n/**\n * Convert a $media key like \"--tablet\" to a friendly display name \"Tablet\". \"--\" returns \"Base\".\n *\n * @param {string} name\n */\nexport function mediaDisplayName(name: string) {\n if (name === \"--\") {\n return \"Base\";\n }\n return (\n name\n .replace(/^--/, \"\")\n .replaceAll(\"-\", \" \")\n .replaceAll(/\\b\\w/g, (c: string) => c.toUpperCase()) || name\n );\n}\n\nexport const unsafeTags = new Set([\"script\", \"style\", \"link\", \"iframe\", \"object\", \"embed\"]);\n\n/**\n * Generate a sensible default Jx node for a given tag name.\n *\n * @param {string} tag\n */\nexport function defaultDef(tag: string): JxMutableNode {\n const def: JxMutableNode = { tagName: tag };\n if (/^h[1-6]$/.test(tag)) {\n def.textContent = \"Heading\";\n } else if (tag === \"p\") {\n def.textContent = \"Paragraph text\";\n } else if (\n tag === \"span\" ||\n tag === \"strong\" ||\n tag === \"em\" ||\n tag === \"small\" ||\n tag === \"mark\" ||\n tag === \"code\" ||\n tag === \"abbr\" ||\n tag === \"q\" ||\n tag === \"sub\" ||\n tag === \"sup\" ||\n tag === \"time\"\n ) {\n def.textContent = \"Text\";\n } else if (tag === \"a\") {\n def.textContent = \"Link\";\n def.attributes = { href: \"#\" };\n } else if (tag === \"button\") {\n def.textContent = \"Button\";\n } else if (tag === \"label\") {\n def.textContent = \"Label\";\n } else if (tag === \"legend\") {\n def.textContent = \"Legend\";\n } else if (tag === \"caption\") {\n def.textContent = \"Caption\";\n } else if (tag === \"summary\") {\n def.textContent = \"Summary\";\n } else if (\n tag === \"li\" ||\n tag === \"dt\" ||\n tag === \"dd\" ||\n tag === \"th\" ||\n tag === \"td\" ||\n tag === \"option\"\n ) {\n def.textContent = \"Item\";\n } else if (tag === \"blockquote\") {\n def.textContent = \"Quote\";\n } else if (tag === \"pre\") {\n def.textContent = \"Preformatted text\";\n } else if (tag === \"input\") {\n def.attributes = { placeholder: \"Enter text...\", type: \"text\" };\n } else if (tag === \"img\") {\n def.attributes = { alt: \"Image\" };\n } else if (tag === \"iframe\") {\n def.attributes = { src: \"\" };\n } else if (tag === \"slot\") {\n // Slot children are the fallback content shown when no slotted content is provided.\n def.children = [{ tagName: \"p\", textContent: \"Slot content\" }];\n } else if (tag === \"select\") {\n def.children = [{ tagName: \"option\", textContent: \"Option 1\" }];\n } else if (tag === \"ul\" || tag === \"ol\") {\n def.children = [{ tagName: \"li\", textContent: \"Item\" }];\n } else if (tag === \"dl\") {\n def.children = [\n { tagName: \"dt\", textContent: \"Term\" },\n { tagName: \"dd\", textContent: \"Definition\" },\n ];\n } else if (tag === \"table\") {\n def.children = [\n {\n children: [\n {\n children: [{ tagName: \"th\", textContent: \"Header\" }],\n tagName: \"tr\",\n },\n ],\n tagName: \"thead\",\n },\n {\n children: [{ children: [{ tagName: \"td\", textContent: \"Cell\" }], tagName: \"tr\" }],\n tagName: \"tbody\",\n },\n ];\n } else if (tag === \"details\") {\n def.children = [\n { tagName: \"summary\", textContent: \"Summary\" },\n { tagName: \"p\", textContent: \"Detail content\" },\n ];\n }\n return def;\n}\n",
|
|
14
|
-
"/// <reference lib=\"dom\" />\n/**\n * Inline-format.js — Inline formatting engine for contenteditable editing\n *\n * Handles toggling inline formatting (bold, italic, code, etc.) with proper wrap/unwrap logic, DOM\n * normalization, and whitespace management.\n */\n\n/** Tags considered inline formatting wrappers */\nconst FORMAT_TAGS = new Set([\n \"strong\",\n \"em\",\n \"b\",\n \"i\",\n \"u\",\n \"del\",\n \"s\",\n \"strike\",\n \"code\",\n \"sub\",\n \"sup\",\n \"span\",\n]);\n\n/**\n * Check whether `tag` is currently active on both ends of the selection. Walks from anchor and\n * focus nodes up to editableRoot looking for the tag. Returns false if selection is outside\n * editableRoot or in plaintext-only mode.\n *\n * @param {string} tag\n * @param {HTMLElement | null} editableRoot\n * @returns {boolean}\n */\nexport function isTagActiveInSelection(tag: string, editableRoot: HTMLElement | null) {\n if (!editableRoot) {\n return false;\n }\n if (editableRoot.contentEditable === \"plaintext-only\") {\n return false;\n }\n const sel = window.getSelection();\n if (!sel || !sel.rangeCount) {\n return false;\n }\n\n const anchor = sel.anchorNode;\n const focus = sel.focusNode;\n if (!anchor || !focus) {\n return false;\n }\n if (!editableRoot.contains(anchor) || !editableRoot.contains(focus)) {\n return false;\n }\n\n /**\n * @param {Node | null} node\n * @returns {boolean}\n */\n const hasTag = (node: Node | null) => {\n let current = node;\n while (current && current !== editableRoot) {\n if (\n current.nodeType === Node.ELEMENT_NODE &&\n (current as Element).tagName.toLowerCase() === tag\n ) {\n return true;\n }\n current = current.parentNode;\n }\n return false;\n };\n\n return hasTag(anchor) && hasTag(focus);\n}\n\n/**\n * Toggle an inline format tag on/off for the current selection. If the tag is active → unwrap. If\n * not → wrap.\n *\n * @param {string} tag\n * @param {HTMLElement | null} editableRoot\n */\nexport function toggleInlineFormat(tag: string, editableRoot: HTMLElement | null) {\n if (!editableRoot) {\n return;\n }\n const sel = window.getSelection();\n if (!sel || !sel.rangeCount) {\n return;\n }\n const range = sel.getRangeAt(0);\n if (range.collapsed) {\n return;\n }\n if (!editableRoot.contains(range.commonAncestorContainer)) {\n return;\n }\n\n // Expand selection to fully include any partially-selected ${...} expressions\n expandRangeToTemplateExpressions(range);\n\n // Find all elements matching `tag` that intersect the selection\n const matches = findIntersectingElements(tag, range, editableRoot);\n\n if (matches.length > 0) {\n unwrapTagInRange(tag, range, editableRoot, matches);\n } else {\n wrapRangeInTag(tag, range, editableRoot);\n }\n\n normalizeInlineContent(editableRoot);\n}\n\n/**\n * Find all elements with the given tag that intersect the selection range.\n *\n * @param {string} tag\n * @param {Range} range\n * @param {HTMLElement} root\n * @returns {Element[]}\n */\nfunction findIntersectingElements(tag: string, range: Range, root: HTMLElement) {\n const matches: Element[] = [];\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, {\n /**\n * @param {Node} node\n * @returns {number}\n */\n acceptNode(node: Node) {\n if ((node as Element).tagName.toLowerCase() === tag && range.intersectsNode(node)) {\n return NodeFilter.FILTER_ACCEPT;\n }\n return NodeFilter.FILTER_SKIP;\n },\n });\n while (walker.nextNode()) {\n matches.push(walker.currentNode as Element);\n }\n return matches;\n}\n\n/**\n * Unwrap all instances of `tag` within the range. Processes in reverse document order to preserve\n * earlier offsets.\n *\n * @param {string} tag\n * @param {Range} range\n * @param {HTMLElement} editableRoot\n * @param {Element[]} matches\n */\nfunction unwrapTagInRange(\n _tag: string,\n _range: Range,\n _editableRoot: HTMLElement,\n matches: Element[],\n) {\n // Process in reverse so DOM mutations don't shift later nodes\n for (let i = matches.length - 1; i >= 0; i--) {\n const el = matches[i]!;\n unwrapElement(el);\n }\n}\n\n/**\n * Replace an element with its children (unwrap).\n *\n * @param {Element} el\n */\nfunction unwrapElement(el: Element) {\n const parent = el.parentNode;\n if (!parent) {\n return;\n }\n const frag = document.createDocumentFragment();\n while (el.firstChild) {\n frag.append(el.firstChild);\n }\n el.replaceWith(frag);\n}\n\n/**\n * Wrap the current selection range in a new element of the given tag. Handles whitespace:\n * leading/trailing whitespace stays outside the wrapper.\n *\n * @param {string} tag\n * @param {Range} range\n * @param {HTMLElement} _editableRoot\n */\nfunction wrapRangeInTag(tag: string, range: Range, _editableRoot: HTMLElement) {\n const contents = range.extractContents();\n\n // Trim leading whitespace from the fragment\n const leadingWS = trimLeadingWhitespace(contents);\n // Trim trailing whitespace from the fragment\n const trailingWS = trimTrailingWhitespace(contents);\n\n // If nothing left after trimming, re-insert everything and bail\n if (!contents.hasChildNodes()) {\n if (leadingWS) {\n range.insertNode(document.createTextNode(leadingWS));\n }\n if (trailingWS) {\n const t = document.createTextNode(trailingWS);\n range.collapse(false);\n range.insertNode(t);\n }\n return;\n }\n\n const wrapper = document.createElement(tag);\n wrapper.append(contents);\n\n // Build the insertion fragment: [leadingWS] [wrapper] [trailingWS]\n const frag = document.createDocumentFragment();\n if (leadingWS) {\n frag.append(document.createTextNode(leadingWS));\n }\n frag.append(wrapper);\n if (trailingWS) {\n frag.append(document.createTextNode(trailingWS));\n }\n\n range.insertNode(frag);\n\n // Restore selection around the wrapper's contents\n const sel = window.getSelection();\n if (sel) {\n sel.removeAllRanges();\n const newRange = document.createRange();\n newRange.selectNodeContents(wrapper);\n sel.addRange(newRange);\n }\n}\n\n/**\n * Remove and return leading whitespace from a document fragment. Only trims if the first node is a\n * text node starting with whitespace.\n *\n * @param {DocumentFragment} frag\n * @returns {string | null}\n */\nfunction trimLeadingWhitespace(frag: DocumentFragment) {\n const first = frag.firstChild;\n if (!first || first.nodeType !== Node.TEXT_NODE) {\n return null;\n }\n const text = first.textContent ?? \"\";\n const match = text.match(/^(\\s+)/);\n if (!match) {\n return null;\n }\n const ws = match[1]!;\n if (text.length === ws.length) {\n // Entire node is whitespace — remove it\n first.remove();\n } else {\n first.textContent = text.slice(ws.length);\n }\n return ws;\n}\n\n/**\n * Remove and return trailing whitespace from a document fragment. Only trims if the last node is a\n * text node ending with whitespace.\n *\n * @param {DocumentFragment} frag\n * @returns {string | null}\n */\nfunction trimTrailingWhitespace(frag: DocumentFragment) {\n const last = frag.lastChild;\n if (!last || last.nodeType !== Node.TEXT_NODE) {\n return null;\n }\n const text = last.textContent ?? \"\";\n const match = text.match(/(\\s+)$/);\n if (!match) {\n return null;\n }\n const ws = match[1]!;\n if (text.length === ws.length) {\n last.remove();\n } else {\n last.textContent = text.slice(0, -ws.length);\n }\n return ws;\n}\n\n// ─── Normalization ─────────────────────────────────────────────────────────────\n\n/**\n * Normalize the inline content of an editable root. Merges adjacent same-tag siblings, collapses\n * redundant nesting, removes empty inline elements, and lifts edge whitespace. Runs to\n * fixed-point.\n *\n * @param {HTMLElement | null} root\n */\nexport function normalizeInlineContent(root: HTMLElement | null) {\n if (!root) {\n return;\n }\n let changed = true;\n let iterations = 0;\n while (changed && iterations < 10) {\n changed = false;\n iterations += 1;\n\n // 1. Merge adjacent text nodes\n root.normalize();\n\n // 2. Merge adjacent same-tag siblings\n if (mergeAdjacentSiblings(root)) {\n changed = true;\n }\n\n // 3. Collapse redundant nesting (strong > strong → strong)\n if (collapseRedundantNesting(root)) {\n changed = true;\n }\n\n // 4. Remove empty inline elements\n if (removeEmptyInlines(root)) {\n changed = true;\n }\n\n // 5. Lift edge whitespace out of inline wrappers\n if (liftEdgeWhitespace(root)) {\n changed = true;\n }\n\n // 6. Unwrap bare <span> elements (no class, style, or attributes)\n if (unwrapBareSpans(root)) {\n changed = true;\n }\n }\n}\n\n/**\n * Merge adjacent sibling elements with the same tag name. E.g.,\n * <strong>a</strong><strong>b</strong> → <strong>ab</strong>\n *\n * @param {HTMLElement} root\n * @returns {boolean}\n */\nfunction mergeAdjacentSiblings(root: HTMLElement) {\n let changed = false;\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n const toMerge: [Element, Element][] = [];\n\n // Collect pairs first to avoid mutation during walk\n while (walker.nextNode()) {\n const el = walker.currentNode as Element;\n const next = el.nextSibling;\n if (\n next &&\n next.nodeType === Node.ELEMENT_NODE &&\n (next as Element).tagName === el.tagName &&\n FORMAT_TAGS.has(el.tagName.toLowerCase()) &&\n attributesMatch(el, next as Element)\n ) {\n toMerge.push([el, next as Element]);\n }\n }\n\n // Process in reverse to preserve earlier offsets\n for (let i = toMerge.length - 1; i >= 0; i--) {\n const [el, next] = toMerge[i]!;\n // Move all children from next into el\n while (next.firstChild) {\n el.append(next.firstChild);\n }\n next.remove();\n changed = true;\n }\n return changed;\n}\n\n/**\n * Collapse redundant nesting where a parent and its only child share the same tag. E.g.,\n * <strong><strong>x</strong></strong> → <strong>x</strong>\n *\n * @param {HTMLElement} root\n * @returns {boolean}\n */\nfunction collapseRedundantNesting(root: HTMLElement) {\n let changed = false;\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n const toCollapse: Element[] = [];\n\n while (walker.nextNode()) {\n const el = walker.currentNode as Element;\n if (!FORMAT_TAGS.has(el.tagName.toLowerCase())) {\n continue;\n }\n // Check if only child is an element with the same tag\n if (\n el.childNodes.length === 1 &&\n el.firstChild !== null &&\n el.firstChild.nodeType === Node.ELEMENT_NODE &&\n (el.firstChild as Element).tagName === el.tagName\n ) {\n toCollapse.push(el);\n }\n }\n\n for (const el of toCollapse) {\n const inner = el.firstChild as Element;\n // Replace outer with inner's children\n while (inner.firstChild) {\n inner.before(inner.firstChild);\n }\n inner.remove();\n changed = true;\n }\n return changed;\n}\n\n/**\n * Remove empty inline elements.\n *\n * @param {HTMLElement} root\n * @returns {boolean}\n */\nfunction removeEmptyInlines(root: HTMLElement) {\n let changed = false;\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n const toRemove: Element[] = [];\n\n while (walker.nextNode()) {\n const el = walker.currentNode as Element;\n if (!FORMAT_TAGS.has(el.tagName.toLowerCase())) {\n continue;\n }\n if (el.childNodes.length === 0 && !el.textContent) {\n toRemove.push(el);\n }\n }\n\n for (const el of toRemove) {\n el.remove();\n changed = true;\n }\n return changed;\n}\n\n/**\n * Lift leading/trailing whitespace out of inline wrapper elements. E.g., <strong> text </strong> →\n * \" \"<strong>text</strong>\" \"\n *\n * @param {HTMLElement} root\n * @returns {boolean}\n */\nfunction liftEdgeWhitespace(root: HTMLElement) {\n let changed = false;\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n /** @type {{ type: string; el: Element; ws: string }[]} */\n const ops = [];\n\n while (walker.nextNode()) {\n const el = walker.currentNode as Element;\n if (!FORMAT_TAGS.has(el.tagName.toLowerCase())) {\n continue;\n }\n if (el === root) {\n continue;\n }\n\n const first = el.firstChild;\n if (first && first.nodeType === Node.TEXT_NODE) {\n const text = first.textContent ?? \"\";\n const m = text.match(/^(\\s+)/);\n if (m && text.length > m[1]!.length) {\n ops.push({ el, type: \"lift-leading\", ws: m[1]! });\n }\n }\n\n const last = el.lastChild;\n if (last && last.nodeType === Node.TEXT_NODE && last !== first) {\n const text = last.textContent ?? \"\";\n const m = text.match(/(\\s+)$/);\n if (m && text.length > m[1]!.length) {\n ops.push({ el, type: \"lift-trailing\", ws: m[1]! });\n }\n }\n }\n\n for (const op of ops) {\n if (op.type === \"lift-leading\") {\n const firstChild = op.el.firstChild as Text;\n firstChild.textContent = (firstChild.textContent ?? \"\").slice(op.ws.length);\n op.el.parentNode?.insertBefore(document.createTextNode(op.ws), op.el);\n changed = true;\n } else if (op.type === \"lift-trailing\") {\n const lastChild = op.el.lastChild as Text;\n lastChild.textContent = (lastChild.textContent ?? \"\").slice(0, -op.ws.length);\n op.el.parentNode?.insertBefore(document.createTextNode(op.ws), op.el.nextSibling);\n changed = true;\n }\n }\n return changed;\n}\n\n/**\n * Unwrap bare <span> elements that have no class, style, or meaningful attributes. These are\n * semantically empty wrappers left over from formatting operations.\n *\n * @param {HTMLElement} root\n * @returns {boolean}\n */\nfunction unwrapBareSpans(root: HTMLElement) {\n let changed = false;\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n const toUnwrap: Element[] = [];\n\n while (walker.nextNode()) {\n const el = walker.currentNode as Element;\n if (el.tagName.toLowerCase() !== \"span\") {\n continue;\n }\n if (el === root) {\n continue;\n }\n // Keep spans with class, style, or any attributes\n if (el.attributes.length > 0) {\n continue;\n }\n toUnwrap.push(el);\n }\n\n for (const el of toUnwrap) {\n unwrapElement(el);\n changed = true;\n }\n return changed;\n}\n\n/**\n * Check if two elements have matching attributes (for merge eligibility). For simple formatting\n * tags, attributes don't matter. For <a>, href must match.\n *\n * @param {Element} a\n * @param {Element} b\n * @returns {boolean}\n */\nfunction attributesMatch(a: Element, b: Element) {\n const tag = a.tagName.toLowerCase();\n if (tag === \"a\") {\n return a.getAttribute(\"href\") === b.getAttribute(\"href\");\n }\n // For simple format tags, always match\n return true;\n}\n\n// ─── Template expression preservation ─────────────────────────────────────────\n\n/**\n * Expand a Range so that it fully includes any `${...}` template expressions that are partially\n * selected. Template expressions are atomic in Jx — if split across inline elements, the template\n * string breaks.\n *\n * Scans the text content of the start and end containers for `${...}` patterns and adjusts the\n * range boundaries outward to include the complete expression.\n *\n * @param {Range} range\n */\nexport function expandRangeToTemplateExpressions(range: Range) {\n expandBoundary(range, true); // Start\n expandBoundary(range, false); // End\n}\n\n/**\n * Expand one boundary (start or end) of a range to avoid splitting a ${...}. `isStart` = true\n * adjusts startContainer/startOffset, `isStart` = false adjusts endContainer/endOffset.\n *\n * @param {Range} range\n * @param {boolean} isStart\n */\nfunction expandBoundary(range: Range, isStart: boolean) {\n const node = isStart ? range.startContainer : range.endContainer;\n const offset = isStart ? range.startOffset : range.endOffset;\n if (node.nodeType !== Node.TEXT_NODE) {\n return;\n }\n\n const text = node.textContent ?? \"\";\n\n // Find all ${...} expression spans in this text node (supporting nested braces)\n const exprs = findTemplateExpressions(text);\n for (const expr of exprs) {\n // Expr = { start, end } — character indices of \"$\" and the closing \"}\" + 1\n if (isStart) {\n // If the range starts inside this expression, move it to include the whole expr\n if (offset > expr.start && offset < expr.end) {\n range.setStart(node, expr.start);\n }\n } else if (offset > expr.start && offset < expr.end) {\n // If the range ends inside this expression, expand to include the whole expr\n range.setEnd(node, expr.end);\n }\n }\n}\n\n/**\n * Find all `${...}` expression spans in a string, handling nested braces. Returns array of { start,\n * end } where start is the index of '$' and end is one past the closing '}'.\n *\n * @param {string} text\n * @returns {{ start: number; end: number }[]}\n */\nexport function findTemplateExpressions(text: string) {\n /** @type {{ start: number; end: number }[]} */\n const results = [];\n let i = 0;\n while (i < text.length - 1) {\n if (text[i] === \"$\" && text[i + 1] === \"{\") {\n const start = i;\n let depth = 1;\n let j = i + 2;\n while (j < text.length && depth > 0) {\n if (text[j] === \"{\") {\n depth += 1;\n } else if (text[j] === \"}\") {\n depth -= 1;\n }\n j += 1;\n }\n if (depth === 0) {\n results.push({ end: j, start });\n i = j;\n continue;\n }\n }\n i += 1;\n }\n return results;\n}\n",
|
|
15
|
-
"/**\n * Which tags can hold a text caret.\n *\n * The canvas carries a document-wide caret, so this set decides where a click lands — a tag missing\n * from it reads to the author as \"this text is not editable\", because clicking simply does nothing.\n * It used to be a hand-maintained list of thirteen tag names, which meant every new text-bearing\n * element had to be remembered here, and the list could disagree with what the document's own\n * vocabulary said.\n *\n * It is now DERIVED, from two sources resolved per tag:\n *\n * 1. **The format class**, when the document has one (`$studio.elements`, via\n * {@link file://../format/constraints.ts}'s `formatEditableVerdicts`). Authoritative for the\n * tags it declares — and able to say NO, which is why this is a per-tag lookup and not a union.\n * 2. **The studio's own element metadata** (`elements-meta.json`) for everything else: HTML that\n * reaches the canvas through a directive, and native `.json` documents, which have no format\n * class at all.\n *\n * The metadata rule is the same in both: a tag holds a caret when it accepts inline children.\n * Containers declare `\"$inlineChildren\": []` and are excluded by it without needing to be named.\n */\n\nimport elementsMeta from \"../../data/elements-meta.json\";\n\ninterface ElementDef {\n $inlineChildren?: string[];\n}\n\n/**\n * Tags the studio's own metadata says accept inline children.\n *\n * `pre` is excluded despite qualifying: its content is preformatted code, where whitespace is\n * significant and the inline-markup path does not apply. Markdown's format class independently\n * agrees (`\"pre\": { \"only\": [\"code\"] }`).\n */\nconst EXCLUDED = new Set([\"pre\"]);\n\nexport const BUILTIN_EDITABLE_TAGS: ReadonlySet<string> = new Set(\n Object.entries(elementsMeta.$defs as Record<string, ElementDef>)\n .filter(([tag, def]) => !EXCLUDED.has(tag) && (def.$inlineChildren?.length ?? 0) > 0)\n .map(([tag]) => tag),\n);\n\n/**\n * The format's per-tag overrides, or null when the document has no format class (a native `.json`\n * document) — in which case the built-in metadata answers on its own.\n */\nexport type EditableVerdicts = Readonly<Record<string, boolean>> | null;\n\n/** Whether `tag` can hold a caret, given the live document's format overrides. */\nexport function isEditableTag(tag: string, verdicts: EditableVerdicts): boolean {\n const declared = verdicts?.[tag.toLowerCase()];\n return declared ?? BUILTIN_EDITABLE_TAGS.has(tag.toLowerCase());\n}\n",
|
|
16
|
-
"/// <reference lib=\"dom\" />\n/// <reference lib=\"dom.iterable\" />\n/**\n * Inline-edit.js — Contenteditable inline editing for content mode\n *\n * Manages the lifecycle of editing text-bearing block elements directly on the canvas. Handles rich\n * text formatting, Enter for new paragraphs, and slash commands for inserting elements.\n */\n\nimport elementsMeta from \"../../data/elements-meta.json\";\nimport { normalizeInlineContent, toggleInlineFormat } from \"./inline-format\";\nimport { isEditableTag } from \"./editable-tags\";\nimport type { EditableVerdicts } from \"./editable-tags\";\nimport type { JxPath } from \"../state\";\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\n\n/**\n * The slash-menu surface inline editing drives. Injected (rather than imported) so this module\n * stays free of the menu's heavy `lit-html` / `ui/layers` dependencies — the editor realm wires the\n * real menu, the canvas iframe supplies its own (or a no-op) without bloating the slim iframe\n * bundle.\n */\nexport interface SlashController {\n show: (\n anchorEl: HTMLElement,\n filter: string,\n cbs: { onSelect: (cmd: SlashCommand) => void; showFilter?: boolean; commands?: SlashCommand[] },\n ) => void;\n dismiss: () => void;\n isOpen: () => boolean;\n}\n\nconst noopSlash: SlashController = {\n dismiss: () => {\n // No slash controller wired in this realm.\n },\n isOpen: () => false,\n show: () => {\n // No slash controller wired in this realm.\n },\n};\nlet slash: SlashController = noopSlash;\n\n/** Inject the slash-menu controller inline editing should drive (call once at realm init). */\nexport function setSlashController(controller: SlashController): void {\n slash = controller;\n}\n\nexport interface InlineAction {\n tag: string;\n label: string;\n icon?: string;\n command?: string;\n shortcut?: string;\n}\n\ninterface ElementDef {\n $inlineChildren?: string[];\n $inlineActions?: InlineAction[] | string;\n}\n\nexport interface SlashCommand {\n label: string;\n tag: string;\n description: string;\n}\n\nexport interface JxContentResult {\n textContent?: string | null;\n children?: (JxMutableNode | string)[];\n}\n\n// ─── Inline tag set (tags that represent rich text formatting) ─────────────\n\n/** Fallback set — used when parent context is unknown */\nconst INLINE_TAGS = new Set([\n \"em\",\n \"strong\",\n \"del\",\n \"code\",\n \"a\",\n \"span\",\n \"br\",\n \"img\",\n \"b\",\n \"i\",\n \"u\",\n \"sub\",\n \"sup\",\n \"s\",\n]);\n\n// ─── Context-aware inline scoping ─────────────────────────────────────────\n\n/**\n * Check if a child tag is inline within the context of a given parent tag. Uses $inlineChildren\n * from elements-meta.json.\n *\n * @param {string} childTag\n * @param {string} parentTag\n * @returns {boolean}\n */\nexport function isInlineInContext(childTag: string, parentTag: string) {\n if (!parentTag) {\n return INLINE_TAGS.has(childTag);\n }\n const parentDef = (elementsMeta.$defs as Record<string, ElementDef>)[parentTag];\n if (!parentDef || !parentDef.$inlineChildren) {\n return false;\n }\n return parentDef.$inlineChildren.includes(childTag);\n}\n\n/**\n * Get the resolved $inlineActions for a given element tag. Follows string references (e.g., \"h1\" →\n * look up h1's actions).\n *\n * @param {string} tag\n * @returns {InlineAction[] | null}\n */\nexport function getInlineActions(tag: string) {\n const def = (elementsMeta.$defs as Record<string, ElementDef>)[tag];\n if (!def) {\n return null;\n }\n let actions = def.$inlineActions;\n if (typeof actions === \"string\") {\n const refDef = (elementsMeta.$defs as Record<string, ElementDef>)[actions];\n actions = refDef?.$inlineActions ?? undefined;\n }\n if (!Array.isArray(actions)) {\n return null;\n }\n return actions;\n}\n\n// ─── Editing state ─────────────────────────────────────────────────────────\n\nlet activeEl: HTMLElement | null = null; // Currently contenteditable element\nlet activePath: JxPath | null = null; // JSON path to the active element\n/**\n * @type {((\n * path: JxPath,\n * children: (JxMutableNode | string)[] | null,\n * textContent: string | null,\n * ) => void)\n * | null}\n */\nlet commitFn:\n | ((\n path: JxPath,\n children: (JxMutableNode | string)[] | null,\n textContent: string | null,\n inPlace: boolean,\n ) => void)\n | null = null; // Function(path, newChildren, newTextContent, inPlace) to commit changes\n/**\n * @type {((path: JxPath, beforeChildren: JxContentResult, afterChildren: JxContentResult) => void)\n * | null}\n */\nlet splitFn:\n | ((path: JxPath, beforeChildren: JxContentResult, afterChildren: JxContentResult) => void)\n | null = null; // Function(path, beforeChildren, afterChildren) to split paragraph\n/**\n * @type {((path: JxPath, elementDef: SlashCommand, commitData?: JxContentResult) => void)\n * | null}\n */\nlet insertFn:\n | ((path: JxPath, elementDef: SlashCommand, commitData?: JxContentResult) => void)\n | null = null; // Function(path, elementDef, commitData?) to insert after current block\nlet endFn: (() => void) | null = null; // Function() called when editing stops\n\n/**\n * Plain (plaintext-only) session state — used for prop-bound text, where the committed value is a\n * plain string (a directive attribute), so rich formatting, Enter-split, and the slash menu are all\n * disabled: Enter commits, Escape restores `_plainOriginal` and commits unchanged (the host no-ops\n * an unchanged prop value).\n */\nlet _plainMode = false;\nlet _plainOriginal = \"\";\n\n/**\n * The live document's format overrides for which tags hold a caret. Injected per render (the same\n * shape as `setSlashController`), because the answer depends on the document's format class — a\n * `.md` page and a native `.json` component have different vocabularies.\n */\nlet editableVerdicts: EditableVerdicts = null;\n\n/** Adopt the format's per-tag caret verdicts for the live render (null = built-in metadata only). */\nexport function setEditableVerdicts(verdicts: EditableVerdicts): void {\n editableVerdicts = verdicts;\n}\n\n/**\n * Whether an element can hold a text caret.\n *\n * Derived from the document's element vocabulary rather than a hand-maintained list — see\n * {@link file://./editable-tags.ts}.\n */\nexport function isEditableBlock(el: HTMLElement) {\n return isEditableTag(el.tagName, editableVerdicts);\n}\n\n/**\n * Check if a node is an inline child. When parentNode is provided, uses context-aware scoping from\n * metadata. Without parent, uses the fallback INLINE_TAGS set.\n *\n * @param {JxMutableNode} node\n * @param {JxMutableNode} [parentNode]\n * @returns {boolean}\n */\nexport function isInlineElement(node: JxMutableNode, parentNode?: JxMutableNode) {\n if (!node || typeof node !== \"object\") {\n return false;\n }\n const childTag = (node.tagName ?? \"div\").toLowerCase();\n if (parentNode) {\n const parentTag = (parentNode.tagName ?? \"div\").toLowerCase();\n return isInlineInContext(childTag, parentTag);\n }\n return INLINE_TAGS.has(childTag);\n}\n\n/**\n * Start inline editing on a canvas element.\n *\n * @param {HTMLElement} el - The canvas DOM element to edit\n * @param {JxPath} path - JSON path to the element\n * @param {{\n * onCommit: (\n * path: JxPath,\n * children: (JxMutableNode | string)[] | null,\n * textContent: string | null,\n * ) => void;\n * onSplit: (\n * path: JxPath,\n * beforeChildren: JxContentResult,\n * afterChildren: JxContentResult,\n * ) => void;\n * onInsert: (path: JxPath, elementDef: SlashCommand, commitData?: JxContentResult) => void;\n * onEnd: () => void;\n * }} callbacks\n * @param {{ plainText?: boolean }} [opts] - `plainText` runs a plaintext-only session (prop-bound\n * text: no rich formatting/split/slash; Enter commits, Escape cancels)\n */\nexport function startEditing(\n el: HTMLElement,\n path: JxPath,\n callbacks: {\n onCommit: (\n path: JxPath,\n children: (JxMutableNode | string)[] | null,\n textContent: string | null,\n inPlace: boolean,\n ) => void;\n onSplit: (\n path: JxPath,\n beforeChildren: JxContentResult,\n afterChildren: JxContentResult,\n ) => void;\n onInsert: (path: JxPath, elementDef: SlashCommand, commitData?: JxContentResult) => void;\n onEnd: () => void;\n },\n opts?: { plainText?: boolean },\n) {\n if (activeEl) {\n // Re-enter (e.g. after a split/insert re-render): tear the old session down WITHOUT firing the\n // User-visible `onEnd` — a re-enter must not reset the parent toolbar via a stray `editEnd`.\n stopEditing(true);\n }\n\n activeEl = el;\n activePath = path;\n commitFn = callbacks.onCommit;\n splitFn = callbacks.onSplit;\n insertFn = callbacks.onInsert;\n endFn = callbacks.onEnd;\n _plainMode = opts?.plainText === true;\n _plainOriginal = _plainMode ? (el.textContent ?? \"\") : \"\";\n\n // Mark the caret's block so the empty-block slash hint can target it. The editing host itself is\n // The canvas container (see syncEditableRoot) — activating a block does NOT make it a separate\n // Contenteditable, which is exactly what lets the caret cross block boundaries natively.\n //\n // A prop-bound block is the one exception: it lives inside a `contenteditable=\"false\"` component\n // Island, so it needs its own nested editing host to be reachable at all.\n el.dataset.jxActiveBlock = \"\";\n if (_plainMode) {\n try {\n el.contentEditable = \"plaintext-only\";\n } catch {\n // Engines without plaintext-only support throw on assignment; paste is already plain via\n // HandlePaste, and the keydown plain branch inertifies the format shortcuts.\n el.contentEditable = \"true\";\n }\n el.focus();\n }\n\n // The caret is NOT moved here. It is already wherever the user clicked or arrowed to — moving it\n // To the end of the block (as this used to) is precisely what made editing feel modal.\n\n el.addEventListener(\"keydown\", handleKeydown);\n el.addEventListener(\"input\", handleInput);\n el.addEventListener(\"paste\", handlePaste);\n}\n\n/**\n * Stop editing and commit changes. Pass `silent` to skip the `onEnd` callback (used by the re-enter\n * path so a stop→start sequence doesn't post a user-visible `editEnd`).\n *\n * @param {boolean} [silent]\n */\nexport function stopEditing(silent = false) {\n if (!activeEl) {\n return;\n }\n\n commitChanges(false);\n slash.dismiss();\n\n delete activeEl.dataset.jxActiveBlock;\n // Only a prop-bound block ever claimed its own editing host; page blocks are edited through the\n // Container's, which must stay editable after the caret leaves this block.\n if (_plainMode) {\n activeEl.contentEditable = \"false\";\n }\n\n activeEl.removeEventListener(\"keydown\", handleKeydown);\n activeEl.removeEventListener(\"input\", handleInput);\n activeEl.removeEventListener(\"paste\", handlePaste);\n\n activeEl = null;\n activePath = null;\n commitFn = null;\n splitFn = null;\n insertFn = null;\n _plainMode = false;\n _plainOriginal = \"\";\n\n if (silent) {\n endFn = null;\n } else if (endFn) {\n const fn = endFn;\n endFn = null;\n fn();\n }\n}\n\n/**\n * Commit the active block's content to the document WITHOUT releasing it.\n *\n * The idle-tick counterpart to {@link stopEditing}: the caret stays exactly where it is and the\n * block stays active, so typing continues uninterrupted while the document keeps up. Callers are\n * responsible for preserving the caret across the DOM normalization this performs — the editing\n * host does that in model coordinates (see `commitTick`).\n *\n * A no-op when nothing is active, and the apply side no-ops an unchanged value, so calling this on\n * every pause is cheap.\n */\nexport function commitActiveBlock(): void {\n commitChanges(true);\n}\n\n/**\n * Whether inline editing is currently active.\n *\n * @returns {boolean}\n */\nexport function isEditing() {\n return activeEl !== null;\n}\n\n/**\n * Get the currently editing element.\n *\n * @returns {HTMLElement | null}\n */\nexport function getActiveElement() {\n return activeEl;\n}\n\n/**\n * Get the document path of the currently editing element (null when no session is live).\n *\n * @returns {JxPath | null}\n */\nexport function getActivePath() {\n return activePath;\n}\n\n/**\n * Whether the DI'd slash menu reports itself open — session-lifecycle guards must not commit-and-\n * end on a pointerdown that is really a slash-menu interaction.\n *\n * @returns {boolean}\n */\nexport function isSlashActive() {\n return slash.isOpen();\n}\n\n// ─── Event handlers ────────────────────────────────────────────────────────\n\n/** @param {KeyboardEvent} e */\nfunction handleKeydown(e: KeyboardEvent) {\n if (_plainMode) {\n if (e.key === \"Escape\") {\n e.preventDefault();\n e.stopPropagation();\n if (activeEl) {\n // Cancel: restore the original text; the commit posts the unchanged value (host no-ops).\n activeEl.textContent = _plainOriginal;\n }\n stopEditing();\n return;\n }\n if (e.key === \"Enter\") {\n e.preventDefault();\n e.stopPropagation();\n stopEditing();\n return;\n }\n // Inertify the browser's native rich shortcuts for the contentEditable=\"true\" fallback.\n if ((e.ctrlKey || e.metaKey) && [\"b\", \"i\", \"u\", \"`\"].includes(e.key)) {\n e.preventDefault();\n }\n return;\n }\n\n // Escape and Enter are NOT handled here. Enter arrives as a `beforeinput` (`insertParagraph`),\n // Which is the one place structural intent is classified; Escape belongs to the editing host,\n // Which owns dismissing the caret. See {@link file://../canvas/iframe-editable-root.ts}.\n\n // Slash command trigger\n if (e.key === \"/\" && !e.ctrlKey && !e.metaKey) {\n // Check if at start of empty block or after a space/newline\n const sel = window.getSelection();\n if (sel && sel.rangeCount > 0) {\n const range = sel.getRangeAt(0);\n const textBefore = getTextBeforeCursor(range);\n if (textBefore === \"\" || textBefore.endsWith(\" \") || textBefore.endsWith(\"\\n\")) {\n // Let the / character be typed, then show menu on next input\n requestAnimationFrame(() => openSlashMenu());\n return;\n }\n }\n }\n\n // Rich text shortcuts\n if (e.ctrlKey || e.metaKey) {\n switch (e.key) {\n case \"b\": {\n e.preventDefault();\n toggleInlineFormat(\"strong\", activeEl);\n break;\n }\n case \"i\": {\n e.preventDefault();\n toggleInlineFormat(\"em\", activeEl);\n break;\n }\n case \"`\": {\n e.preventDefault();\n toggleInlineFormat(\"code\", activeEl);\n break;\n }\n default: {\n break;\n }\n }\n }\n}\n\nfunction handleInput() {\n // Check if slash menu should update or dismiss\n if (slash.isOpen()) {\n updateSlashMenu();\n }\n}\n\n/** @param {ClipboardEvent} e */\nfunction handlePaste(e: ClipboardEvent) {\n e.preventDefault();\n // Paste as plain text to avoid foreign HTML\n const text = e.clipboardData?.getData(\"text/plain\") ?? \"\";\n document.execCommand(\"insertText\", false, text);\n}\n\n// ─── Enter: split the active block ─────────────────────────────────────────\n\n/**\n * Split the active block at the caret, reporting the two halves through `onSplit`.\n *\n * Called from the editing host's `beforeinput` chokepoint (`insertParagraph`), never from a keydown\n * — Enter is a structural intent, and `beforeinput` is the one place those are recognised.\n *\n * A non-collapsed selection INSIDE the block is dropped by construction: the \"before\" half ends at\n * the selection's start and the \"after\" half begins at its end. A selection spanning two blocks is\n * the caller's to reject (the `after` range could not be built against this block).\n *\n * The active block is released WITHOUT committing — the split writes both halves itself, and a\n * commit racing it would re-apply the pre-split text over the first one. Returns false when there\n * is nothing to split.\n */\nexport function splitActiveBlock(): boolean {\n if (!splitFn || !activeEl || !activePath) {\n return false;\n }\n\n const sel = window.getSelection();\n if (!sel || !sel.rangeCount) {\n return false;\n }\n\n const range = sel.getRangeAt(0);\n\n const beforeRange = document.createRange();\n beforeRange.setStart(activeEl, 0);\n beforeRange.setEnd(range.startContainer, range.startOffset);\n\n const afterRange = document.createRange();\n afterRange.setStart(range.endContainer, range.endOffset);\n afterRange.setEnd(activeEl, activeEl.childNodes.length);\n\n const beforeChildren = fragmentToJx(beforeRange.cloneContents());\n const afterChildren = fragmentToJx(afterRange.cloneContents());\n\n const path = [...activePath];\n const split = splitFn;\n\n releaseWithoutCommit();\n split(path, beforeChildren, afterChildren);\n return true;\n}\n\n/**\n * Drop the active block's bookkeeping without committing it, firing `onEnd`. Used by the paths that\n * write the block's content themselves (split, slash-insert) — a commit afterwards would clobber\n * what they just wrote.\n */\nfunction releaseWithoutCommit(): void {\n if (!activeEl) {\n return;\n }\n delete activeEl.dataset.jxActiveBlock;\n if (_plainMode) {\n activeEl.contentEditable = \"false\";\n }\n activeEl.removeEventListener(\"keydown\", handleKeydown);\n activeEl.removeEventListener(\"input\", handleInput);\n activeEl.removeEventListener(\"paste\", handlePaste);\n activeEl = null;\n activePath = null;\n commitFn = null;\n splitFn = null;\n insertFn = null;\n _plainMode = false;\n _plainOriginal = \"\";\n\n if (endFn) {\n const fn = endFn;\n endFn = null;\n fn();\n }\n}\n\n// ─── Content sync: DOM → Jx ────────────────────────────────────────────\n\n/**\n * Serialize the active block and hand it to `onCommit`.\n *\n * `inPlace` distinguishes the idle tick (the caret is still in this block) from a release. The\n * parent uses it to suppress the DOM half of the echoed patch, so a commit mid-typing cannot\n * re-render the subtree the caret lives in.\n */\nfunction commitChanges(inPlace: boolean) {\n if (!commitFn || !activeEl || !activePath) {\n return;\n }\n\n if (_plainMode) {\n // A prop value is a plain single-line string (a directive attribute) — flatten any newline\n // That survived plaintext editing and skip the rich DOM→Jx serialization entirely.\n commitFn(activePath, null, (activeEl.textContent ?? \"\").replaceAll(\"\\n\", \" \"), inPlace);\n return;\n }\n\n normalizeInlineContent(activeEl);\n const result = elementToJx(activeEl);\n commitFn(activePath, result.children ?? null, result.textContent ?? null, inPlace);\n}\n\n/**\n * Normalize a node's children array: merge adjacent text nodes and fold all-text children into\n * textContent. Returns `{ textContent }` or `{ children }`.\n *\n * @param {{ children?: (JxMutableNode | string)[] }} node\n * @returns {JxContentResult}\n */\nexport function normalizeChildren(node: { children?: (JxMutableNode | string)[] }) {\n if (!Array.isArray(node.children) || node.children.length === 0) {\n return { textContent: \"\" };\n }\n\n // Step 1: Merge adjacent text nodes\n const merged = [];\n for (const child of node.children) {\n if (typeof child === \"string\" && merged.length > 0 && typeof merged.at(-1) === \"string\") {\n merged[merged.length - 1] += child;\n } else {\n merged.push(child);\n }\n }\n\n // Step 2: If all children are text, fold into textContent\n if (merged.every((c: JxMutableNode | string) => typeof c === \"string\")) {\n return { textContent: merged.join(\"\") };\n }\n\n return { children: merged };\n}\n\n/**\n * Convert a contenteditable element's content to Jx children/textContent. Returns { textContent }\n * for plain text or { children } for rich content.\n *\n * @param {HTMLElement} el\n * @returns {JxContentResult}\n */\nfunction elementToJx(el: HTMLElement): JxContentResult {\n const nodes = el.childNodes;\n\n // If just a single text node, use textContent\n if (nodes.length === 0) {\n return { textContent: \"\" };\n }\n if (nodes.length === 1 && nodes[0]!.nodeType === Node.TEXT_NODE) {\n return { textContent: nodes[0]!.textContent };\n }\n\n // Mixed content → children array\n const children: (JxMutableNode | string)[] = [];\n for (const child of nodes) {\n const jsx = domNodeToJx(child);\n if (jsx !== null && jsx !== undefined) {\n children.push(jsx);\n }\n }\n\n // Normalize: merge adjacent text nodes + fold all-text to textContent\n return normalizeChildren({ children });\n}\n\n/**\n * Convert a DOM node to a Jx element definition.\n *\n * @param {Node} node\n * @returns {JxMutableNode | string | null}\n */\nfunction domNodeToJx(node: Node) {\n if (node.nodeType === Node.TEXT_NODE) {\n const text = node.textContent;\n if (!text) {\n return null;\n }\n return text; // Bare string — text node child\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return null;\n }\n\n const el = node as HTMLElement;\n const tag = el.tagName.toLowerCase();\n const result: JxMutableNode = { tagName: tag };\n\n // Map browser execCommand output to our tag conventions\n const tagMap: Record<string, string> = {\n b: \"strong\",\n i: \"em\",\n s: \"del\",\n strike: \"del\",\n };\n if (tagMap[tag]) {\n result.tagName = tagMap[tag];\n }\n\n // Attributes\n // A canvas anchor is DE-LINKED in design/edit: the runtime stamps its URL as `data-jx-href` so a\n // Click selects the anchor instead of navigating the iframe (see setCanvasDelinkAnchors). Reading\n // Only `href` here would serialize every edited link as `[text]()` — silently destroying the URL\n // Of any paragraph that happens to contain one.\n const href = el.dataset.jxHref ?? el.getAttribute(\"href\");\n if (tag === \"a\" && href != null) {\n result.attributes = { href };\n if ((el as HTMLAnchorElement).title) {\n result.attributes.title = (el as HTMLAnchorElement).title;\n }\n }\n if (tag === \"code\") {\n result.textContent = el.textContent;\n return result;\n }\n\n // Recurse children\n const { childNodes } = el;\n if (childNodes.length === 0) {\n result.textContent = \"\";\n } else if (childNodes.length === 1 && childNodes[0]!.nodeType === Node.TEXT_NODE) {\n result.textContent = childNodes[0]!.textContent;\n } else {\n result.children = [];\n for (const child of childNodes) {\n const jsx = domNodeToJx(child);\n if (jsx) {\n result.children.push(/** @type {JxMutableNode} */ jsx);\n }\n }\n }\n\n return result;\n}\n\n/**\n * Convert a DocumentFragment to a Jx-compatible structure. Returns { textContent } or { children }.\n *\n * @param {DocumentFragment} frag\n * @returns {JxContentResult}\n */\nfunction fragmentToJx(frag: DocumentFragment) {\n const nodes = frag.childNodes;\n if (nodes.length === 0) {\n return { textContent: \"\" };\n }\n if (nodes.length === 1 && nodes[0]!.nodeType === Node.TEXT_NODE) {\n return { textContent: nodes[0]!.textContent };\n }\n\n const children: (JxMutableNode | string)[] = [];\n for (const child of nodes) {\n const jsx = domNodeToJx(child);\n if (jsx) {\n children.push(jsx);\n }\n }\n\n if (\n children.length === 1 &&\n typeof children[0] !== \"string\" &&\n children[0]!.tagName === \"span\" &&\n typeof children[0]!.textContent === \"string\"\n ) {\n return { textContent: children[0]!.textContent };\n }\n\n return children.length > 0 ? { children } : { textContent: \"\" };\n}\n\n// ─── Rich text helpers ─────────────────────────────────────────────────────\n\n/**\n * @param {Range} range\n * @returns {string}\n */\nfunction getTextBeforeCursor(range: Range) {\n const preRange = document.createRange();\n preRange.setStart(activeEl!, 0);\n preRange.setEnd(range.startContainer, range.startOffset);\n return preRange.toString();\n}\n\n// ─── Slash command menu (delegates to shared slash-menu.js) ──────────────\n\n/** Track the character offset where \"/\" was typed so we can detect backspace-past-slash */\nlet _slashFilterStart = 0;\n\nfunction openSlashMenu() {\n if (!activeEl || !insertFn || !activePath) {\n return;\n }\n\n const sel = window.getSelection();\n if (!sel || !sel.rangeCount) {\n return;\n }\n const range = sel.getRangeAt(0);\n _slashFilterStart = getTextBeforeCursor(range).length;\n\n slash.show(activeEl, \"\", { onSelect: handleSlashSelect });\n}\n\nfunction updateSlashMenu() {\n if (!activeEl) {\n return;\n }\n\n const sel = window.getSelection();\n if (!sel || !sel.rangeCount) {\n slash.dismiss();\n return;\n }\n\n const range = sel.getRangeAt(0);\n const fullText = getTextBeforeCursor(range);\n const slashIdx = fullText.lastIndexOf(\"/\");\n\n if (slashIdx === -1 || fullText.length < _slashFilterStart - 1) {\n slash.dismiss();\n return;\n }\n\n const filter = fullText.slice(slashIdx + 1).toLowerCase();\n slash.show(activeEl, filter, { onSelect: handleSlashSelect });\n}\n\n/** @param {SlashCommand} cmd */\nfunction handleSlashSelect(cmd: SlashCommand) {\n if (!activeEl || !insertFn || !activePath) {\n return;\n }\n\n // Remove the /command text from the element\n const sel = window.getSelection();\n if (sel && sel.rangeCount) {\n const range = sel.getRangeAt(0);\n const fullText = getTextBeforeCursor(range);\n const slashIdx = fullText.lastIndexOf(\"/\");\n if (slashIdx !== -1) {\n const walker = document.createTreeWalker(activeEl, NodeFilter.SHOW_TEXT);\n let charCount = 0;\n let slashNode: Text | null = null;\n let slashOffset = 0;\n while (walker.nextNode()) {\n const node = walker.currentNode as Text;\n if (charCount + node.length > slashIdx) {\n slashNode = node;\n slashOffset = slashIdx - charCount;\n break;\n }\n charCount += node.length;\n }\n if (slashNode) {\n const delRange = document.createRange();\n delRange.setStart(slashNode, slashOffset);\n delRange.setEnd(range.startContainer, range.startOffset);\n delRange.deleteContents();\n }\n }\n }\n\n // Compute commit data inline instead of calling commitChanges() — avoids a separate\n // Update() call that would race with the insertFn update() (two concurrent async renders).\n normalizeInlineContent(activeEl);\n const commitResult = elementToJx(activeEl);\n\n const path = [...activePath];\n const insert = insertFn;\n\n // The insert carries `commitResult`, so it writes this block's content itself — releasing without\n // A commit keeps the two from racing.\n releaseWithoutCommit();\n\n // Pass commit data so onInsert can batch commit + insert into a single update()\n insert(path, cmd, commitResult);\n}\n",
|
|
17
|
-
"/// <reference lib=\"dom\" />\n/**\n * Geometry read funnel — the single place the studio reads element bounds and does point hit-tests.\n *\n * Centralizing these reads is a seam for the iframe-canvas migration: today every call delegates\n * straight to the DOM, but routing them through one module lets later phases redirect\n * CANVAS-element geometry to rects posted out of the iframe (which the parent can't measure\n * directly) without touching dozens of call sites. A test (`geometry.test.ts`) asserts no raw\n * `getBoundingClientRect`/`elementFromPoint`/`elementsFromPoint` calls exist elsewhere in `src`.\n */\n\n/** Bounding rect of an element, in viewport coordinates. */\nexport function rectOf(el: Element): DOMRect {\n return el.getBoundingClientRect();\n}\n\n/**\n * Bounding rect of a Range, in viewport coordinates. Lives here (the one allowlisted home for\n * `getBoundingClientRect`) so the `geometry.test.ts` textual guard passes — the iframe-side\n * selection snapshot funnels its caret/selection geometry through this, never calling\n * `range.getBoundingClientRect()` directly.\n */\nexport function rectOfRange(r: Range): DOMRect {\n return r.getBoundingClientRect();\n}\n\n/** Topmost element at a viewport point, in `root` (defaults to the global document). */\nexport function elementAtPoint(\n x: number,\n y: number,\n root: Document | ShadowRoot = document,\n): Element | null {\n return root.elementFromPoint(x, y);\n}\n\n/** All elements at a viewport point, front-to-back, in `root` (defaults to the global document). */\nexport function elementsAtPoint(\n x: number,\n y: number,\n root: Document | ShadowRoot = document,\n): Element[] {\n return root.elementsFromPoint(x, y);\n}\n",
|
|
18
|
-
"/// <reference lib=\"dom\" />\n/// <reference lib=\"dom.iterable\" />\n/**\n * Canvas helpers — extracted from studio.js (Phase 4n). Shared query/utility functions used by\n * multiple canvas-related modules: element lookup, zoom, panel resolution, inline bubbling.\n */\n\nimport { canvasPanels, getNodeAtPath, parentElementPath } from \"../store\";\nimport { activeTab } from \"../workspace/workspace\";\nimport { isInlineInContext } from \"../editor/inline-edit\";\nimport type { JxPath } from \"../state\";\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\n\n/**\n * Convert a canvas panel's mediaName to an activeMedia value. Panels without a breakpoint (content\n * mode, single-panel docs) carry \"\" or \"base\" — both mean the base style context (null).\n *\n * @param {string | null | undefined} mediaName\n * @returns {string | null}\n */\nexport function panelMediaToActiveMedia(mediaName: string | null | undefined) {\n return !mediaName || mediaName === \"base\" ? null : mediaName;\n}\n\n/** Return the active canvas panel based on the current activeMedia setting. */\nexport function getActivePanel() {\n if (canvasPanels.length === 0) {\n return null;\n }\n if (canvasPanels.length === 1) {\n return canvasPanels[0];\n }\n const activeMedia = activeTab.value?.session.ui.activeMedia ?? null;\n for (const p of canvasPanels) {\n if (activeMedia === null && (p.mediaName === \"base\" || p.mediaName === null)) {\n return p;\n }\n if (p.mediaName === activeMedia) {\n return p;\n }\n }\n return canvasPanels[0];\n}\n\n/**\n * Walk up the tree from a path, bubbling past inline elements until we find the nearest non-inline\n * ancestor. Returns the original path if already non-inline.\n *\n * @param {JxMutableNode | undefined} doc\n * @param {JxPath} path\n */\nexport function bubbleInlinePath(doc: JxMutableNode | undefined, path: JxPath) {\n if (!doc) {\n return path;\n }\n let currentPath = path;\n while (currentPath.length >= 2) {\n const node = getNodeAtPath(doc, currentPath);\n const pPath = parentElementPath(currentPath);\n const parentNode = pPath ? getNodeAtPath(doc, pPath) : null;\n if (!node || !parentNode) {\n break;\n }\n const childTag = (node.tagName ?? \"div\").toLowerCase();\n const parentTag = (parentNode.tagName ?? \"div\").toLowerCase();\n if (!isInlineInContext(childTag, parentTag)) {\n break;\n }\n currentPath = pPath as JxPath;\n }\n return currentPath;\n}\n\n/**\n * Find a canvas DOM element by its document path.\n *\n * @param {JxPath} path\n * @param {HTMLElement} canvasEl\n * @returns {HTMLElement | null}\n */\nexport function findCanvasElement(path: JxPath, canvasEl: HTMLElement) {\n let el: HTMLElement | null | undefined = canvasEl.firstElementChild as HTMLElement | null;\n if (!el) {\n return null;\n }\n if (path.length === 0) {\n return el;\n }\n\n let i = 0;\n while (i < path.length) {\n const seg = path[i];\n // A lone \"map\" segment steps into a repeater perimeter's single template child.\n if (seg === \"map\") {\n el = el.children[0] as HTMLElement | undefined;\n i += 1;\n if (!el) {\n break;\n }\n continue;\n }\n if (seg !== \"children\" && seg !== \"cases\") {\n return null;\n }\n const idx = path[i + 1];\n if (idx === undefined) {\n el = el.children[0] as HTMLElement | undefined;\n } else if (idx === \"map\") {\n // Legacy whole-children template `[..., \"children\", \"map\"]`: perimeter at child[0].\n el = el.children[0]?.children[0] as HTMLElement | undefined;\n } else {\n el = el.children[idx as number] as HTMLElement | undefined;\n }\n if (!el) {\n break;\n }\n i += 2;\n }\n\n return el ?? null;\n}\n",
|
|
19
|
-
"/// <reference lib=\"dom\" />\n/**\n * Canvas panel utilities — extracted from studio.js (Phase 4l). Panzoom infrastructure: panel DOM\n * template creation, centering, transform application, zoom indicator, and fit-to-screen.\n */\n\nimport { html, nothing } from \"lit-html\";\nimport type { CanvasPanel } from \"../types\";\nimport { ref } from \"lit-html/directives/ref.js\";\nimport { classMap } from \"lit-html/directives/class-map.js\";\nimport { styleMap } from \"lit-html/directives/style-map.js\";\nimport { ifDefined } from \"lit-html/directives/if-defined.js\";\n\nimport { canvasPanels, canvasWrap, renderOnly, updateUi } from \"../store\";\nimport { activeTab } from \"../workspace/workspace\";\nimport { view } from \"../view\";\nimport { findCanvasElement, getActivePanel, panelMediaToActiveMedia } from \"./canvas-helpers\";\nimport { rectOf } from \"../utils/geometry\";\nimport type { TemplateResult } from \"lit-html\";\n\nlet _ctx: {\n getCanvasMode: () => string;\n getZoom: () => number;\n setZoomDirect: (zoom: number) => void;\n};\n\n/**\n * Initialize the canvas utils module.\n *\n * @param {{\n * getCanvasMode: () => string;\n * getZoom: () => number;\n * setZoomDirect: (zoom: number) => void;\n * }} ctx\n */\nexport function initCanvasUtils(ctx: {\n getCanvasMode: () => string;\n getZoom: () => number;\n setZoomDirect: (zoom: number) => void;\n}) {\n _ctx = ctx;\n}\n\n/**\n * Create the DOM structure for a single canvas panel.\n *\n * @param {string | null} mediaName\n * @param {string | null} label\n * @param {boolean} fullWidth\n * @param {number | null} width\n */\nexport function canvasPanelTemplate(\n mediaName: string | null,\n label: string | null,\n fullWidth: boolean,\n width: number | null = null,\n): { tpl: TemplateResult; panel: CanvasPanel } {\n // The DOM fields start null and are wired by the template's ref() directives,\n // Which lit runs synchronously during render — before any consumer reads them.\n const panel = {\n _width: width || null,\n canvas: null,\n element: null,\n mediaName: mediaName || \"\",\n ready: false,\n renderScope: null,\n scrollContainer: null,\n viewport: null,\n } as unknown as CanvasPanel;\n const tpl = html`\n <div\n class=${classMap({ \"canvas-panel\": true, \"full-width\": fullWidth })}\n data-media=${ifDefined(mediaName !== null ? mediaName : undefined)}\n ${ref((el) => {\n if (el) {\n panel.element = el as HTMLElement;\n }\n })}\n >\n ${\n label\n ? html`\n <div\n class=\"canvas-panel-header\"\n @click=${() => {\n updateUi(\"activeMedia\", panelMediaToActiveMedia(mediaName));\n }}\n >\n ${label}\n </div>\n `\n : nothing\n }\n <div\n class=\"canvas-panel-viewport\"\n style=${styleMap({ width: width && !fullWidth ? `${width}px` : \"\" })}\n ${ref((el) => {\n if (el) {\n panel.viewport = el as HTMLElement;\n }\n })}\n >\n <div\n class=\"canvas-panel-canvas\"\n style=${styleMap({ width: width ? `${width}px` : \"\" })}\n ${ref((el) => {\n if (el) {\n panel.canvas = el as HTMLElement;\n }\n })}\n ></div>\n </div>\n </div>\n `;\n return { panel, tpl };\n}\n\n/** Center canvas horizontally in viewport, top-aligned vertically. */\nexport function centerCanvas() {\n if (!view.panzoomWrap) {\n return;\n }\n const wrapWidth = canvasWrap.clientWidth;\n const contentWidth = view.panzoomWrap.scrollWidth;\n const zoom = _ctx.getZoom();\n const scaledWidth = contentWidth * zoom;\n view.panX = Math.max(16, (wrapWidth - scaledWidth) / 2);\n view.panY = 0;\n}\n\n/**\n * Attach a ResizeObserver to view.panzoomWrap that re-centers until the user pans. Handles async\n * content (runtime rendering, data fetching) that changes layout after initial paint.\n */\nexport function observeCenterUntilStable() {\n if (view.centerObserver) {\n view.centerObserver.disconnect();\n view.centerObserver = null;\n }\n if (!view.panzoomWrap) {\n return;\n }\n view.needsCenter = true;\n view.centerObserver = new ResizeObserver(() => {\n if (!view.needsCenter) {\n view.centerObserver?.disconnect();\n view.centerObserver = null;\n return;\n }\n centerCanvas();\n applyTransform();\n });\n view.centerObserver.observe(view.panzoomWrap);\n centerCanvas();\n}\n\n/** Apply the current zoom + pan transform to the panzoom wrapper. */\nexport function applyTransform() {\n if (!view.panzoomWrap) {\n return;\n }\n const zoom = _ctx.getZoom();\n view.panzoomWrap.style.transform = `translate(${view.panX}px, ${view.panY}px) scale(${zoom})`;\n // Overlays live INSIDE the scaled panzoom-wrap (iframe hosts draw there), so no per-mode redraw\n // Is needed here — the flush only re-anchors the fixed block-action-bar. The tab-bar zoom widget\n // Tracks `ui.zoom` reactively, so no explicit indicator refresh is needed either.\n renderOnly(\"overlays\");\n}\n\n// ─── Edit-mode content zoom ──────────────────────────────────────────────────\n// Browser-page-zoom semantics: the canvas footprint stays fixed while the CONTENT reflows at the\n// Zoomed effective width — unlike design mode's panzoom, which visually scales a fixed layout.\n\nexport const EDIT_ZOOM_MIN = 0.25;\n\nexport const EDIT_ZOOM_MAX = 3;\n\n/** Clamp an edit-zoom value to the supported range. */\nexport function clampEditZoom(zoom: number): number {\n return Math.min(EDIT_ZOOM_MAX, Math.max(EDIT_ZOOM_MIN, zoom));\n}\n\n/**\n * Apply the active tab's edit-mode content zoom to the single edit panel.\n *\n * Mechanism: a parent-side transform on the iframe never reflows the iframe's internal document (it\n * is its own layout viewport), so genuine reflow requires resizing the iframe's REAL CSS width to\n * `renderWidth / editZoom` — and a compensating `scale(editZoom)` on the canvas element brings the\n * rendered footprint back to exactly `renderWidth`. The overlay layer (the iframe's DOM sibling\n * inside the canvas element) inherits the transform, so overlay boxes stay drawn at scale 1 (D-2),\n * and `hostDragGeometry`'s empirical `rect.width / clientWidth` evaluates to exactly `editZoom`\n * with no bridge changes.\n *\n * `renderWidth` is measured live from `.content-edit-column` (already `min(baseWidth, available)`\n * via normal block layout) — the nominal `$media[\"--\"]` width would overflow a narrow studio\n * window.\n *\n * HARD INVARIANT: never trigger a canvas re-render from here (`renderCanvas`/`mountIframeCanvas`) —\n * a re-render rebuilds the iframe DOM and would destroy a live inline-edit session. Live zoom is\n * bare style writes only; the iframe's own ResizeObserver re-posts `contentHeight` after the\n * reflow, which also finalizes the viewport height.\n */\nexport function applyEditZoom() {\n if (_ctx.getCanvasMode() !== \"edit\") {\n return;\n }\n const [panel] = canvasPanels;\n if (!panel?.canvas || !panel.viewport) {\n return;\n }\n const canvasEl = panel.canvas;\n const iframe = canvasEl.querySelector(\"iframe\");\n const editZoom = activeTab.value?.session.ui.editZoom ?? 1;\n if (editZoom === 1) {\n // Exactly today's fluid behavior — no inline width, no transform, auto viewport height.\n panel._width = null;\n canvasEl.style.width = \"\";\n canvasEl.style.transform = \"\";\n canvasEl.style.transformOrigin = \"\";\n if (iframe) {\n iframe.style.width = \"100%\";\n }\n panel.viewport.style.height = \"\";\n } else {\n const column = canvasWrap.querySelector<HTMLElement>(\".content-edit-column\");\n if (!column) {\n return;\n }\n // The column width is parent-driven (width:100%, max-width:baseWidth), so it is independent of\n // The canvas content — measuring it mid-zoom is stable. No rounding: layoutWidth * editZoom\n // Must equal renderWidth exactly.\n const renderWidth = rectOf(column).width;\n if (renderWidth <= 0) {\n return;\n }\n const layoutWidth = renderWidth / editZoom;\n panel._width = layoutWidth;\n canvasEl.style.width = `${layoutWidth}px`;\n canvasEl.style.transform = `scale(${editZoom})`;\n canvasEl.style.transformOrigin = \"top left\";\n if (iframe) {\n iframe.style.width = `${layoutWidth}px`;\n // Transforms don't affect an ancestor's auto-height, so the viewport (the white \"page\"\n // Surface) needs its height pinned to the SCALED content height. offsetHeight is the\n // Pre-measurement approximation; the next contentHeight message writes the exact value.\n panel.viewport.style.height = `${iframe.offsetHeight * editZoom}px`;\n }\n }\n // Re-anchor the fixed block-action-bar over the rescaled canvas.\n renderOnly(\"overlays\");\n}\n\n/** Set the active tab's edit zoom (clamped) and apply it synchronously. */\nexport function setEditZoom(zoom: number) {\n const tab = activeTab.value;\n if (!tab) {\n return;\n }\n tab.session.ui.editZoom = clampEditZoom(zoom);\n applyEditZoom();\n}\n\nlet _editZoomRaf = 0;\n\n/**\n * Wheel-rate edit-zoom setter: the reactive `editZoom` write lands immediately (the tab-bar label\n * tracks it), but the DOM work — an iframe width resize, i.e. a real reflow — is coalesced to one\n * `applyEditZoom()` per animation frame so a fast ctrl+scroll burst doesn't thrash layout.\n */\nexport function requestEditZoom(zoom: number) {\n const tab = activeTab.value;\n if (!tab) {\n return;\n }\n tab.session.ui.editZoom = clampEditZoom(zoom);\n if (_editZoomRaf) {\n return;\n }\n _editZoomRaf = requestAnimationFrame(() => {\n _editZoomRaf = 0;\n applyEditZoom();\n });\n}\n\n/** Calculate zoom + pan to fit all panels within the viewport. */\nexport function fitToScreen() {\n if (!view.panzoomWrap) {\n return;\n }\n const wrapWidth = canvasWrap.clientWidth;\n const wrapHeight = canvasWrap.clientHeight;\n const gap = 24;\n const padding = 32;\n let totalPanelWidth = 0;\n for (const p of canvasPanels) {\n totalPanelWidth += p._width || 800;\n }\n totalPanelWidth += gap * Math.max(0, canvasPanels.length - 1) + padding;\n\n const zoom = _ctx.getZoom();\n const wrapRect = rectOf(view.panzoomWrap);\n const unscaledHeight = wrapRect.height / zoom;\n const maxPanelHeight = unscaledHeight + padding;\n\n const fitZoomW = wrapWidth / totalPanelWidth;\n const fitZoomH = wrapHeight / maxPanelHeight;\n const fitZoom = Math.min(5, Math.max(0.05, Math.min(fitZoomW, fitZoomH)));\n\n _ctx.setZoomDirect(fitZoom);\n\n const scaledWidth = totalPanelWidth * fitZoom;\n const scaledHeight = maxPanelHeight * fitZoom;\n view.panX = Math.max(0, (wrapWidth - scaledWidth) / 2);\n view.panY = Math.max(0, (wrapHeight - scaledHeight) / 2);\n applyTransform();\n}\n\n/** Reset zoom to 100% and re-center horizontally. */\nexport function resetZoom() {\n if (!view.panzoomWrap) {\n return;\n }\n _ctx.setZoomDirect(1);\n centerCanvas();\n applyTransform();\n}\n\n/**\n * Smoothly pan/scroll the canvas vertically to center the given DOM element.\n *\n * @param {HTMLElement} el\n * @param {{ scrollContainer?: HTMLElement | null }} [panel]\n */\nfunction _panToEl(el: HTMLElement, panel?: { scrollContainer?: HTMLElement | null }) {\n const wrapRect = rectOf(canvasWrap);\n const elRect = rectOf(el);\n const elCenterY = elRect.top + elRect.height / 2 - wrapRect.top;\n const vpCenterY = wrapRect.height / 2;\n const offsetY = vpCenterY - elCenterY;\n\n if (panel?.scrollContainer) {\n panel.scrollContainer.scrollTo({\n behavior: \"smooth\",\n top: panel.scrollContainer.scrollTop - offsetY,\n });\n } else {\n animatePanBy(offsetY);\n }\n}\n\n/**\n * Pan the panzoom canvas vertically so a PARENT-VIEWPORT rect is centered — for callers whose\n * target lives inside an iframe (no parent DOM element to measure; the host converts the measured\n * iframe rect and passes it here).\n */\nexport function panToParentRect(rect: { top: number; height: number }) {\n const wrapRect = rectOf(canvasWrap);\n const elCenterY = rect.top + rect.height / 2 - wrapRect.top;\n animatePanBy(wrapRect.height / 2 - elCenterY);\n}\n\n/** Animate `view.panY` by `offsetY` with the shared 250ms ease-out. */\nfunction animatePanBy(offsetY: number) {\n const startY = view.panY;\n const targetY = startY + offsetY;\n const start = performance.now();\n const duration = 250;\n const step = (now: number) => {\n const t = Math.min((now - start) / duration, 1);\n const ease = t * (2 - t);\n view.panY = startY + (targetY - startY) * ease;\n applyTransform();\n if (t < 1) {\n requestAnimationFrame(step);\n }\n };\n requestAnimationFrame(step);\n}\n\n/**\n * Pan the canvas vertically so the element at `path` is centered in the viewport.\n *\n * @param {(string | number)[]} path\n */\nexport function panToElement(path: (string | number)[]) {\n const panel = getActivePanel();\n if (!panel?.canvas) {\n return;\n }\n const el = findCanvasElement(path, panel.canvas);\n if (!el) {\n return;\n }\n _panToEl(el, panel);\n}\n\n/** Toggle \"active\" class on canvas panel headers based on activeMedia. */\nexport function updateActivePanelHeaders() {\n const activeMedia = activeTab.value?.session.ui.activeMedia ?? null;\n for (const p of canvasPanels) {\n const header = p.element?.querySelector(\".canvas-panel-header\");\n if (header) {\n const isActive =\n (activeMedia === null && p.mediaName === \"base\") ||\n (activeMedia === null && p.mediaName === null) ||\n activeMedia === p.mediaName;\n header.classList.toggle(\"active\", isActive);\n }\n }\n}\n",
|
|
20
|
-
"// In order to disable the native drag preview you can\n// use `event.dataTransfer.setDragImage()` to set a small\n// invisible image as the drag preview.\n// There are alternative techniques,\n// (eg setting opacity to in onGenerateDragPreview and then 1 in onDragStart)\n// but the technique in this file worked best across browsers and platforms\n\n// Here we are preloading the image so that it is ready for the first drag.\n// Even though the image is base64 encoded, the browser queues an async task\n// to decode the image. The image needs to be decoded before it can be used\nvar tinyTransparentImage = function () {\n // SSR safe\n if (typeof window === 'undefined') {\n return null;\n }\n\n // Image generated by: https://png-pixel.com/\n // It is a 1x1 transparent gif\n // It is the smallest possible transparent image we could find that works on all platforms\n // Note: using an encoded SVG would be nicer code, but it doesn't work on iOS\n var img = new Image();\n img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==';\n return img;\n}();\nexport function disableNativeDragPreview(_ref) {\n var nativeSetDragImage = _ref.nativeSetDragImage;\n if (nativeSetDragImage && tinyTransparentImage) {\n nativeSetDragImage(tinyTransparentImage, 0, 0);\n }\n}",
|
|
21
|
-
"function _objectWithoutPropertiesLoose(r, e) {\n if (null == r) return {};\n var t = {};\n for (var n in r) if ({}.hasOwnProperty.call(r, n)) {\n if (-1 !== e.indexOf(n)) continue;\n t[n] = r[n];\n }\n return t;\n}\nexport { _objectWithoutPropertiesLoose as default };",
|
|
22
|
-
"import objectWithoutPropertiesLoose from \"./objectWithoutPropertiesLoose.js\";\nfunction _objectWithoutProperties(e, t) {\n if (null == e) return {};\n var o,\n r,\n i = objectWithoutPropertiesLoose(e, t);\n if (Object.getOwnPropertySymbols) {\n var n = Object.getOwnPropertySymbols(e);\n for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]);\n }\n return i;\n}\nexport { _objectWithoutProperties as default };",
|
|
23
|
-
"export function isShallowEqual(a, b) {\n var aKeys = Object.keys(a);\n var bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) {\n return false;\n }\n return aKeys.every(function (key) {\n return Object.is(a[key], b[key]);\n });\n}\n\n/**\n * Used to store a stable object, which returns a new object only if one of the values has changed\n */\nexport function stable() {\n var isEqual = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : isShallowEqual;\n var cache = null;\n return function (value) {\n if (cache && isEqual(cache.value, value)) {\n return cache.value;\n }\n cache = {\n value: value\n };\n return cache.value;\n };\n}",
|
|
24
|
-
"import _defineProperty from \"@babel/runtime/helpers/defineProperty\";\nimport _objectWithoutProperties from \"@babel/runtime/helpers/objectWithoutProperties\";\nvar _excluded = [\"block\"];\nfunction ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }\nfunction _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }\nimport { isShallowEqual, stable } from './internal/memoize';\n// using a symbol so we can guarantee a key with a unique value\nvar uniqueKey = Symbol('tree-item-instruction');\nfunction getCenter(rect) {\n return {\n x: (rect.right + rect.left) / 2,\n y: (rect.bottom + rect.top) / 2\n };\n}\nfunction standardHitbox(_ref) {\n var client = _ref.client,\n borderBox = _ref.borderBox;\n var quarterOfHeight = borderBox.height / 4;\n\n // In the top 1/4: reorder-above\n // On the line = in the top 1/4 to give this zone a bit more space\n if (client.y <= borderBox.top + quarterOfHeight) {\n return 'reorder-above';\n }\n // In the bottom 1/4: reorder-below\n // On the line = in the bottom 1/4 to give this zone a bit more space\n if (client.y >= borderBox.bottom - quarterOfHeight) {\n return 'reorder-below';\n }\n return 'make-child';\n}\nfunction getInstruction(_ref2) {\n var element = _ref2.element,\n input = _ref2.input,\n currentLevel = _ref2.currentLevel,\n indentPerLevel = _ref2.indentPerLevel,\n mode = _ref2.mode;\n var client = {\n x: input.clientX,\n y: input.clientY\n };\n var borderBox = element.getBoundingClientRect();\n if (mode === 'standard') {\n var type = standardHitbox({\n borderBox: borderBox,\n client: client\n });\n return {\n type: type,\n indentPerLevel: indentPerLevel,\n currentLevel: currentLevel\n };\n }\n var center = getCenter(borderBox);\n if (mode === 'expanded') {\n // leveraging \"standard\" hitbox to ensure that the 'reorder-above' hit zone is\n // exactly the same for \"standard\" and \"expanded\" items\n var _type = standardHitbox({\n borderBox: borderBox,\n client: client\n });\n return {\n // Use the \"standard\" hitbox for \"reorder above\",\n // The rest of the item is \"make-child\"\n type: _type === 'reorder-above' ? _type : 'make-child',\n indentPerLevel: indentPerLevel,\n currentLevel: currentLevel\n };\n }\n\n // `mode` is \"last-in-group\"\n\n var visibleInset = indentPerLevel * currentLevel;\n\n // Before the left edge of the visible item\n if (client.x < borderBox.left + visibleInset) {\n // Above the center: `reorder-above`\n if (client.y < center.y) {\n return {\n type: 'reorder-above',\n indentPerLevel: indentPerLevel,\n currentLevel: currentLevel\n };\n }\n // On or below the center: `reparent`\n // On the center = `reparent` as we are giving a slightly bigger hitbox to this\n // action as it is the only place a user can do it\n var rawLevel = (client.x - borderBox.left) / indentPerLevel;\n // We can get sub pixel negative numbers as getBoundingClientRect gives sub-pixel accuracy,\n // where as clientX is rounded to the nearest pixel.\n // Using Math.max() ensures we can never get a negative level\n var desiredLevel = Math.max(Math.floor(rawLevel), 0);\n return {\n type: 'reparent',\n desiredLevel: desiredLevel,\n indentPerLevel: indentPerLevel,\n currentLevel: currentLevel\n };\n }\n // On the visible item\n return {\n type: standardHitbox({\n borderBox: borderBox,\n client: client\n }),\n indentPerLevel: indentPerLevel,\n currentLevel: currentLevel\n };\n}\nfunction areInstructionsEqual(a, b) {\n // Shortcut\n if (a.type !== b.type) {\n return false;\n }\n if (a.type === 'instruction-blocked' && b.type === 'instruction-blocked') {\n return areInstructionsEqual(a.desired, b.desired);\n }\n return isShallowEqual(a, b);\n}\n\n// Note: not using `memoize-one` as all we need is a cached value.\n// We do not need to avoid executing an expensive function.\nvar memoizeInstruction = stable(areInstructionsEqual);\nfunction applyInstructionBlock(_ref3) {\n var desired = _ref3.desired,\n block = _ref3.block;\n if (block !== null && block !== void 0 && block.includes(desired.type) && desired.type !== 'instruction-blocked') {\n var blocked = {\n type: 'instruction-blocked',\n desired: desired\n };\n return blocked;\n }\n return desired;\n}\nexport function attachInstruction(userData, _ref4) {\n var block = _ref4.block,\n rest = _objectWithoutProperties(_ref4, _excluded);\n var desired = getInstruction(rest);\n var withBlock = applyInstructionBlock({\n desired: desired,\n block: block\n });\n var memoized = memoizeInstruction(withBlock);\n return _objectSpread(_objectSpread({}, userData), {}, _defineProperty({}, uniqueKey, memoized));\n}\nexport function extractInstruction(userData) {\n var _ref5;\n return (_ref5 = userData[uniqueKey]) !== null && _ref5 !== void 0 ? _ref5 : null;\n}",
|
|
25
|
-
"/// <reference lib=\"dom\" />\n/**\n * Jx Declarative Expression Engine (spec §19)\n *\n * Shared module used by both runtime (evaluateExpression) and compiler (compileExpression).\n *\n * @module expression\n */\n\nimport type { JxExpressionNode, JxExpressionOperand } from \"@jxsuite/schema/types\";\nimport type { JxScope } from \"./types.ts\";\n\n/** The runtime's expression node — the schema's expression model. */\nexport type ExpressionNode = JxExpressionNode;\nexport type ExpressionOperand = JxExpressionOperand;\n\n/** The `$map` iteration context object stored in scope during mapped rendering. */\ninterface ScopeMapCtx {\n item?: unknown;\n index?: number;\n [key: string]: unknown;\n}\n\n/** View the scope's `$map` iteration context, if present. */\nfunction scopeMap(state: JxScope): ScopeMapCtx | undefined {\n const map = state.$map;\n return map && typeof map === \"object\" ? (map as ScopeMapCtx) : undefined;\n}\n\ninterface CompileOpts {\n statePrefix?: string;\n eventParam?: string;\n /**\n * Parameter-name order per named-formula state key, used by `call` sites to map positional\n * argument lists onto the emitted formula functions' named-args object.\n */\n formulaParams?: Record<string, string[]>;\n}\n\nconst MUTATING_OPS = new Set([\n \"=\",\n \"+=\",\n \"-=\",\n \"*=\",\n \"/=\",\n \"push\",\n \"pop\",\n \"shift\",\n \"unshift\",\n \"splice\",\n]);\nconst UNARY_OPS = new Set([\"!\", \"-\"]);\nconst BINARY_OPS = new Set([\n \"+\",\n \"-\",\n \"*\",\n \"/\",\n \"%\",\n \"===\",\n \"!==\",\n \"<\",\n \"<=\",\n \">\",\n \">=\",\n \"&&\",\n \"||\",\n \"??\",\n]);\nconst ASSIGNMENT_OPS = new Set([\"=\", \"+=\", \"-=\", \"*=\", \"/=\"]);\nconst ARRAY_METHOD_OPS = new Set([\"push\", \"pop\", \"shift\", \"unshift\", \"splice\"]);\nconst AGGREGATE_OPS = new Set([\"reduce\", \"map\", \"filter\"]);\nconst CONDITIONAL_OPS = new Set([\"?:\", \"switch\"]);\n\n/**\n * Pure standard-library method operators (spec §19.4d): genuine `String.prototype` /\n * `Array.prototype` / `Number.prototype` methods that never mutate their receiver — the ES2023\n * change-by-copy family stands in where mutation would otherwise occur (`toSorted`, not `sort`).\n * Receiver in `target`; `value` carries the argument (bare scalar) or argument list (array), the\n * splice precedent. No token is invented.\n */\nexport const PURE_METHOD_OPS = new Set([\n // Array.prototype (and the String.prototype homonyms: includes/indexOf/slice/at/concat)\n \"includes\",\n \"indexOf\",\n \"lastIndexOf\",\n \"join\",\n \"slice\",\n \"concat\",\n \"at\",\n \"flat\",\n \"toSorted\",\n \"toReversed\",\n \"toSpliced\",\n \"with\",\n // String.prototype\n \"toUpperCase\",\n \"toLowerCase\",\n \"trim\",\n \"trimStart\",\n \"trimEnd\",\n \"split\",\n \"startsWith\",\n \"endsWith\",\n \"padStart\",\n \"padEnd\",\n \"replaceAll\",\n \"repeat\",\n \"charAt\",\n \"normalize\",\n \"toLocaleUpperCase\",\n \"toLocaleLowerCase\",\n // Number.prototype\n \"toFixed\",\n \"toPrecision\",\n \"toLocaleString\",\n]);\n\nexport const BLESSED_OPERATORS = new Set([\n ...MUTATING_OPS,\n ...UNARY_OPS,\n ...BINARY_OPS,\n ...AGGREGATE_OPS,\n ...CONDITIONAL_OPS,\n ...PURE_METHOD_OPS,\n \"call\",\n]);\n\n/**\n * Pure globals a `call` node may target through the `window#/` scheme (spec §19.4c). Every entry is\n * a genuine ECMAScript or WHATWG standard-library function with no side effects; anything off this\n * list is a compile-time error, keeping formula purity decidable.\n */\nexport const BLESSED_GLOBALS = new Set([\n // Global functions\n \"isNaN\",\n \"isFinite\",\n \"parseFloat\",\n \"parseInt\",\n \"encodeURIComponent\",\n \"decodeURIComponent\",\n \"structuredClone\",\n // Math\n \"Math/abs\",\n \"Math/ceil\",\n \"Math/floor\",\n \"Math/round\",\n \"Math/trunc\",\n \"Math/sign\",\n \"Math/sqrt\",\n \"Math/cbrt\",\n \"Math/pow\",\n \"Math/exp\",\n \"Math/log\",\n \"Math/log2\",\n \"Math/log10\",\n \"Math/min\",\n \"Math/max\",\n \"Math/hypot\",\n // Number\n \"Number/isInteger\",\n \"Number/isFinite\",\n \"Number/isNaN\",\n \"Number/parseFloat\",\n \"Number/parseInt\",\n // JSON\n \"JSON/parse\",\n \"JSON/stringify\",\n // Object\n \"Object/keys\",\n \"Object/values\",\n \"Object/entries\",\n \"Object/fromEntries\",\n // Array\n \"Array/from\",\n \"Array/isArray\",\n \"Array/of\",\n // String\n \"String/fromCharCode\",\n \"String/fromCodePoint\",\n // Intl (synthetic helpers — see BLESSED_HELPERS; Intl formatters are constructors,\n // So the plain-function call shape wraps construct-then-format)\n \"Intl/formatNumber\",\n \"Intl/formatDate\",\n \"Intl/formatRelativeTime\",\n]);\n\n/**\n * Synthetic blessed helpers (spec §19.4c): pure functions that have no direct `window` global\n * because the underlying standard-library API is a constructor. The interpreter dispatches to\n * these; the compiler emits the equivalent inline construct-then-format expression.\n */\nconst BLESSED_HELPERS: Record<string, (...a: unknown[]) => unknown> = {\n \"Intl/formatDate\": (value, locale, options) =>\n new Intl.DateTimeFormat(\n locale as string | undefined,\n options as Intl.DateTimeFormatOptions | undefined,\n ).format(new Date(value as string | number | Date)),\n \"Intl/formatNumber\": (value, locale, options) =>\n new Intl.NumberFormat(\n locale as string | undefined,\n options as Intl.NumberFormatOptions | undefined,\n ).format(value as number),\n \"Intl/formatRelativeTime\": (value, unit, locale, options) =>\n new Intl.RelativeTimeFormat(\n locale as string | undefined,\n options as Intl.RelativeTimeFormatOptions | undefined,\n ).format(value as number, unit as Intl.RelativeTimeFormatUnit),\n};\n\n/** Whether a `window#/…` callee ref is on the blessed pure-globals list. */\nexport function isBlessedGlobal(ref: string): boolean {\n return ref.startsWith(\"window#/\") && BLESSED_GLOBALS.has(ref.slice(\"window#/\".length));\n}\n\n/**\n * @param {string} op\n * @returns {boolean}\n */\nexport function isMutating(op: string) {\n return MUTATING_OPS.has(op);\n}\n\n// ─── Runtime Evaluation ──────────────────────────────────────────────────────\n\ninterface IterCtx {\n acc?: unknown;\n item?: unknown;\n index?: number;\n /** Named-formula arguments bound for the current `call` body ($args/<name> refs). */\n args?: Record<string, unknown>;\n /** Call-nesting depth; capped at MAX_CALL_DEPTH to bound recursive formulas. */\n callDepth?: number;\n}\n\n/** Recursion bound for `call` chains (formula → formula), mirroring MAX_REPORT_DEPTH. */\nexport const MAX_CALL_DEPTH = 64;\n\n/**\n * Editor-mode evaluation trace (spec §19.9). When passed, every node and operand reports its\n * evaluated value keyed by its path within the expression tree, and the branch-selecting operators\n * (`?:`, `switch` — plus the eager `&&`/`||`/`??`) yield values for ALL branches so a visual editor\n * can badge every node. Absent (production), evaluation is untouched.\n */\nexport interface ExpressionTrace {\n report: (path: (string | number)[], value: unknown) => void;\n /** Current node path — internal; leave unset at the call boundary. */\n path?: (string | number)[];\n /** Recursion depth — internal; reporting stops beyond MAX_REPORT_DEPTH. */\n depth?: number;\n}\n\n/** Reporting recursion bound: branch-forcing removes natural exit conditions, so cap the walk. */\nexport const MAX_REPORT_DEPTH = 64;\n\n/** Derive the trace for a child operand at path segment(s) `seg`; undefined once capped. */\nfunction subTrace(\n trace: ExpressionTrace | undefined,\n seg: string | number | (string | number)[],\n): ExpressionTrace | undefined {\n if (!trace) {\n return undefined;\n }\n const depth = (trace.depth ?? 0) + 1;\n if (depth > MAX_REPORT_DEPTH) {\n return undefined;\n }\n return {\n depth,\n path: [...(trace.path ?? []), ...(Array.isArray(seg) ? seg : [seg])],\n report: trace.report,\n };\n}\n\n/** Resolve an operand to its runtime value. */\nfunction resolveOperand(\n operand: unknown,\n state: JxScope,\n event: Event | null,\n iterCtx?: IterCtx,\n trace?: ExpressionTrace,\n): unknown {\n if (operand === null || operand === undefined) {\n return operand;\n }\n\n // Nested expression node\n if (typeof operand === \"object\" && !Array.isArray(operand) && \"operator\" in operand) {\n return evaluateExpression(operand as ExpressionNode, state, event, iterCtx, trace);\n }\n\n // $ref pointer\n if (typeof operand === \"object\" && !Array.isArray(operand) && \"$ref\" in operand) {\n const resolved = resolveExprRef((operand as { $ref: string }).$ref, state, event, iterCtx);\n trace?.report(trace.path ?? [], resolved);\n return resolved;\n }\n\n // Array of operands (e.g., splice args)\n if (Array.isArray(operand)) {\n return operand.map((o: unknown, i: number) =>\n resolveOperand(o, state, event, iterCtx, subTrace(trace, i)),\n );\n }\n\n // Literal\n trace?.report(trace.path ?? [], operand);\n return operand;\n}\n\n/** Resolve a $ref string within expression context. */\nfunction resolveExprRef(ref: string, state: JxScope, event: Event | null, iterCtx?: IterCtx) {\n if (ref === \"$reduce/acc\") {\n return iterCtx?.acc;\n }\n if (ref.startsWith(\"$reduce/\")) {\n return iterCtx?.acc;\n }\n if (ref.startsWith(\"$args/\")) {\n const parts = ref.slice(\"$args/\".length).split(\"/\");\n const base = iterCtx?.args?.[parts[0]!];\n return parts.length > 1 ? getPath(base, parts.slice(1).join(\"/\")) : base;\n }\n if (ref.startsWith(\"event#/\")) {\n const path = ref.slice(\"event#/\".length);\n return getPath(event, path);\n }\n if (ref.startsWith(\"$map/\")) {\n const parts = ref.split(\"/\");\n const [, key] = parts;\n let base;\n const map = scopeMap(state);\n if (key === \"item\") {\n base = iterCtx?.item ?? map?.item ?? state[\"$map/item\"];\n } else if (key === \"index\") {\n base = iterCtx?.index ?? map?.index ?? state[\"$map/index\"];\n } else {\n base = map?.[key!] ?? state[`$map/${key}`];\n }\n return parts.length > 2 ? getPath(base, parts.slice(2).join(\"/\")) : base;\n }\n if (ref.startsWith(\"#/state/\")) {\n const sub = ref.slice(\"#/state/\".length);\n const slash = sub.indexOf(\"/\");\n if (slash === -1) {\n return state[sub];\n }\n return getPath(state[sub.slice(0, slash)], sub.slice(slash + 1));\n }\n if (ref.startsWith(\"parent#/\")) {\n return state[ref.slice(\"parent#/\".length)];\n }\n if (ref.startsWith(\"window#/\")) {\n return getPath(globalThis.window, ref.slice(\"window#/\".length));\n }\n if (ref.startsWith(\"document#/\")) {\n return getPath(globalThis.document, ref.slice(\"document#/\".length));\n }\n return state[ref] ?? null;\n}\n\n/** Resolve a $ref to a writable location — returns { obj, key } for assignment. */\nfunction resolveWritableRef(\n ref: string,\n state: JxScope,\n _event: Event | null,\n iterCtx?: IterCtx,\n): { obj: JxScope; key: string } {\n if (ref.startsWith(\"$map/\")) {\n const parts = ref.split(\"/\");\n const [, key] = parts;\n let base;\n const map = scopeMap(state);\n if (key === \"item\") {\n base = iterCtx?.item ?? map?.item ?? state[\"$map/item\"];\n } else if (key === \"index\") {\n base = iterCtx?.index ?? map?.index ?? state[\"$map/index\"];\n } else {\n base = map?.[key!] ?? state[`$map/${key}`];\n }\n if (parts.length > 2) {\n const pathParts = parts.slice(2);\n const lastKey = pathParts.pop();\n const obj = pathParts.length > 0 ? getPath(base, pathParts.join(\"/\")) : base;\n return { key: lastKey as string, obj: obj as JxScope };\n }\n return {\n key: key === \"item\" ? \"$map/item\" : \"$map/index\",\n obj: scopeMap(state) ?? state,\n };\n }\n if (ref.startsWith(\"#/state/\")) {\n const sub = ref.slice(\"#/state/\".length);\n const slash = sub.indexOf(\"/\");\n if (slash === -1) {\n return { key: sub, obj: state };\n }\n const parts = sub.split(\"/\");\n const lastKey = parts.pop();\n let obj = state;\n // Pointer paths address objects by construction (validated by the schema).\n for (const p of parts) {\n obj = obj[p] as JxScope;\n }\n return { key: lastKey as string, obj };\n }\n return { key: ref, obj: state };\n}\n\n/** Evaluate an expression node at runtime. */\nexport function evaluateExpression(\n node: ExpressionNode,\n state: JxScope,\n event: Event | null,\n iterCtx?: IterCtx,\n trace?: ExpressionTrace,\n): unknown {\n const result = evaluateNode(node, state, event, iterCtx, trace);\n trace?.report(trace.path ?? [], result);\n return result;\n}\n\nfunction evaluateNode(\n node: ExpressionNode,\n state: JxScope,\n event: Event | null,\n iterCtx?: IterCtx,\n trace?: ExpressionTrace,\n): unknown {\n const { operator, target, value, initial } = node;\n\n if (!BLESSED_OPERATORS.has(operator)) {\n throw new Error(`$expression: unknown operator \"${operator}\"`);\n }\n\n // ─── Unary ───\n if (UNARY_OPS.has(operator) && !(\"value\" in node)) {\n const operand: unknown = resolveOperand(\n target,\n state,\n event,\n iterCtx,\n subTrace(trace, \"target\"),\n );\n if (operator === \"!\") {\n return !operand;\n }\n if (operator === \"-\") {\n return -(operand as number);\n }\n }\n\n // ─── Call (spec §19.4c) ───\n if (operator === \"call\") {\n const calleeRef = (target as { $ref?: string } | null)?.$ref;\n if (typeof calleeRef !== \"string\") {\n throw new TypeError(\"$expression: call target must be a $ref pointer\");\n }\n const callDepth = (iterCtx?.callDepth ?? 0) + 1;\n if (callDepth > MAX_CALL_DEPTH) {\n throw new Error(`$expression: call depth exceeded (${MAX_CALL_DEPTH})`);\n }\n const argValues = Array.isArray(value)\n ? value.map((o: unknown, i: number) =>\n resolveOperand(o, state, event, iterCtx, subTrace(trace, [\"value\", i])),\n )\n : [];\n\n // Blessed pure global via the window#/ scheme (Math.max, JSON.parse, …).\n if (calleeRef.startsWith(\"window#/\")) {\n if (!isBlessedGlobal(calleeRef)) {\n throw new Error(`$expression: \"${calleeRef}\" is not a blessed pure global`);\n }\n const globalPath = calleeRef.slice(\"window#/\".length);\n const helper = BLESSED_HELPERS[globalPath];\n if (helper) {\n return helper(...argValues);\n }\n const fn = getPath(globalThis.window, globalPath) as (...a: unknown[]) => unknown;\n const lastSlash = globalPath.lastIndexOf(\"/\");\n const thisArg =\n lastSlash === -1\n ? globalThis.window\n : getPath(globalThis.window, globalPath.slice(0, lastSlash));\n return fn.apply(thisArg, argValues);\n }\n\n const callee = resolveExprRef(calleeRef, state, event, iterCtx);\n // A scope callable (buildScope lowers parameterized formula entries to functions).\n if (typeof callee === \"function\") {\n return (callee as (...a: unknown[]) => unknown)(...argValues);\n }\n // A raw named-formula def (standalone evaluation, e.g. editor preview).\n if (callee && typeof callee === \"object\" && \"$expression\" in callee) {\n const def = callee as { $expression: ExpressionNode; parameters?: unknown[] };\n const args: Record<string, unknown> = {};\n for (const [i, p] of (def.parameters ?? []).entries()) {\n const name = typeof p === \"string\" ? p : ((p as { name?: string } | null)?.name ?? \"\");\n if (!name) {\n continue;\n }\n args[name] =\n argValues[i] === undefined && typeof p === \"object\" && p !== null && \"default\" in p\n ? (p as { default?: unknown }).default\n : argValues[i];\n }\n // The callee body's node paths are its own tree, not the call site's — no trace inside.\n return evaluateExpression(def.$expression, state, event, { args, callDepth });\n }\n throw new TypeError(`$expression: call target \"${calleeRef}\" is not callable`);\n }\n\n // ─── Conditional (pure) ───\n if (CONDITIONAL_OPS.has(operator)) {\n if (operator === \"?:\") {\n const test = resolveOperand(target, state, event, iterCtx, subTrace(trace, \"target\"));\n if (trace) {\n // Editor mode: evaluate both branches so each carries a live value.\n const consequent = resolveOperand(value, state, event, iterCtx, subTrace(trace, \"value\"));\n const alternate = resolveOperand(\n initial,\n state,\n event,\n iterCtx,\n subTrace(trace, \"initial\"),\n );\n return test ? consequent : alternate;\n }\n return test\n ? resolveOperand(value, state, event, iterCtx)\n : resolveOperand(initial, state, event, iterCtx);\n }\n // Switch — value-keyed selection; discriminant matched against case keys by string form.\n const discriminant = resolveOperand(target, state, event, iterCtx, subTrace(trace, \"target\"));\n const key = String(discriminant);\n const cases = node.cases ?? {};\n const matched = Object.hasOwn(cases, key);\n if (trace) {\n let result: unknown;\n for (const [k, caseOperand] of Object.entries(cases)) {\n const v = resolveOperand(caseOperand, state, event, iterCtx, subTrace(trace, [\"cases\", k]));\n if (k === key) {\n result = v;\n }\n }\n const fallback = resolveOperand(\n node.default,\n state,\n event,\n iterCtx,\n subTrace(trace, \"default\"),\n );\n return matched ? result : fallback;\n }\n return matched\n ? resolveOperand(cases[key], state, event, iterCtx)\n : resolveOperand(node.default, state, event, iterCtx);\n }\n\n // ─── Binary (pure) ───\n if (BINARY_OPS.has(operator)) {\n const left = resolveOperand(\n target,\n state,\n event,\n iterCtx,\n subTrace(trace, \"target\"),\n ) as number & string;\n const right = resolveOperand(value, state, event, iterCtx, subTrace(trace, \"value\")) as number &\n string;\n switch (operator) {\n case \"+\": {\n return left + right;\n }\n case \"-\": {\n return left - right;\n }\n case \"*\": {\n return left * right;\n }\n case \"/\": {\n return left / right;\n }\n case \"%\": {\n return left % right;\n }\n case \"===\": {\n return left === right;\n }\n case \"!==\": {\n return left !== right;\n }\n case \"<\": {\n return left < right;\n }\n case \"<=\": {\n return left <= right;\n }\n case \">\": {\n return left > right;\n }\n case \">=\": {\n return left >= right;\n }\n case \"&&\": {\n return left && right;\n }\n case \"||\": {\n return left || right;\n }\n case \"??\": {\n return (left as unknown) ?? (right as unknown);\n }\n default: {\n break;\n }\n }\n }\n\n // ─── Assignment ───\n if (ASSIGNMENT_OPS.has(operator)) {\n const rhs = resolveOperand(value, state, event, iterCtx, subTrace(trace, \"value\")) as number;\n const { obj, key } = resolveWritableRef(\n (target as { $ref: string }).$ref,\n state,\n event,\n iterCtx,\n );\n switch (operator) {\n case \"=\": {\n obj[key] = rhs;\n break;\n }\n case \"+=\": {\n const current = obj[key] as number;\n obj[key] = current + rhs;\n break;\n }\n case \"-=\": {\n const current = obj[key] as number;\n obj[key] = current - rhs;\n break;\n }\n case \"*=\": {\n const current = obj[key] as number;\n obj[key] = current * rhs;\n break;\n }\n case \"/=\": {\n const current = obj[key] as number;\n obj[key] = current / rhs;\n break;\n }\n default: {\n break;\n }\n }\n return;\n }\n\n // ─── Array methods ───\n if (ARRAY_METHOD_OPS.has(operator)) {\n const arr: unknown[] = resolveOperand(\n target,\n state,\n event,\n iterCtx,\n subTrace(trace, \"target\"),\n ) as unknown[];\n switch (operator) {\n case \"push\": {\n return arr.push(resolveOperand(value, state, event, iterCtx, subTrace(trace, \"value\")));\n }\n case \"unshift\": {\n return arr.unshift(resolveOperand(value, state, event, iterCtx, subTrace(trace, \"value\")));\n }\n case \"pop\": {\n return arr.pop();\n }\n case \"shift\": {\n return arr.shift();\n }\n case \"splice\": {\n const args: unknown[] = resolveOperand(\n value,\n state,\n event,\n iterCtx,\n subTrace(trace, \"value\"),\n ) as unknown[];\n return (arr.splice as (...a: unknown[]) => unknown[])(...args);\n }\n default: {\n break;\n }\n }\n }\n\n // ─── Pure standard-library methods (spec §19.4d) ───\n if (PURE_METHOD_OPS.has(operator)) {\n const receiver = resolveOperand(target, state, event, iterCtx, subTrace(trace, \"target\"));\n const args =\n value === undefined\n ? []\n : Array.isArray(value)\n ? (resolveOperand(value, state, event, iterCtx, subTrace(trace, \"value\")) as unknown[])\n : [resolveOperand(value, state, event, iterCtx, subTrace(trace, \"value\"))];\n const method = (receiver as Record<string, unknown> | null | undefined)?.[operator];\n if (typeof method !== \"function\") {\n // Null-safe, like path reads: a missing receiver or method yields undefined, not a throw.\n return undefined;\n }\n return (method as (...a: unknown[]) => unknown).apply(receiver, args);\n }\n\n // ─── Aggregates (pure) ───\n if (AGGREGATE_OPS.has(operator)) {\n const arr: unknown[] = resolveOperand(\n target,\n state,\n event,\n iterCtx,\n subTrace(trace, \"target\"),\n ) as unknown[];\n // Trace only the first iteration's per-item expression — one sample badge per node,\n // Not one report per array element.\n if (operator === \"reduce\") {\n let acc: unknown = resolveOperand(initial, state, event, iterCtx, subTrace(trace, \"initial\"));\n for (const [index, item] of arr.entries()) {\n acc = evaluateExpression(\n value as ExpressionNode,\n state,\n event,\n { acc, index, item },\n index === 0 ? subTrace(trace, \"value\") : undefined,\n );\n }\n return acc;\n }\n if (operator === \"map\") {\n return arr.map((item: unknown, index: number) =>\n evaluateExpression(\n value as ExpressionNode,\n state,\n event,\n { ...iterCtx, index, item },\n index === 0 ? subTrace(trace, \"value\") : undefined,\n ),\n );\n }\n if (operator === \"filter\") {\n return arr.filter((item: unknown, index: number) =>\n evaluateExpression(\n value as ExpressionNode,\n state,\n event,\n { ...iterCtx, index, item },\n index === 0 ? subTrace(trace, \"value\") : undefined,\n ),\n );\n }\n }\n\n return undefined;\n}\n\n// ─── Compiler: Expression → JS Source ────────────────────────────────────────\n\n/** Compile an operand to a JS source string. */\nfunction compileOperand(operand: unknown, opts: CompileOpts): string {\n if (operand === null) {\n return \"null\";\n }\n if (operand === undefined) {\n return \"undefined\";\n }\n\n // Nested expression node\n if (typeof operand === \"object\" && !Array.isArray(operand) && \"operator\" in operand) {\n return compileExpression(operand as ExpressionNode, opts);\n }\n\n // $ref pointer\n if (typeof operand === \"object\" && !Array.isArray(operand) && \"$ref\" in operand) {\n return compileRef((operand as { $ref: string }).$ref, opts);\n }\n\n // Array of operands\n if (Array.isArray(operand)) {\n return operand.map((o: unknown) => compileOperand(o, opts)).join(\", \");\n }\n\n // Literal\n return JSON.stringify(operand);\n}\n\n/**\n * The module-scope function name a named formula compiles to. Shared by call-site emission here and\n * the declaration emission in the compiler targets.\n *\n * @param {string} key\n * @returns {string}\n */\nexport function formulaFnName(key: string) {\n return `_fx_${key.replaceAll(/[^A-Za-z0-9_$]/g, \"_\")}`;\n}\n\n/**\n * Compile a $ref to its JS equivalent.\n *\n * @param {string} ref\n * @param {CompileOpts} opts\n * @returns {string}\n */\nfunction compileRef(ref: string, opts: CompileOpts) {\n const s = opts.statePrefix ?? \"state\";\n const e = opts.eventParam ?? \"event\";\n\n if (ref === \"$reduce/acc\") {\n return \"_acc\";\n }\n if (ref.startsWith(\"$reduce/\")) {\n return \"_acc\";\n }\n if (ref.startsWith(\"$args/\")) {\n const parts = ref.slice(\"$args/\".length).split(\"/\");\n return `_args${parts.map((p) => `[${JSON.stringify(p)}]`).join(\"\")}`;\n }\n\n if (ref.startsWith(\"event#/\")) {\n const path = ref.slice(\"event#/\".length);\n return `${e}.${path.replaceAll(\"/\", \".\")}`;\n }\n\n if (ref.startsWith(\"$map/\")) {\n const parts = ref.split(\"/\");\n const [, key] = parts;\n if (key === \"item\") {\n return parts.length > 2 ? `_item.${parts.slice(2).join(\".\")}` : \"_item\";\n }\n if (key === \"index\") {\n return \"_index\";\n }\n return `_${key}`;\n }\n\n if (ref.startsWith(\"#/state/\")) {\n const path = ref.slice(\"#/state/\".length);\n return `${s}.${path.replaceAll(\"/\", \".\")}`;\n }\n\n if (ref.startsWith(\"parent#/\")) {\n return `${s}.${ref.slice(\"parent#/\".length)}`;\n }\n if (ref.startsWith(\"window#/\")) {\n return `window.${ref.slice(\"window#/\".length).replaceAll(\"/\", \".\")}`;\n }\n if (ref.startsWith(\"document#/\")) {\n return `document.${ref.slice(\"document#/\".length).replaceAll(\"/\", \".\")}`;\n }\n\n return `${s}.${ref}`;\n}\n\n/** Compile a writable $ref target to its JS equivalent (for LHS of assignment). */\nfunction compileTarget(target: unknown, opts: CompileOpts): string {\n if (typeof target === \"object\" && target !== null && \"$ref\" in target) {\n return compileRef((target as { $ref: string }).$ref, opts);\n }\n return compileOperand(target, opts);\n}\n\n/**\n * Compile an expression node to a JS source string. Returns a statement for mutating ops, a value\n * expression for pure ops.\n *\n * @param {ExpressionNode} node\n * @param {CompileOpts} [opts]\n * @returns {string}\n */\n/**\n * Emit the inline JS for a synthetic blessed helper (see BLESSED_HELPERS), or null for ordinary\n * globals that compile to a plain `window.<path>` call.\n *\n * @param {string} path - The `window#/`-stripped callee path (e.g. \"Intl/formatNumber\")\n * @param {string[]} args - Already-compiled argument expressions\n * @returns {string | null}\n */\nfunction compileHelperCall(path: string, args: string[]): string | null {\n const a = (i: number) => args[i] ?? \"undefined\";\n switch (path) {\n case \"Intl/formatNumber\": {\n return `new Intl.NumberFormat(${a(1)}, ${a(2)}).format(${a(0)})`;\n }\n case \"Intl/formatDate\": {\n return `new Intl.DateTimeFormat(${a(1)}, ${a(2)}).format(new Date(${a(0)}))`;\n }\n case \"Intl/formatRelativeTime\": {\n return `new Intl.RelativeTimeFormat(${a(2)}, ${a(3)}).format(${a(0)}, ${a(1)})`;\n }\n default: {\n return null;\n }\n }\n}\n\nexport function compileExpression(node: ExpressionNode, opts: CompileOpts = {}): string {\n const { operator, target, value, initial } = node;\n\n // ─── Unary ───\n if (UNARY_OPS.has(operator) && !(\"value\" in node)) {\n const operand: string = compileOperand(target, opts);\n if (operator === \"!\") {\n return `!(${operand})`;\n }\n if (operator === \"-\") {\n return `-(${operand})`;\n }\n }\n\n // ─── Call (spec §19.4c) ───\n if (operator === \"call\") {\n const calleeRef = (target as { $ref?: string } | null)?.$ref ?? \"\";\n const args = Array.isArray(value) ? value.map((o: unknown) => compileOperand(o, opts)) : [];\n if (calleeRef.startsWith(\"window#/\")) {\n if (!isBlessedGlobal(calleeRef)) {\n throw new Error(`$expression: \"${calleeRef}\" is not a blessed pure global`);\n }\n const helperJs = compileHelperCall(calleeRef.slice(\"window#/\".length), args);\n if (helperJs) {\n return helperJs;\n }\n return `window.${calleeRef.slice(\"window#/\".length).replaceAll(\"/\", \".\")}(${args.join(\", \")})`;\n }\n if (calleeRef.startsWith(\"#/state/\")) {\n const key = calleeRef.slice(\"#/state/\".length);\n const params = opts.formulaParams?.[key];\n if (params) {\n const named = params\n .map((p, i) => `${JSON.stringify(p)}: ${args[i] ?? \"undefined\"}`)\n .join(\", \");\n return `${formulaFnName(key)}(${opts.statePrefix ?? \"state\"}, { ${named} })`;\n }\n }\n // Fallback: the scope member itself is callable.\n return `${compileRef(calleeRef, opts)}(${args.join(\", \")})`;\n }\n\n // ─── Conditional (pure) ───\n if (CONDITIONAL_OPS.has(operator)) {\n if (operator === \"?:\") {\n const test: string = compileOperand(target, opts);\n const consequent: string = compileOperand(value, opts);\n const alternate: string = compileOperand(initial, opts);\n return `(${test} ? ${consequent} : ${alternate})`;\n }\n // Switch — bind the discriminant's string form once, then chain strict-equality tests.\n const discriminant: string = compileOperand(target, opts);\n const chain = Object.entries(node.cases ?? {})\n .map(([k, v]) => `_d === ${JSON.stringify(k)} ? ${compileOperand(v, opts)} : `)\n .join(\"\");\n const fallback = \"default\" in node ? compileOperand(node.default, opts) : \"undefined\";\n return `((_d) => ${chain}${fallback})(String(${discriminant}))`;\n }\n\n // ─── Binary (pure) ───\n if (BINARY_OPS.has(operator)) {\n const left: string = compileOperand(target, opts);\n const right: string = compileOperand(value, opts);\n return `(${left} ${operator} ${right})`;\n }\n\n // ─── Assignment ───\n if (ASSIGNMENT_OPS.has(operator)) {\n const lhs: string = compileTarget(target, opts);\n const rhs: string = compileOperand(value, opts);\n return `${lhs} ${operator} ${rhs}`;\n }\n\n // ─── Array methods ───\n if (ARRAY_METHOD_OPS.has(operator)) {\n const arr: string = compileTarget(target, opts);\n switch (operator) {\n case \"push\": {\n return `${arr}.push(${compileOperand(value, opts)})`;\n }\n case \"unshift\": {\n return `${arr}.unshift(${compileOperand(value, opts)})`;\n }\n case \"pop\": {\n return `${arr}.pop()`;\n }\n case \"shift\": {\n return `${arr}.shift()`;\n }\n case \"splice\": {\n const args: string = Array.isArray(value)\n ? value.map((o: unknown) => compileOperand(o, opts)).join(\", \")\n : compileOperand(value, opts);\n return `${arr}.splice(${args})`;\n }\n default: {\n break;\n }\n }\n }\n\n // ─── Pure standard-library methods (spec §19.4d) ───\n if (PURE_METHOD_OPS.has(operator)) {\n const receiver: string = compileOperand(target, opts);\n const args: string =\n value === undefined\n ? \"\"\n : Array.isArray(value)\n ? value.map((o: unknown) => compileOperand(o, opts)).join(\", \")\n : compileOperand(value, opts);\n // ?.method?.() matches the interpreter: missing receiver or method yields undefined.\n return `(${receiver})?.${operator}?.(${args})`;\n }\n\n // ─── Aggregates (pure) ───\n if (AGGREGATE_OPS.has(operator)) {\n const arr: string = compileOperand(target, opts);\n const itemExpr: string = compileExpression(value as ExpressionNode, opts);\n if (operator === \"reduce\") {\n const seed: string = compileOperand(initial, opts);\n return `${arr}.reduce((_acc, _item, _index) => ${itemExpr}, ${seed})`;\n }\n if (operator === \"map\") {\n return `${arr}.map((_item, _index) => ${itemExpr})`;\n }\n if (operator === \"filter\") {\n return `${arr}.filter((_item, _index) => ${itemExpr})`;\n }\n }\n\n return \"undefined\";\n}\n\n// ─── Utilities ───────────────────────────────────────────────────────────────\n\n/** Resolve a dotted/slashed path on an object. */\nfunction getPath(obj: unknown, path: string): unknown {\n let current: unknown = obj;\n for (const k of path.split(/[./]/)) {\n current = (current as Record<string, unknown>)?.[k];\n }\n return current;\n}\n\n// ─── Statement-Engine Surface (spec §20) ─────────────────────────────────────\n\n/**\n * Evaluate a bare operand (pointer, literal, or nested node) outside a node position — used by\n * statement execution (spec §20) for `if` tests and `$switch` discriminants.\n */\nexport function evaluateOperand(\n operand: unknown,\n state: JxScope,\n event: Event | null,\n iterCtx?: IterCtx,\n): unknown {\n return resolveOperand(operand, state, event, iterCtx);\n}\n\n/** Compile a bare operand to JS source — the statement compiler's counterpart to evaluateOperand. */\nexport function compileOperandSource(operand: unknown, opts: CompileOpts = {}): string {\n return compileOperand(operand, opts);\n}\n\nexport type { CompileOpts, IterCtx };\n",
|
|
26
|
-
"/// <reference lib=\"dom\" />\n/**\n * Jx Statement Engine (spec §20) — structured function bodies.\n *\n * A Function entry's `body` may be a statement array instead of opaque JS source. This module is\n * the statements counterpart to expression.ts, with the same dual shape: `runStatements`\n * (interpreter) and `compileStatements` (JS emitter), shared by the runtime and every compiler\n * target. Statement kinds reuse web-platform names only: bare expression nodes (§19), the JSON\n * Schema `if`/`then`/`else` triple, `$switch`/`cases` in statement position, and WHATWG's\n * `dispatchEvent` with `CustomEventInit` members.\n */\n\nimport {\n compileExpression,\n compileOperandSource,\n evaluateExpression,\n evaluateOperand,\n} from \"./expression.ts\";\n\nimport type { JxStatement } from \"@jxsuite/schema/types\";\nimport type { CompileOpts, ExpressionNode, IterCtx } from \"./expression.ts\";\nimport type { JxScope } from \"./types.ts\";\n\ninterface RunOpts {\n /** Named-formula-style arguments bound for $args/<name> refs in the body. */\n args?: Record<string, unknown>;\n /** Dispatch target for dispatchEvent statements; defaults to event?.currentTarget. */\n target?: EventTarget | null;\n}\n\nfunction statementKind(statement: JxStatement): \"expression\" | \"if\" | \"switch\" | \"dispatch\" {\n if (\"operator\" in statement) {\n return \"expression\";\n }\n if (\"if\" in statement) {\n return \"if\";\n }\n if (\"$switch\" in statement) {\n return \"switch\";\n }\n return \"dispatch\";\n}\n\n/**\n * Execute a statement list sequentially against the reactive scope. A statement whose value is a\n * thenable is awaited before the next runs (ECMA async/await semantics); purely synchronous bodies\n * complete synchronously before the returned promise settles.\n */\nexport async function runStatements(\n statements: JxStatement[],\n state: JxScope,\n event: Event | null,\n opts: RunOpts = {},\n): Promise<void> {\n const iterCtx: IterCtx | undefined = opts.args ? { args: opts.args } : undefined;\n for (const statement of statements) {\n switch (statementKind(statement)) {\n case \"expression\": {\n const result = evaluateExpression(statement as ExpressionNode, state, event, iterCtx);\n if (result && typeof (result as PromiseLike<unknown>).then === \"function\") {\n await (result as PromiseLike<unknown>);\n }\n break;\n }\n case \"if\": {\n const branch = statement as { if: unknown; then: JxStatement[]; else?: JxStatement[] };\n const taken = evaluateOperand(branch.if, state, event, iterCtx) ? branch.then : branch.else;\n if (Array.isArray(taken)) {\n await runStatements(taken, state, event, opts);\n }\n break;\n }\n case \"switch\": {\n const branch = statement as {\n $switch: unknown;\n cases: Record<string, JxStatement[]>;\n default?: JxStatement[];\n };\n const key = String(evaluateOperand(branch.$switch, state, event, iterCtx));\n const cases = branch.cases ?? {};\n const taken = Object.hasOwn(cases, key) ? cases[key] : branch.default;\n if (Array.isArray(taken)) {\n await runStatements(taken, state, event, opts);\n }\n break;\n }\n case \"dispatch\": {\n const dispatch = statement as {\n dispatchEvent: string;\n detail?: unknown;\n bubbles?: boolean;\n composed?: boolean;\n };\n const target = opts.target ?? event?.currentTarget;\n if (!target) {\n break;\n }\n const init: CustomEventInit = {};\n if (\"detail\" in dispatch) {\n init.detail = evaluateOperand(dispatch.detail, state, event, iterCtx);\n }\n if (dispatch.bubbles !== undefined) {\n init.bubbles = dispatch.bubbles;\n }\n if (dispatch.composed !== undefined) {\n init.composed = dispatch.composed;\n }\n target.dispatchEvent(new CustomEvent(dispatch.dispatchEvent, init));\n break;\n }\n default: {\n break;\n }\n }\n }\n}\n\ninterface StatementCompileOpts extends CompileOpts {\n /** JS expression for the dispatchEvent target; defaults to `(event && event.currentTarget)`. */\n dispatchTarget?: string;\n /** Indentation prefix for emitted lines. */\n indent?: string;\n}\n\n/**\n * Compile a statement list to a JS statement block (no surrounding braces). Mirrors `runStatements`\n * exactly; each statement kind lowers to its genuine ECMAScript form — expression statements,\n * `if`/`else`, `switch` over the discriminant's string form, and `dispatchEvent(new\n * CustomEvent(...))`.\n */\nexport function compileStatements(\n statements: JxStatement[],\n opts: StatementCompileOpts = {},\n): string {\n const indent = opts.indent ?? \"\";\n const lines: string[] = [];\n for (const statement of statements) {\n switch (statementKind(statement)) {\n case \"expression\": {\n lines.push(`${indent}${compileExpression(statement as ExpressionNode, opts)};`);\n break;\n }\n case \"if\": {\n const branch = statement as { if: unknown; then: JxStatement[]; else?: JxStatement[] };\n const test = compileOperandSource(branch.if, opts);\n const inner = { ...opts, indent: `${indent} ` };\n lines.push(`${indent}if (${test}) {`, compileStatements(branch.then ?? [], inner));\n if (branch.else) {\n lines.push(`${indent}} else {`, compileStatements(branch.else, inner));\n }\n lines.push(`${indent}}`);\n break;\n }\n case \"switch\": {\n const branch = statement as {\n $switch: unknown;\n cases: Record<string, JxStatement[]>;\n default?: JxStatement[];\n };\n const disc = compileOperandSource(branch.$switch, opts);\n const inner = { ...opts, indent: `${indent} ` };\n lines.push(`${indent}switch (String(${disc})) {`);\n for (const [key, caseStatements] of Object.entries(branch.cases ?? {})) {\n lines.push(\n `${indent} case ${JSON.stringify(key)}: {`,\n compileStatements(caseStatements, inner),\n `${indent} break;`,\n `${indent} }`,\n );\n }\n if (branch.default) {\n lines.push(\n `${indent} default: {`,\n compileStatements(branch.default, inner),\n `${indent} }`,\n );\n }\n lines.push(`${indent}}`);\n break;\n }\n case \"dispatch\": {\n const dispatch = statement as {\n dispatchEvent: string;\n detail?: unknown;\n bubbles?: boolean;\n composed?: boolean;\n };\n const eventName = opts.eventParam ?? \"event\";\n const target = opts.dispatchTarget ?? `(${eventName} && ${eventName}.currentTarget)`;\n const init: string[] = [];\n if (\"detail\" in dispatch) {\n init.push(`detail: ${compileOperandSource(dispatch.detail, opts)}`);\n }\n if (dispatch.bubbles !== undefined) {\n init.push(`bubbles: ${JSON.stringify(dispatch.bubbles)}`);\n }\n if (dispatch.composed !== undefined) {\n init.push(`composed: ${JSON.stringify(dispatch.composed)}`);\n }\n const initSource = init.length > 0 ? `, { ${init.join(\", \")} }` : \"\";\n lines.push(\n `${indent}${target}?.dispatchEvent(new CustomEvent(${JSON.stringify(dispatch.dispatchEvent)}${initSource}));`,\n );\n break;\n }\n default: {\n break;\n }\n }\n }\n return lines.join(\"\\n\");\n}\n",
|
|
27
|
-
"/// <reference lib=\"dom\" />\n/**\n * Jx — JSON-native reactive web component runtime\n * @version 3.0.0\n * @license MIT\n *\n * Four-step pipeline:\n * 1. resolve — fetch JSON source (or accept raw object)\n * 2. buildScope — state detection + reactive proxy construction\n * 3. render — walk resolved tree, build DOM, wire reactive effects\n * 4. output — append to target\n *\n * @module jx\n */\n\nimport {\n computed,\n effect,\n effectScope,\n isRef,\n onEffectCleanup,\n reactive,\n ref,\n toRaw,\n} from \"@vue/reactivity\";\nimport { evaluateExpression, isMutating } from \"./expression.ts\";\nimport type { DynamicClass, JxEventHandler, JxPath, JxRenderOptions, JxScope } from \"./types.ts\";\nimport {\n bodyReturnsValue,\n hasStructuredBody,\n isExpressionDef,\n isFunctionDef,\n isJsonObject,\n isMappedArray,\n isNamedFormulaDef,\n isPrototypeDef,\n isRef as isRefValue,\n isServerFnDef,\n isTemplateString,\n paramNames,\n} from \"@jxsuite/schema/guards\";\nimport { runStatements } from \"./statements.ts\";\nimport type {\n JxAttributeValue,\n JxClassDef,\n JxDocument,\n JxElement,\n JxFunctionDef,\n JxHeadEntry,\n JxMappedArray,\n JxPrototypeDef,\n JxRef,\n JxServerFnDef,\n JxStyle,\n} from \"@jxsuite/schema/types\";\nimport type { Ref } from \"@vue/reactivity\";\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Mount a Jx document into a DOM container.\n *\n * @example\n * import { Jx } from \"@jxsuite/runtime\";\n * const state = await Jx(\"./counter.json\", document.getElementById(\"app\"));\n *\n * @param {string | JxDocument} source - Path to .json file, URL, or raw document object\n * @param {HTMLElement} [target] Default is `document.body`\n * @param {JxRenderOptions} [options]\n * @returns {Promise<JxScope>} Resolves with the live component scope (state reactive\n * proxy)\n */\n/** The document-schema version this runtime understands (the `/schema/vN` in a hosted `$schema`). */\nexport const SUPPORTED_SCHEMA_VERSION = 1;\nlet _schemaVersionWarned = false;\n\n/**\n * Warn once when a document declares a hosted `$schema` whose version differs from the one this\n * runtime supports. A relative or non-hosted `$schema` (local dev schema paths) is ignored. This is\n * a diagnostic only — there is no document-format migration story yet (see spec §3.2 / §21.4).\n */\nfunction checkSchemaVersion($schema: unknown): void {\n if (_schemaVersionWarned || typeof $schema !== \"string\") {\n return;\n }\n const match = $schema.match(/\\/schema\\/v(\\d+)\\b/);\n if (match && Number(match[1]) !== SUPPORTED_SCHEMA_VERSION) {\n _schemaVersionWarned = true;\n console.warn(\n `Jx: document $schema is version v${match[1]} but this runtime supports ` +\n `v${SUPPORTED_SCHEMA_VERSION}. Behavior may be undefined; there is no format migrator yet.`,\n );\n }\n}\n\nexport async function Jx(\n source: string | JxDocument,\n target: HTMLElement = document.body,\n options?: JxRenderOptions,\n) {\n const base = typeof source === \"string\" ? new URL(source, location.href).href : location.href;\n const doc = await resolve(source);\n checkSchemaVersion(doc.$schema);\n\n // Register custom elements declared in $elements (depth-first)\n if (doc.$elements) {\n await registerElements(doc.$elements, base);\n }\n\n // Inject <head> elements declared in $head (link, meta, script, etc.)\n if (doc.$head) {\n injectHead(doc.$head, base);\n }\n\n if (doc.$media) {\n _rootMedia = doc.$media;\n }\n\n const state = await buildScope(doc, {}, base);\n target.append(renderNode(doc, state, options));\n if (typeof state.onMount === \"function\") {\n (state.onMount as (s: JxScope) => unknown)(state);\n }\n return state;\n}\n\n// ─── Step 1: Resolve ──────────────────────────────────────────────────────────\n\nconst _resolveCache = new Map<string, Promise<JxDocument>>();\n\nexport async function resolve(source: string | JxDocument): Promise<JxDocument> {\n if (typeof source !== \"string\") {\n return source;\n }\n if (_resolveCache.has(source)) {\n return _resolveCache.get(source)!;\n }\n const p = fetch(source).then((res) => {\n if (!res.ok) {\n throw new Error(`Jx: failed to fetch ${source} (${res.status})`);\n }\n // Trust boundary: fetched sources are Jx documents by contract.\n return res.json() as Promise<JxDocument>;\n });\n _resolveCache.set(source, p);\n return p;\n}\n\n// ─── Step 2: Build scope ──────────────────────────────────────────────────────\n\n/** JSON Schema keywords used to identify pure type definitions (Shape 2b). */\nconst SCHEMA_KEYWORDS = new Set([\n \"type\",\n \"properties\",\n \"items\",\n \"enum\",\n \"minimum\",\n \"maximum\",\n \"minLength\",\n \"maxLength\",\n \"pattern\",\n \"required\",\n \"examples\",\n]);\n\n/** /** @type {{ skip: boolean }} */\nconst _serverFnConfig = { skip: false };\n/** Set to true to suppress timing: \"server\" resolution (used by Studio edit mode). */\nexport function setSkipServerFunctions(v: boolean) {\n _serverFnConfig.skip = v;\n}\n\n/** @type {{ skip: boolean }} */\nconst _autoRequestConfig = { skip: false };\n/**\n * Set to true to suppress AUTOMATIC `$prototype: \"Request\"` fetches — the sibling of\n * {@link setSkipServerFunctions}, and used by Studio for the same reason.\n *\n * `buildScope` re-resolves every `state` entry on each full canvas render, so an auto-request\n * re-issued its HTTP call every time the canvas rebuilt. In edit/design mode that meant authoring\n * actions — a signal edit, or pressing Enter inside component-wrapped content, both of which force\n * a full render — fired network requests. Live data belongs to preview and to the deployed site.\n *\n * Only non-`manual` requests are gated: a `manual` one fires from an event handler, and edit mode\n * strips handlers before rendering. The returned ref is unchanged either way — it simply stays at\n * its initial `null`, which is the same state bindings observe before any fetch resolves.\n */\nexport function setSkipAutoRequests(v: boolean) {\n _autoRequestConfig.skip = v;\n}\n\n// ─── Dev-proxy auth token (Studio cross-origin canvas) ────────────────────────\n// The Studio canvas iframe is served from a token-gated loopback origin (createProjectServer): its\n// POST /__jx_resolve__ + /__jx_server__ routes 403 without ?token=<rpcToken>. The iframe boot reads\n// The token from its URL and calls setResolveToken so these dev-proxy fetches authenticate. Unset by\n// Default, leaving production + same-origin dev untouched (bare path, no query appended).\nlet _resolveToken: string | null = null;\nexport function setResolveToken(token: string | null) {\n _resolveToken = token || null;\n}\n/** Append the dev-proxy auth token to a privileged resolve path when one is configured. */\nfunction resolveProxyPath(path: string): string {\n return _resolveToken ? `${path}?token=${encodeURIComponent(_resolveToken)}` : path;\n}\n\n/** @deprecated No longer needed — ContentCollection/ContentEntry resolve via generic class path */\nexport function setSkipContentResolution(_v: boolean) {\n // No-op retained for API compatibility\n}\n\n/**\n * Observe runtime-created reactive values: runs `fn` immediately inside a reactive effect and\n * re-runs it whenever a tracked value changes; returns a disposer. Dep tracking in @vue/reactivity\n * is per module INSTANCE, so an effect created from another copy of the package (e.g. the studio's\n * own pin) can never track a ref/reactive created here — consumers that want to observe\n * runtime-resolved scope values (the Studio canvas iframe's dataScope re-post) must use this.\n *\n * @param {() => void} fn - Read the reactive values to observe inside this callback.\n * @returns {() => void} Disposer — stops the effect and its scope.\n */\nexport function observeScope(fn: () => void): () => void {\n const scope = effectScope(true);\n scope.run(() => {\n effect(fn);\n });\n return () => scope.stop();\n}\n\n/**\n * Run `fn` inside a detached reactive scope of THIS module's reactivity instance, returning its\n * result plus a disposer that stops every effect `fn` created. Callers that render via\n * {@link renderNode} and later tear the render down (the Studio canvas full render and its surgical\n * subtree re-renders) MUST use this instead of their own effectScope: scope collection is per\n * vue-reactivity module instance, so a scope from another copy of the package collects NOTHING and\n * its stop() silently leaks every binding effect of the superseded render.\n *\n * @param {() => T} fn - Work that may create reactive effects (typically a renderNode call).\n * @returns {{ result: T; stop: () => void }} The callback result and the scope disposer.\n */\nexport function runScoped<T>(fn: () => T): { result: T; stop: () => void } {\n const scope = effectScope(true);\n try {\n const result = scope.run(fn) as T;\n return { result, stop: () => scope.stop() };\n } catch (error) {\n // A throwing fn would otherwise leak the effects it created before failing.\n scope.stop();\n throw error;\n }\n}\n\n/**\n * Studio-canvas viewport-unit transpose. The canvas iframe is sized to its document's height, so\n * any viewport unit (`vh`/`vw`/`vmin`/`vmax`/`svh`/…) — which resolves against the iframe ELEMENT —\n * would feed back into an ever-growing height. When this is on, the runtime transposes them to\n * CONTAINER units (`cqh`/`cqw`/…) that resolve against the canvas's fixed-size query container (see\n * `canvas.html`): a predictable, feedback-free stand-in for the viewport. Off (the default) leaves\n * CSS untouched for real production rendering.\n */\nlet _canvasViewportTranspose = false;\nexport function setCanvasViewportTranspose(on: boolean) {\n _canvasViewportTranspose = on;\n}\n\nconst VIEWPORT_UNIT_RE = /(-?\\d*\\.?\\d+)(?:s|l|d)?v(h|w|min|max|i|b)\\b/gi;\nconst VIEWPORT_UNIT_MAP: Record<string, string> = {\n b: \"cqb\",\n h: \"cqh\",\n i: \"cqi\",\n max: \"cqmax\",\n min: \"cqmin\",\n w: \"cqw\",\n};\n\n/**\n * Transpose CSS viewport units → container-query units in a value string, but only when the\n * studio-canvas flag is set (otherwise the value is returned untouched). `100vh` → `100cqh`,\n * `50svw` → `50cqw`, `10vmin` → `10cqmin`, etc.\n */\nexport function transposeCanvasUnits(value: string): string {\n if (!_canvasViewportTranspose || !value.includes(\"v\")) {\n return value;\n }\n return value.replace(\n VIEWPORT_UNIT_RE,\n (_m, num: string, dim: string) => `${num}${VIEWPORT_UNIT_MAP[dim.toLowerCase()] ?? `cq${dim}`}`,\n );\n}\n\n/**\n * Studio-canvas anchor de-linking. In the editor canvas a rendered `<a href>` would navigate the\n * iframe when clicked, fighting element selection. When this is on, the runtime stamps the value on\n * `data-jx-href` instead of `href` so the anchor is inert (selectable, not a live link) while the\n * original target stays recoverable for richer link handling later. Off (the default) leaves\n * production rendering untouched; the studio sets it for design/edit (not preview — see\n * iframe-render).\n */\nlet _canvasDelinkAnchors = false;\nexport function setCanvasDelinkAnchors(on: boolean) {\n _canvasDelinkAnchors = on;\n}\n\n/** The attribute name to stamp `key` on `el` under — `href` → `data-jx-href` on de-linked anchors. */\nfunction canvasAttrName(el: HTMLElement, key: string): string {\n if (_canvasDelinkAnchors && key === \"href\" && (el.tagName === \"A\" || el.tagName === \"AREA\")) {\n return \"data-jx-href\";\n }\n return key;\n}\n\n/**\n * Studio-canvas prop-binding markers. When on, `bindProperty` stamps `data-jx-bound-prop=\"<key>\"`\n * on elements whose `textContent` is an invertible single-key state binding — the pure template\n * `\"${state.key}\"` or `{ \"$ref\": \"#/state/key\" }`. The studio canvas uses the marker to offer\n * inline editing of component-instance prop values; the rendered text must BE the prop value\n * verbatim, so mixed templates and deep paths are never stamped. Off (the default) leaves\n * production rendering untouched; the studio sets it for design/edit (not preview — see\n * iframe-render).\n */\nlet _stampPropBindings = false;\nexport function setStampPropBindings(on: boolean) {\n _stampPropBindings = on;\n}\n\n/** The single invertible template form: the whole string is exactly one `${state.key}` access. */\nconst PURE_STATE_TEMPLATE = /^\\s*\\$\\{\\s*state\\.(\\w+)\\s*\\}\\s*$/;\n\n/** The state key of an invertible `textContent` binding, or null (mixed template, deep path). */\nfunction boundPropKey(key: string, val: unknown, state: JxScope): string | null {\n if (!_stampPropBindings || key !== \"textContent\") {\n return null;\n }\n let sub: string | null = null;\n if (isRefObj(val)) {\n if (!val.$ref.startsWith(\"#/state/\")) {\n return null;\n }\n const rest = val.$ref.slice(\"#/state/\".length);\n sub = rest && !rest.includes(\"/\") ? rest : null;\n } else if (typeof val === \"string\") {\n sub = PURE_STATE_TEMPLATE.exec(val)?.[1] ?? null;\n }\n if (!sub) {\n return null;\n }\n // Only plain writable data entries are per-instance props. Computed/signal entries live as refs\n // In the raw scope (auto-unwrapped by the reactive proxy), and function/object entries (handlers,\n // $prototype instances) are not prop-overridable either — an instance $props write against any of\n // Them would clobber the definition's behavior, so their bindings are never marked editable.\n const stored = (toRaw(state) as Record<string, unknown>)[sub];\n if (isRef(stored) || typeof stored === \"function\") {\n return null;\n }\n if (typeof stored === \"object\" && stored !== null) {\n return null;\n }\n return sub;\n}\n\n/**\n * Build the reactive scope (state) from the document using the five-shape detection algorithm.\n *\n * @param {JxDocument} doc\n * @param {JxScope} [parentScope] Default is `{}`\n * @param {string} [base] Base URL for resolving $src imports. Default is `location.href`\n * @returns {Promise<JxScope>} Reactive proxy (state)\n */\nexport async function buildScope(\n doc: JxDocument,\n parentScope: JxScope = {},\n base: string = location.href,\n) {\n const raw: JxScope = {};\n\n // Merge parent scope properties\n for (const [key, val] of Object.entries(parentScope)) {\n raw[key] = val;\n }\n\n const defs = doc.state ?? {};\n\n // Pass 0: resolve bare $prototype names via import map\n const imports = doc.imports ?? {};\n for (const [, def] of Object.entries(defs)) {\n if (isPrototypeDef(def) && !def.$src) {\n const mapped = imports[def.$prototype];\n if (mapped) {\n if (!mapped.endsWith(\".class.json\")) {\n console.warn(\n `Jx: import \"${def.$prototype}\" must map to a .class.json path, got \"${mapped}\"`,\n );\n continue;\n }\n def.$src = mapped;\n }\n }\n }\n\n // First pass: collect naked values, expanded defaults, plain objects\n for (const [key, def] of Object.entries(defs)) {\n // 1. String value\n if (typeof def === \"string\") {\n if (!def.includes(\"${\")) {\n raw[key] = def;\n } // Shape 1: naked string\n continue; // Template strings handled in second pass\n }\n\n // 2. Number, boolean, null\n if (typeof def === \"number\" || typeof def === \"boolean\" || def === null) {\n raw[key] = def;\n continue;\n }\n\n // 3. Array\n if (Array.isArray(def)) {\n raw[key] = def;\n continue;\n }\n\n // 4. Object\n if (typeof def === \"object\") {\n if (def.$prototype) {\n continue;\n } // Handled in later passes\n if (isExpressionDef(def)) {\n continue;\n } // Handled in pass 2.5\n if (isServerFnDef(def)) {\n continue;\n } // Handled in fifth pass\n if (\"default\" in def) {\n raw[key] = def.default;\n continue;\n } // Shape 2: expanded signal\n if (hasSchemaKeywords(def)) {\n continue;\n } // Shape 2b: pure type def\n raw[key] = def; // Shape 1: plain object\n }\n }\n\n // Wrap in Vue reactive proxy — deep reactivity from this point on\n const state = reactive(raw);\n\n // Second pass: template strings → computed\n for (const [key, def] of Object.entries(defs)) {\n if (typeof def === \"string\" && def.includes(\"${\")) {\n state[key] = computed(() => evaluateTemplate(def, state));\n }\n }\n\n // Pass 2.5: $expression entries (Shape 5)\n for (const [key, def] of Object.entries(defs)) {\n if (isExpressionDef(def)) {\n const node = def.$expression;\n if (isNamedFormulaDef(def)) {\n // A named formula: callable with positional args mapped onto its declared parameters.\n const params = def.parameters as (string | { name?: string; default?: unknown })[];\n state[key] = (...argValues: unknown[]) => {\n const args: Record<string, unknown> = {};\n for (const [i, p] of params.entries()) {\n const name = typeof p === \"string\" ? p : (p?.name ?? \"\");\n if (!name) {\n continue;\n }\n args[name] =\n argValues[i] === undefined && typeof p === \"object\" && p !== null && \"default\" in p\n ? p.default\n : argValues[i];\n }\n return evaluateExpression(node, state, null, { args });\n };\n } else if (isMutating(node.operator)) {\n const handler: JxEventHandler = (s, event) => evaluateExpression(node, s, event);\n state[key] = handler;\n } else {\n state[key] = computed(() => evaluateExpression(node, state, null));\n }\n }\n }\n\n // Third pass: $prototype: \"Function\" entries\n for (const [key, def] of Object.entries(defs)) {\n if (hasStructuredBody(def)) {\n // Structured body (spec §20): with parameters → a callable mapping positional args onto\n // $args names (invoked via the call operator); without → an event handler.\n const { body } = def;\n if (Array.isArray(def.parameters) && def.parameters.length > 0) {\n const params = def.parameters as (string | { name?: string; default?: unknown })[];\n state[key] = (...argValues: unknown[]) => {\n const args: Record<string, unknown> = {};\n for (const [i, p] of params.entries()) {\n const name = typeof p === \"string\" ? p : (p?.name ?? \"\");\n if (!name) {\n continue;\n }\n args[name] =\n argValues[i] === undefined && typeof p === \"object\" && p !== null && \"default\" in p\n ? p.default\n : argValues[i];\n }\n return runStatements(body, state, null, { args });\n };\n } else {\n const handler: JxEventHandler = (s, event) => {\n void runStatements(body, s, event ?? null);\n };\n state[key] = handler;\n }\n } else if (isFunctionDef(def)) {\n state[key] = await resolveFunction(def, state, key, base);\n }\n }\n\n // Fourth pass: other $prototype entries (Request, Set, Map, etc.)\n for (const [key, def] of Object.entries(defs)) {\n if (isPrototypeDef(def)) {\n state[key] = await resolvePrototype(def, state, key, base);\n }\n }\n\n // Fifth pass: timing: \"server\" entries (dev mode — execute client-side, boundary unenforced)\n if (!_serverFnConfig.skip) {\n for (const [key, def] of Object.entries(defs)) {\n if (isServerFnDef(def)) {\n state[key] = await resolveServerFunction(def, state, key, base);\n }\n }\n }\n\n if (doc.$media) {\n state[\"$media\"] = doc.$media;\n } else if (!state[\"$media\"] && Object.keys(_rootMedia).length > 0) {\n state[\"$media\"] = _rootMedia;\n }\n\n return state;\n}\n\n/**\n * Check whether an object contains any JSON Schema keywords. Used to discriminate Shape 2b (pure\n * type definition) from Shape 1 (naked object).\n *\n * @param {JxScope} obj\n * @returns {boolean}\n */\nfunction hasSchemaKeywords(obj: object) {\n for (const k of Object.keys(obj)) {\n if (SCHEMA_KEYWORDS.has(k)) {\n return true;\n }\n }\n return false;\n}\nexport { hasSchemaKeywords };\n\n/**\n * Evaluate a template string in the context of state and optional $map. Templates use\n * `state.varName` and `$map.item` syntax.\n *\n * @param {string} str\n * @param {JxScope} state\n * @returns {string}\n */\nfunction evaluateTemplate(str: string, state: JxScope): string {\n const $map = state?.$map as { item?: unknown; index?: number } | undefined;\n const fn = new Function(\"state\", \"$map\", \"item\", \"index\", `return \\`${str}\\``) as (\n state: JxScope,\n $map: unknown,\n item: unknown,\n index: number | undefined,\n ) => string;\n return fn(state, $map, $map?.item, $map?.index);\n}\n\n// ─── Step 2b: Function resolution (Shape 4) ─────────────────────────────────\n\n/** Shape of a dynamically imported module: named exports plus an optional default. */\ntype ImportedModule = Record<string, unknown> & { default?: Record<string, unknown> };\n\n/** Minimal contract an externally-imported resolver class may implement. */\ninterface ExternalClassInstance {\n value?: unknown;\n resolve?: () => unknown;\n subscribe?: (cb: (newVal: unknown) => void) => void;\n}\n\n/** Module cache for $src imports (shared with external class resolution). */\nconst _moduleCache = new Map<string, ImportedModule>();\n\n/**\n * Resolve a $prototype: \"Function\" entry into a function or computed.\n *\n * Functions receive state as their first parameter at call time. Functions with a return statement\n * in their body are wrapped in computed() for reactive evaluation.\n *\n * @param {JxFunctionDef} def - State entry with $prototype: \"Function\"\n * @param {JxScope} state - Reactive scope proxy\n * @param {string} key - Def key name\n * @param {string} [base] - Base URL for resolving $src imports\n * @returns {Promise<unknown>}\n */\nasync function resolveFunction(def: JxFunctionDef, state: JxScope, key: string, base?: string) {\n if (def.body && def.$src) {\n throw new Error(`Jx: '${key}' declares both body and $src — these are mutually exclusive`);\n }\n if (!def.body && !def.$src) {\n const params = resolveParamNames(def);\n const noop = new Function(...params, \"\");\n Object.defineProperty(noop, \"name\", {\n configurable: true,\n value: def.name ?? key,\n });\n return noop;\n }\n\n let fn: ((...args: unknown[]) => unknown) | undefined;\n\n if (typeof def.body === \"string\") {\n const params = resolveParamNames(def);\n fn = new Function(...params, def.body) as (...args: unknown[]) => unknown;\n Object.defineProperty(fn, \"name\", {\n configurable: true,\n value: def.name ?? key,\n });\n } else {\n // $src: dynamic import (the body/$src dichotomy was validated above)\n const src = def.$src;\n if (!src) {\n throw new Error(`Jx: '${key}' has neither body nor $src`);\n }\n const exportName = def.$export ?? key;\n let mod: ImportedModule;\n if (_moduleCache.has(src)) {\n mod = _moduleCache.get(src)!;\n } else {\n if (base) {\n const resolvedSrc = new URL(src, base).href;\n try {\n mod = (await import(resolvedSrc)) as ImportedModule;\n } catch {\n mod = (await import(src)) as ImportedModule;\n }\n } else {\n mod = (await import(src)) as ImportedModule;\n }\n _moduleCache.set(src, mod);\n }\n const candidate = mod[exportName] ?? mod.default?.[exportName];\n if (typeof candidate !== \"function\") {\n throw new TypeError(`Jx: export \"${exportName}\" not found or not a function in \"${src}\"`);\n }\n fn = candidate as (...args: unknown[]) => unknown;\n }\n\n // Detect computed: body contains a return statement, or $src function introspection.\n // Functions with parameters (event handlers, callbacks) are never computed.\n const hasParams = (def.parameters ?? def.arguments ?? []).length > 0;\n let isComputed = false;\n if (!hasParams) {\n if (typeof def.body === \"string\") {\n isComputed = bodyReturnsValue(def.body);\n } else if (fn) {\n isComputed = fn.length <= 1 && bodyReturnsValue(fn.toString());\n }\n }\n if (isComputed) {\n return computed(() => fn(state));\n }\n\n return fn;\n}\n\n// ─── Step 3: Render ───────────────────────────────────────────────────────────\n\n/**\n * Extract parameter names from a function definition. Supports both legacy \"arguments\" (string\n * array) and CEM-compatible \"parameters\" (object array). Always ensures \"state\" is the first\n * parameter.\n *\n * @param {JxFunctionDef | JxPrototypeDef} def\n * @returns {string[]}\n */\nfunction resolveParamNames(def: JxFunctionDef | JxPrototypeDef) {\n const names = def.parameters ? paramNames(def.parameters) : (def.arguments ?? []);\n return names.length > 0 && names[0] === \"state\" ? names : [\"state\", ...names];\n}\n\n/**\n * Reserved Jx keys — never set as DOM properties.\n *\n * @type {Set<string>}\n */\nexport const RESERVED_KEYS = new Set([\n \"$schema\",\n \"$id\",\n \"$defs\",\n \"state\",\n \"$ref\",\n \"$props\",\n \"$elements\",\n \"$title\",\n \"$description\",\n \"$switch\",\n \"$prototype\",\n \"$src\",\n \"$export\",\n \"$media\",\n \"$map\",\n \"timing\",\n \"default\",\n \"description\",\n \"body\",\n \"parameters\",\n \"arguments\",\n \"name\",\n \"tagName\",\n \"children\",\n \"style\",\n \"attributes\",\n \"items\",\n \"map\",\n \"filter\",\n \"sort\",\n \"cases\",\n \"observedAttributes\",\n]);\n\n/**\n * Recursively render a Jx element definition into a DOM element.\n *\n * @param {JxElement | string | number | boolean} def\n * @param {JxScope} state - Reactive scope proxy (or child scope via Object.create)\n * @param {JxRenderOptions} [options]\n * @returns {HTMLElement | Text}\n */\n/** Refs already warned about, so the §13 diagnostic fires once per distinct target. */\nconst warnedRefChildren = new Set<string>();\n\nexport function renderNode(\n def: JxElement | string | number | boolean,\n state: JxScope,\n options?: JxRenderOptions,\n): HTMLElement | Text {\n const path = options?._path ?? [];\n\n // Text node children: bare strings/numbers/booleans produce DOM Text nodes\n if (typeof def === \"string\" || typeof def === \"number\" || typeof def === \"boolean\") {\n const textNode = document.createTextNode(String(def));\n if (typeof def === \"string\" && isTemplateString(def)) {\n effect(() => {\n textNode.textContent = evaluateTemplate(def, state);\n });\n }\n return textNode;\n }\n\n // Extend scope with any $-prefixed local bindings declared on this node\n let localState: JxScope = state;\n for (const [key, val] of Object.entries(def)) {\n if (key.startsWith(\"$\") && !RESERVED_KEYS.has(key)) {\n if (localState === state) {\n localState = Object.create(state) as JxScope;\n }\n localState[key] = isRefObj(val) ? resolveRef(val.$ref, state) : val;\n }\n }\n\n /*\n * §13 diagnostic: a node-level external `$ref` (the withdrawn component-instance syntax) has no\n * tagName and silently renders an empty <div>. Warn once per target instead of failing silently —\n * the supported mechanism is $elements + a custom-element tag (see spec §13).\n */\n if (\"$ref\" in def && !def.tagName) {\n const refTarget = String((def as { $ref?: unknown }).$ref ?? \"\");\n if (!warnedRefChildren.has(refTarget)) {\n warnedRefChildren.add(refTarget);\n console.warn(\n `Jx: a $ref child (\"${refTarget}\") is not a supported component instance; register the ` +\n `component in $elements and use its custom-element tag instead (spec §13).`,\n );\n }\n }\n\n // Custom element with $props: set JS properties on the element instance\n const tagName = def.tagName ?? \"div\";\n const isCustomEl = tagName.includes(\"-\") && customElements.get(tagName);\n\n if (def.$props && isCustomEl) {\n return renderCustomElementWithProps(def, localState, options, path);\n }\n\n if (def.$props) {\n // A hyphenated tag carrying $props is a component instance whose definition has not finished\n // Registering yet (async defineElement — e.g. the Studio desktop canvas, where the component\n // Fetch can land after this node renders). Render via the property-first path anyway: it sets\n // The instance props as JS properties on the bare element, which the eventual upgrade's\n // ConnectedCallback reads back off `this` (see the def.state merge below), so the instance's\n // Props win. The old branch stripped the props here, so a late upgrade painted the component's\n // State DEFAULTS instead (\"0\"/\"DESCRIPTION\" for every instance). A non-custom tag can never\n // Upgrade, so it keeps the historical mergeProps-into-scope behavior.\n if (tagName.includes(\"-\")) {\n return renderCustomElementWithProps(def, localState, options, path);\n }\n const { $props: _$props, ...rest } = def;\n return renderNode(rest, mergeProps(def, localState), options);\n }\n if (def.$switch) {\n return renderSwitch(def, localState, options);\n }\n\n const el = document.createElement(tagName);\n\n if (options?.onNodeCreated) {\n options.onNodeCreated(el, path, def, localState);\n }\n\n applyProperties(el, def, localState);\n applyStyle(\n el,\n def.style ?? {},\n (localState[\"$media\"] as Record<string, string>) ?? {},\n localState,\n );\n applyAttributes(el, def.attributes ?? {}, localState);\n\n const kids = def.children;\n if (isMappedArray(kids)) {\n // Legacy whole-children repeater: the items render directly into `el` (which keeps its own\n // TagName, e.g. <ul>), with no extra wrapper element.\n const arrOpts = options ? { ...options, _path: [...path, \"children\"] } : undefined;\n renderMappedArrayInto(el, kids, localState, arrOpts);\n } else if (Array.isArray(kids)) {\n for (let i = 0; i < kids.length; i++) {\n const child = kids[i]!;\n const childOpts = options ? { ...options, _path: [...path, \"children\", i] } : undefined;\n if (isMappedArray(child)) {\n // Array pseudo-element among siblings: expand inline, no wrapper.\n renderMappedArrayInto(el, child, localState, childOpts);\n } else {\n el.append(renderNode(child, localState, childOpts));\n }\n }\n }\n\n return el;\n}\n\n// ─── Template string utilities ────────────────────────────────────────────────\n\n/**\n * Check if a value is a template string (contains ${}).\n *\n * @param {unknown} val\n * @returns {boolean}\n */\n// ─── Property / style / attribute application ─────────────────────────────────\n\n/**\n * @param {HTMLElement} el\n * @param {JxElement} def\n * @param {JxScope} state\n */\nfunction applyProperties(el: HTMLElement, def: JxElement, state: JxScope) {\n for (const [key, val] of Object.entries(def)) {\n if (RESERVED_KEYS.has(key)) {\n continue;\n }\n if (key.startsWith(\"$\")) {\n continue;\n } // Scope bindings — handled in renderNode\n\n if (key.startsWith(\"on\")) {\n // Event handler: $ref to a function\n if (isRefObj(val)) {\n const handler = resolveRef(val.$ref, state);\n if (typeof handler === \"function\") {\n const scope = state;\n const handlerFn = handler as (s: JxScope, e: Event) => unknown;\n el.addEventListener(key.slice(2), (e) => handlerFn(scope, e));\n }\n continue;\n }\n // Event handler: inline $prototype: \"Function\" with a structured body (spec §20)\n if (hasStructuredBody(val)) {\n const { body } = val;\n const scope = state;\n el.addEventListener(key.slice(2), (e) => {\n void runStatements(body, scope, e);\n });\n continue;\n }\n // Event handler: inline $prototype: \"Function\"\n if (isFunctionDef(val) && typeof val.body === \"string\") {\n const params = resolveParamNames(val);\n const fn = new Function(...params, val.body) as (s: JxScope, e: Event) => unknown;\n const scope = state;\n el.addEventListener(key.slice(2), (e) => fn(scope, e));\n continue;\n }\n // Event handler: inline $expression\n if (isExpressionDef(val)) {\n const node = val.$expression;\n const scope = state;\n el.addEventListener(key.slice(2), (e) => evaluateExpression(node, scope, e));\n continue;\n }\n }\n\n bindProperty(el, key, val, state);\n }\n}\n\n/**\n * @param {HTMLElement} el\n * @param {string} key\n * @param {unknown} val\n * @param {JxScope} state\n */\nfunction bindProperty(el: HTMLElement, key: string, val: unknown, state: JxScope) {\n const target = el as unknown as Record<string, unknown>;\n const boundProp = boundPropKey(key, val, state);\n if (boundProp) {\n el.dataset.jxBoundProp = boundProp;\n }\n if (isRefObj(val)) {\n const refVal = val as { $ref: string };\n if (key === \"id\") {\n target[key] = resolveRef(refVal.$ref, state) as string;\n return;\n }\n effect(() => {\n target[key] = resolveRef(refVal.$ref, state);\n });\n return;\n }\n\n // Universal ${} reactivity — template strings in element properties\n if (isTemplateString(val)) {\n effect(() => {\n target[key] = evaluateTemplate(val as string, state);\n });\n return;\n }\n\n target[key] = val;\n}\n\n/**\n * Apply inline styles and emit a scoped <style> block for nested CSS selectors and @custom-media\n * breakpoint rules.\n *\n * @param {HTMLElement} el\n * @param {JxStyle} styleDef\n * @param {Record<string, string>} [mediaQueries] Named breakpoints from root $media. Default is\n * `{}`\n * @param {JxScope} [state] Component scope for template string evaluation. Default is `{}`\n */\nexport function applyStyle(\n el: HTMLElement,\n styleDef: JxStyle,\n mediaQueries: Record<string, string> = {},\n state: JxScope = {},\n) {\n const nested: Record<string, JxStyle> = {};\n const media: Record<string, JxStyle> = {};\n const baseDecls: Record<string, string> = {};\n\n // Collect properties overridden by media queries so we can avoid inline styles for them\n const mediaOverriddenProps = new Set<string>();\n for (const [prop, val] of Object.entries(styleDef)) {\n if (prop.startsWith(\"@\") && val && typeof val === \"object\") {\n for (const k of Object.keys(val)) {\n if (\n !k.startsWith(\":\") &&\n !k.startsWith(\".\") &&\n !k.startsWith(\"&\") &&\n !k.startsWith(\"[\") &&\n !k.startsWith(\"@\")\n ) {\n mediaOverriddenProps.add(k);\n }\n }\n }\n }\n\n for (const [prop, val] of Object.entries(styleDef)) {\n if (val !== null && typeof val === \"object\" && !Array.isArray(val)) {\n if (prop.startsWith(\"@\")) {\n media[prop] = val;\n } else {\n nested[prop] = val;\n }\n continue;\n }\n if (prop.startsWith(\"@\") || isNestedSelector(prop)) {\n // Scalar under a selector/media key — invalid style shape, drop it.\n continue;\n }\n if (val === undefined) {\n continue;\n }\n const scalar = String(val);\n if (prop.startsWith(\"--\")) {\n if (isTemplateString(val)) {\n effect(() => {\n el.style.setProperty(prop, transposeCanvasUnits(evaluateTemplate(val, state)));\n });\n } else {\n el.style.setProperty(prop, transposeCanvasUnits(scalar));\n }\n } else if (isTemplateString(val)) {\n effect(() => {\n (el.style as unknown as Record<string, string>)[prop] = transposeCanvasUnits(\n evaluateTemplate(val, state),\n );\n });\n } else if (mediaOverriddenProps.has(prop)) {\n // Goes through toCSSText (which transposes) — don't double-transpose here.\n baseDecls[prop] = scalar;\n } else {\n (el.style as unknown as Record<string, string>)[prop] = transposeCanvasUnits(scalar);\n }\n }\n\n const hasNested = Object.keys(nested).length > 0;\n const hasMedia = Object.keys(media).length > 0;\n const hasBaseDecls = Object.keys(baseDecls).length > 0;\n if (!hasNested && !hasMedia && !hasBaseDecls) {\n return;\n }\n\n const uid = `jx-${Math.random().toString(36).slice(2, 7)}`;\n el.dataset.jx = uid;\n\n let css = \"\";\n const baseCSS = toCSSText(baseDecls);\n if (baseCSS) {\n css += `[data-jx=\"${uid}\"] { ${baseCSS} }\\n`;\n }\n\n function emitNested(scope: string, rules: JxStyle) {\n const props = toCSSText(rules);\n if (props) {\n css += `${scope} { ${props} }\\n`;\n }\n for (const [sel, sub] of Object.entries(rules)) {\n if (sub === null || typeof sub !== \"object\" || Array.isArray(sub)) {\n continue;\n }\n if (sel.startsWith(\"@\")) {\n continue;\n }\n const resolved = sel.startsWith(\"&\")\n ? sel.replace(\"&\", scope)\n : sel.startsWith(\"[\")\n ? `${scope}${sel}`\n : sel.startsWith(\":\") || sel.startsWith(\".\")\n ? `${scope}${sel}`\n : `${scope} ${sel}`;\n emitNested(resolved, sub);\n }\n }\n\n for (const [sel, rules] of Object.entries(nested)) {\n const resolved = sel.startsWith(\"&\")\n ? sel.replace(\"&\", `[data-jx=\"${uid}\"]`)\n : sel.startsWith(\"[\")\n ? `[data-jx=\"${uid}\"]${sel}`\n : sel.startsWith(\":\") || sel.startsWith(\".\")\n ? `[data-jx=\"${uid}\"]${sel}`\n : `[data-jx=\"${uid}\"] ${sel}`;\n emitNested(resolved, rules);\n }\n\n function emitMediaNested(atRule: string, parentSel: string, obj: JxStyle) {\n for (const [sel, sub] of Object.entries(obj)) {\n if (sub === null || typeof sub !== \"object\" || Array.isArray(sub)) {\n continue;\n }\n if (sel.startsWith(\"@\")) {\n continue;\n }\n const resolved = sel.startsWith(\"&\")\n ? sel.replace(\"&\", parentSel)\n : sel.startsWith(\"[\")\n ? `${parentSel}${sel}`\n : sel.startsWith(\":\") || sel.startsWith(\".\")\n ? `${parentSel}${sel}`\n : `${parentSel} ${sel}`;\n const props = toCSSText(sub);\n if (props) {\n css += `${atRule} { ${resolved} { ${props} } }\\n`;\n }\n emitMediaNested(atRule, resolved, sub);\n }\n }\n\n for (const [key, rules] of Object.entries(media)) {\n if (key === \"@--\") {\n continue;\n } // Base canvas width, not a real media query\n const query = key.startsWith(\"@--\")\n ? (mediaQueries[key.slice(1)] ?? key.slice(1))\n : key.startsWith(\"@(\")\n ? key.slice(1)\n : null;\n const atRule = query === null ? key : `@media ${query}`;\n const scope = `[data-jx=\"${uid}\"]`;\n const scheme = query === null ? null : pureSchemeOf(query);\n if (scheme) {\n // Dual-emit scheme rules: a media-guarded copy for auto plus a forced-attribute copy.\n // The forced root attribute wins over the OS preference.\n const { auto, forced } = schemeSelectors(scope, scheme);\n css += `${atRule} { ${auto} { ${toCSSText(rules)} } }\\n`;\n emitMediaNested(atRule, auto, rules);\n emitNested(forced, rules);\n } else {\n css += `${atRule} { ${scope} { ${toCSSText(rules)} } }\\n`;\n emitMediaNested(atRule, scope, rules);\n }\n }\n\n const tag = document.createElement(\"style\");\n tag.textContent = css;\n tag.dataset.jxOwner = uid;\n document.head.append(tag);\n elementStyleTags.set(el, tag);\n}\n\n/**\n * Scoped <style> tags emitted per element by applyStyle (latest wins). Lets callers replace an\n * element's emitted styles instead of accumulating orphaned tags.\n */\nexport const elementStyleTags = new WeakMap<HTMLElement, HTMLStyleElement>();\n\n/**\n * Re-apply an element's style definition in place: removes the previously emitted scoped <style>\n * tag (if any), clears inline styles, and applies the new definition.\n *\n * @param {HTMLElement} el\n * @param {JxStyle | undefined} styleDef\n * @param {Record<string, string>} [mediaQueries]\n * @param {JxScope} [state]\n */\nexport function reapplyStyle(\n el: HTMLElement,\n styleDef: JxStyle | undefined,\n mediaQueries: Record<string, string> = {},\n state: JxScope = {},\n) {\n const prev = elementStyleTags.get(el);\n if (prev) {\n prev.remove();\n elementStyleTags.delete(el);\n }\n el.style.cssText = \"\";\n delete el.dataset.jx;\n applyStyle(el, styleDef ?? {}, mediaQueries, state);\n}\n\n/**\n * @param {HTMLElement} el\n * @param {Record<string, import(\"@jxsuite/schema/types\").JxAttributeValue>} attrs\n * @param {JxScope} state\n */\nfunction applyAttributes(el: HTMLElement, attrs: Record<string, JxAttributeValue>, state: JxScope) {\n for (const [k, v] of Object.entries(attrs)) {\n const attr = canvasAttrName(el, k);\n if (isRefObj(v)) {\n effect(() => el.setAttribute(attr, String(resolveRef(v.$ref, state) ?? \"\")));\n } else if (isTemplateString(v)) {\n effect(() => el.setAttribute(attr, String(evaluateTemplate(v, state))));\n } else {\n el.setAttribute(attr, String(v));\n }\n }\n}\n\n// ─── Array mapping ────────────────────────────────────────────────────────────\n\n/**\n * Render a mapped array (repeater) wrapper-less: its item instances are inserted directly into\n * `parentEl`, in place, ahead of an anchor comment that marks the array's position among the\n * parent's other children. Re-renders reactively when `items` (or the filter/sort sources) change;\n * each generation's item renders live in their own detached effect scope so nested arrays and\n * template bindings are disposed — not leaked or double-fired — on the next change.\n *\n * `options._path` is the array node's own document path (`[…, \"children\", i]`, or `[…, \"children\"]`\n * for a legacy whole-children repeater); item instances render at `[…that…, \"map\", index]`.\n *\n * @param {HTMLElement} parentEl\n * @param {import(\"@jxsuite/schema/types\").JxMappedArray} arrayDef\n * @param {JxScope} state\n * @param {JxRenderOptions} [options]\n */\nfunction renderMappedArrayInto(\n parentEl: HTMLElement,\n arrayDef: JxMappedArray,\n state: JxScope,\n options?: JxRenderOptions,\n) {\n const path = options?._path ?? [];\n const anchor = document.createComment(\"jx-array\");\n parentEl.append(anchor);\n const { items: itemsSrc, map: mapDef, filter: filterRef, sort: sortRef } = arrayDef;\n\n effect(() => {\n let items: unknown = isRefObj(itemsSrc) ? resolveRef(itemsSrc.$ref, state) : itemsSrc;\n if (Array.isArray(items) && isRefObj(filterRef)) {\n const fn = resolveRef(filterRef.$ref, state);\n if (typeof fn === \"function\") {\n items = items.filter(fn as (v: unknown) => boolean);\n }\n }\n if (Array.isArray(items) && isRefObj(sortRef)) {\n const fn = resolveRef(sortRef.$ref, state);\n if (typeof fn === \"function\") {\n items = [...(items as unknown[])].toSorted(fn as (a: unknown, b: unknown) => number);\n }\n }\n if (!Array.isArray(items) || !mapDef) {\n return;\n }\n\n // Render this generation's items inside a detached scope; the cleanup (run before the next\n // Re-render and when the enclosing render scope stops) tears it down and removes its nodes.\n const scope = effectScope(true);\n const nodes: ChildNode[] = [];\n scope.run(() => {\n for (const [index, item] of (items as unknown[]).entries()) {\n const child = Object.create(state) as JxScope;\n child.$map = { index, item };\n child[\"$map/item\"] = item;\n child[\"$map/index\"] = index;\n const childOpts = options ? { ...options, _path: [...path, \"map\", index] } : undefined;\n const node = renderNode(mapDef, child, childOpts);\n anchor.before(node);\n nodes.push(node);\n }\n });\n onEffectCleanup(() => {\n scope.stop();\n for (const n of nodes) {\n n.remove();\n }\n });\n });\n}\n\n// ─── $switch ──────────────────────────────────────────────────────────────────\n\n/**\n * @param {JxElement} def\n * @param {JxScope} state\n * @param {JxRenderOptions} [options]\n * @returns {HTMLElement}\n */\nfunction renderSwitch(def: JxElement, state: JxScope, options?: JxRenderOptions) {\n const path = options?._path ?? [];\n const container = document.createElement(def.tagName ?? \"div\");\n\n if (options?.onNodeCreated) {\n options.onNodeCreated(container, path, def, state);\n }\n\n applyProperties(container, def, state);\n applyStyle(container, def.style ?? {}, (state[\"$media\"] as Record<string, string>) ?? {}, state);\n applyAttributes(container, def.attributes ?? {}, state);\n let generation = 0;\n\n effect(() => {\n container.innerHTML = \"\";\n if (!isRefObj(def.$switch)) {\n return;\n }\n const key = resolveRef(def.$switch.$ref, state) as string;\n const caseDef = def.cases?.[key];\n if (!caseDef) {\n return;\n }\n\n if (isRefObj(caseDef)) {\n // External $ref — fetch and render asynchronously\n const gen = (generation += 1);\n const { href } = new URL(caseDef.$ref, location.href);\n resolve(href)\n .then(async (doc) => {\n if (gen !== generation) {\n return;\n }\n const childScope = await buildScope(doc, {}, href);\n if (gen !== generation) {\n return;\n }\n container.innerHTML = \"\";\n const childOpts = options ? { ...options, _path: [...path, \"cases\", key] } : undefined;\n container.append(renderNode(doc, childScope, childOpts));\n })\n .catch((error: unknown) =>\n console.error(\"Jx $switch: failed to load external case\", caseDef.$ref, error),\n );\n return;\n }\n\n const childOpts = options ? { ...options, _path: [...path, \"cases\", key] } : undefined;\n container.append(renderNode(caseDef, state, childOpts));\n });\n\n return container;\n}\n\n// ─── Prototype namespaces (Shape 5) ──────────────────────────────────────────\n\n/**\n * Resolve a $prototype definition into a value for the reactive scope.\n *\n * Returns a ref() for async/persistent entries (Request, Storage, Cookie, IndexedDB), or a plain\n * value for simple entries (Set, Map, FormData, Blob).\n *\n * @param {JxPrototypeDef} def - State entry with $prototype\n * @param {JxScope} state - Reactive scope proxy\n * @param {string} key - Def key (for diagnostics)\n * @param {string} [base] - Base URL for resolving $src imports\n * @returns {Promise<unknown>}\n */\nexport async function resolvePrototype(\n def: JxPrototypeDef,\n state: JxScope,\n key: string,\n base?: string,\n) {\n // ── External class via $src ─────────────────────────────────────────────────\n if (def.$src) {\n return resolveExternalPrototype(def, state, key, base);\n }\n\n switch (def.$prototype) {\n case \"Request\": {\n const s: Ref<unknown> = ref(null);\n const debounceMs = def.debounce ?? 0;\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n if (!def.manual && !_autoRequestConfig.skip) {\n effect(() => {\n let url: string | undefined;\n if (isTemplateString(def.url)) {\n url = evaluateTemplate(def.url, state);\n } else {\n ({ url } = def);\n }\n if (!url || url === \"undefined\" || url.includes(\"undefined\")) {\n return;\n }\n\n const controller = new AbortController();\n onEffectCleanup(() => {\n controller.abort();\n if (debounceTimer !== null) {\n clearTimeout(debounceTimer);\n }\n });\n\n const doFetch = () =>\n fetch(url, {\n method: def.method ?? \"GET\",\n signal: controller.signal,\n ...(def.headers && { headers: def.headers }),\n ...(def.body && {\n body: typeof def.body === \"object\" ? JSON.stringify(def.body) : def.body,\n }),\n })\n .then((r) => (r.ok ? r.json() : Promise.reject(r.statusText)))\n .then((d) => {\n s.value = d;\n })\n .catch((error: unknown) => {\n if (!(error instanceof Error && error.name === \"AbortError\")) {\n s.value = { error: String(error) };\n }\n });\n\n if (debounceMs > 0) {\n debounceTimer = setTimeout(doFetch, debounceMs);\n } else {\n void doFetch();\n }\n });\n }\n\n return s;\n }\n\n case \"URLSearchParams\": {\n return computed(() => {\n const p: Record<string, string> = {};\n for (const [k, v] of Object.entries(def)) {\n if (k !== \"$prototype\") {\n p[k] = (\n isRefObj(v)\n ? resolveRef(v.$ref, state)\n : isTemplateString(v)\n ? evaluateTemplate(v, state)\n : v\n ) as string;\n }\n }\n return new URLSearchParams(p).toString();\n });\n }\n\n case \"LocalStorage\":\n case \"SessionStorage\": {\n const store = def.$prototype === \"LocalStorage\" ? localStorage : sessionStorage;\n const k = def.key ?? key;\n let init: unknown;\n try {\n const s = store.getItem(k);\n init = s !== null ? (JSON.parse(s) as unknown) : (def.default ?? null);\n } catch {\n init = def.default ?? null;\n }\n const storageState: Ref<unknown> = ref(init);\n // Persist on change\n effect(() => {\n const v = storageState.value;\n if (v === null) {\n try {\n store.removeItem(k);\n } catch {}\n } else {\n try {\n store.setItem(k, JSON.stringify(v));\n } catch {}\n }\n });\n return storageState;\n }\n\n case \"Cookie\": {\n const name = def.name ?? key;\n const read = () => {\n const m = document.cookie.match(new RegExp(`(?:^|; )${name}=([^;]*)`));\n if (!m) {\n return null;\n }\n try {\n return JSON.parse(decodeURIComponent(m[1]!));\n } catch {\n return m[1];\n }\n };\n const cookieState: Ref<unknown> = ref(read() ?? def.default ?? null);\n // Persist on change\n effect(() => {\n const v = cookieState.value;\n let s = `${name}=${encodeURIComponent(JSON.stringify(v))}`;\n if (def.maxAge !== undefined) {\n s += `; Max-Age=${def.maxAge}`;\n }\n if (def.path) {\n s += `; Path=${def.path}`;\n }\n if (def.domain) {\n s += `; Domain=${def.domain}`;\n }\n if (def.secure) {\n s += `; Secure`;\n }\n if (def.sameSite) {\n s += `; SameSite=${def.sameSite}`;\n }\n // oxlint-disable-next-line unicorn/no-document-cookie -- the Cookie $prototype IS the cookie store binding\n document.cookie = s;\n });\n return cookieState;\n }\n\n case \"IndexedDB\": {\n const idbState: Ref<unknown> = ref(null);\n const {\n database,\n store,\n version = 1,\n keyPath = \"id\",\n autoIncrement = true,\n indexes = [],\n } = def;\n if (!database || !store) {\n throw new Error(`Jx: IndexedDB entry '${key}' requires database and store`);\n }\n const req = indexedDB.open(database, version);\n req.addEventListener(\"upgradeneeded\", (e) => {\n const db: IDBDatabase = (e.target as IDBOpenDBRequest).result;\n if (!db.objectStoreNames.contains(store)) {\n const os = db.createObjectStore(store, { autoIncrement, keyPath });\n for (const i of indexes) {\n os.createIndex(i.name, i.keyPath, { unique: i.unique ?? false });\n }\n }\n });\n req.addEventListener(\"success\", (e) => {\n const db: IDBDatabase = (e.target as IDBOpenDBRequest).result;\n idbState.value = {\n database,\n getStore: (mode: IDBTransactionMode = \"readwrite\") =>\n Promise.resolve(db.transaction(store, mode).objectStore(store)),\n isReady: true,\n store,\n version,\n };\n });\n req.addEventListener(\"error\", () => {\n idbState.value = { error: req.error?.message };\n });\n return idbState;\n }\n\n case \"Set\": {\n return new Set(Array.isArray(def.default) ? def.default : []);\n }\n\n case \"Map\": {\n return new Map(Object.entries(isJsonObject(def.default) ? def.default : {}));\n }\n\n case \"FormData\": {\n const fd = new FormData();\n for (const [k, v] of Object.entries(def.fields ?? {})) {\n fd.append(k, v as string);\n }\n return fd;\n }\n\n case \"Blob\": {\n return new Blob((def.parts as BlobPart[]) ?? [], {\n type: typeof def.type === \"string\" ? def.type : \"text/plain\",\n });\n }\n\n case \"ReadableStream\": {\n return null;\n }\n\n default: {\n console.warn(\n `Jx: unknown $prototype \"${def.$prototype}\" for \"${key}\". Did you mean to add '$src'?`,\n );\n return ref(null);\n }\n }\n}\n\n// ─── External class resolution ────────────────────────────────────────────────\n\n/** Reserved keys stripped from the config object passed to external class constructors. */\nconst EXTERNAL_RESERVED = new Set([\n \"$prototype\",\n \"$src\",\n \"$export\",\n \"timing\",\n \"default\",\n \"description\",\n \"body\",\n \"parameters\",\n \"arguments\",\n \"name\",\n]);\n\n/**\n * Resolve an external class prototype via $src.\n *\n * @param {JxPrototypeDef} def\n * @param {JxScope} state\n * @param {string} key\n * @param {string} [base]\n * @returns {Promise<unknown>}\n */\nasync function resolveExternalPrototype(\n def: JxPrototypeDef,\n state: JxScope,\n key: string,\n base?: string,\n) {\n const src = def.$src;\n\n // Non-Function $prototype must use .class.json as entrypoint\n if (!src || !src.endsWith(\".class.json\")) {\n throw new Error(\n `Jx: $prototype \"${def.$prototype}\" requires a .class.json $src, got \"${src}\". ` +\n `Wrap the class in a .class.json schema with $implementation.`,\n );\n }\n\n return resolveClassJson(def, state, key, base);\n}\n\n/**\n * Import a JS module and instantiate a class from it. Internal helper used by resolveClassJson for\n * $implementation.\n *\n * @param {JxScope} def - Original state entry (for config extraction)\n * @param {string} src - JS module URL to import\n * @param {string} exportName - Export name to look up\n * @param {string} [base] - Base URL for resolution\n * @returns {Promise<unknown>}\n */\nasync function importAndInstantiate(def: JxScope, src: string, exportName: string, base?: string) {\n let mod: ImportedModule;\n if (_moduleCache.has(src)) {\n mod = _moduleCache.get(src)!;\n } else {\n try {\n mod = (await import(src)) as ImportedModule;\n } catch {\n if (base) {\n const resolvedSrc = new URL(src, base).href;\n mod = (await import(resolvedSrc)) as ImportedModule;\n } else {\n throw new Error(`Failed to import \"${src}\"`);\n }\n }\n _moduleCache.set(src, mod);\n }\n\n const ExportedClass = mod[exportName] ?? mod.default?.[exportName];\n if (!ExportedClass) {\n throw new Error(`Jx: export \"${exportName}\" not found in \"${src}\"`);\n }\n if (typeof ExportedClass !== \"function\") {\n throw new TypeError(`Jx: \"${exportName}\" from \"${src}\" is not a class`);\n }\n\n const config: JxScope = {};\n for (const [k, v] of Object.entries(def)) {\n if (!EXTERNAL_RESERVED.has(k)) {\n config[k] = v;\n }\n }\n\n const Ctor = ExportedClass as new (config: JxScope) => ExternalClassInstance;\n const instance = new Ctor(config);\n\n let value: unknown;\n if (typeof instance.resolve === \"function\") {\n value = await instance.resolve();\n } else if (\"value\" in instance) {\n ({ value } = instance);\n } else {\n value = instance;\n }\n\n // Always wrap in ref for reactivity with external classes\n const s: Ref<unknown> = ref(value);\n if (typeof instance.subscribe === \"function\") {\n instance.subscribe((newVal: unknown) => {\n s.value = newVal;\n });\n }\n return s;\n}\n\n/**\n * Resolve a .class.json schema-defined class. Fetches the schema, follows $implementation if\n * hybrid, or constructs dynamically if self-contained.\n *\n * @param {JxPrototypeDef} def\n * @param {JxScope} state\n * @param {string} key\n * @param {string} [base]\n * @returns {Promise<unknown>}\n */\nasync function resolveClassJson(def: JxPrototypeDef, state: JxScope, key: string, base?: string) {\n const src = def.$src;\n if (!src) {\n throw new Error(`Jx: class entry '${key}' has no $src`);\n }\n let classDef: JxClassDef;\n\n // Bare specifiers (package references like @scope/pkg/file) can't be fetched directly —\n // Go straight to dev proxy which can resolve them via node_modules.\n const isBareSpecifier =\n !src.startsWith(\".\") &&\n !src.startsWith(\"/\") &&\n !src.startsWith(\"http\") &&\n !src.startsWith(\"file:\");\n if (isBareSpecifier) {\n return resolveViaDevProxy(def, state, key, base);\n }\n\n // Try fetching the .class.json file directly\n try {\n const url = base ? new URL(src, base).href : src;\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n // Trust boundary: fetched .class.json sources are class definitions by contract.\n classDef = (await res.json()) as JxClassDef;\n } catch {\n // Fall back to dev proxy (server will handle .class.json resolution)\n return resolveViaDevProxy(def, state, key, base);\n }\n\n // Hybrid mode: $implementation points to the real JS module\n if (classDef.$implementation) {\n // If the schema references $context (e.g. content types), the browser cannot provide\n // The required server-side context — go directly to dev proxy.\n const schemaStr = JSON.stringify(classDef);\n if (schemaStr.includes('\"#/$context/')) {\n return resolveViaDevProxy(def, state, key, base);\n }\n const schemaUrl = base ? new URL(src, base).href : new URL(src, location.href).href;\n const implSrc = new URL(classDef.$implementation, schemaUrl).href;\n const exportName = def.$export ?? classDef.title ?? def.$prototype;\n try {\n return await importAndInstantiate(def, implSrc, exportName, base);\n } catch {\n return resolveViaDevProxy(def, state, key, base);\n }\n }\n\n // Self-contained: construct class dynamically from schema\n const DynClass = classFromSchema(classDef);\n const config: JxScope = {};\n for (const [k, v] of Object.entries(def)) {\n if (!EXTERNAL_RESERVED.has(k)) {\n config[k] = v;\n }\n }\n const instance = new DynClass(config) as ExternalClassInstance;\n\n let value: unknown;\n if (typeof instance.resolve === \"function\") {\n value = await instance.resolve();\n } else if (\"value\" in instance) {\n ({ value } = instance);\n } else {\n value = instance;\n }\n\n // Always wrap in ref for reactivity\n const s: Ref<unknown> = ref(value);\n if (typeof instance.subscribe === \"function\") {\n instance.subscribe((newVal: unknown) => {\n s.value = newVal;\n });\n }\n return s;\n}\n\n/**\n * Dynamically construct a class from a .class.json schema definition. Browser-side: maps private\n * fields to _-prefixed public fields.\n *\n * @param {import(\"@jxsuite/schema/types\").JxClassDef} classDef\n * @returns {DynamicClass}\n */\nfunction classFromSchema(classDef: JxClassDef) {\n const fields = classDef.$defs?.fields ?? {};\n // JSON objects inherit Object.prototype.constructor — only an own object value counts.\n const rawCtor = classDef.$defs?.constructor;\n const ctor = typeof rawCtor === \"object\" ? rawCtor : undefined;\n const methods = classDef.$defs?.methods ?? {};\n\n // oxlint-disable-next-line typescript/no-extraneous-class -- methods are attached to the prototype dynamically below\n class DynClass {\n constructor(config: Record<string, unknown> = {}) {\n for (const [key, typedField] of Object.entries(fields)) {\n const id = typedField.identifier ?? key;\n const propName = typedField.access === \"private\" ? `_${id}` : id;\n if (config[id] !== undefined) {\n (this as Record<string, unknown>)[propName] = config[id];\n } else if (typedField.initializer !== undefined) {\n (this as Record<string, unknown>)[propName] = typedField.initializer;\n } else if (typedField.default !== undefined) {\n (this as Record<string, unknown>)[propName] = structuredClone(typedField.default);\n } else {\n (this as Record<string, unknown>)[propName] = null;\n }\n }\n if (ctor?.body) {\n const bodyStr = Array.isArray(ctor.body) ? ctor.body.join(\"\\n\") : ctor.body;\n (\n new Function(\"config\", bodyStr) as (\n this: unknown,\n config: Record<string, unknown>,\n ) => void\n ).call(this, config);\n }\n }\n }\n\n for (const [key, typedMethod] of Object.entries(methods)) {\n const name = typedMethod.identifier ?? key;\n const params = (typedMethod.parameters ?? []).map((p) => {\n if (p.$ref) {\n return p.$ref.split(\"/\").pop() as string;\n }\n const n = p.identifier ?? p.name;\n return typeof n === \"string\" ? n : \"arg\";\n });\n const bodyStr = Array.isArray(typedMethod.body)\n ? typedMethod.body.join(\"\\n\")\n : (typedMethod.body ?? \"\");\n\n if (typedMethod.role === \"accessor\") {\n const descriptor: PropertyDescriptor = {};\n if (typedMethod.getter) {\n descriptor.get = new Function(typedMethod.getter.body ?? \"\") as () => unknown;\n }\n if (typedMethod.setter) {\n const sp = (typedMethod.setter.parameters ?? []).map(\n (p) => p.$ref?.split(\"/\").pop() ?? \"v\",\n );\n descriptor.set = new Function(...sp, typedMethod.setter.body ?? \"\") as (v: unknown) => void;\n }\n Object.defineProperty(DynClass.prototype, name, {\n ...descriptor,\n configurable: true,\n });\n } else if (typedMethod.scope === \"static\") {\n (DynClass as unknown as DynamicClass)[name] = new Function(...params, bodyStr);\n } else {\n (DynClass as unknown as DynamicClass).prototype[name] = new Function(...params, bodyStr);\n }\n }\n\n Object.defineProperty(DynClass, \"name\", {\n configurable: true,\n value: classDef.title,\n });\n const dynCtor = DynClass as unknown as DynamicClass;\n return dynCtor;\n}\n\n/**\n * Dev-mode fallback: when an $src module cannot run in the browser, proxy the resolve() call\n * through the Jx dev server (POST /**jx_resolve**). Supports reactive template strings in config\n * values via Vue effect().\n *\n * @param {JxPrototypeDef} def\n * @param {JxScope} state\n * @param {string} key\n * @param {string} [base]\n * @returns {Promise<unknown>}\n */\nasync function resolveViaDevProxy(def: JxPrototypeDef, state: JxScope, key: string, base?: string) {\n const config: JxScope = {};\n for (const [k, v] of Object.entries(def)) {\n if (!EXTERNAL_RESERVED.has(k)) {\n config[k] = v;\n }\n }\n\n const hasTemplates = Object.values(config).some((v: unknown) => isTemplateString(v));\n\n /** @param {JxScope} resolvedConfig */\n const doResolve = (resolvedConfig: JxScope) =>\n fetch(resolveProxyPath(\"/__jx_resolve__\"), {\n body: JSON.stringify({\n $base: base,\n $export: def.$export,\n $prototype: def.$prototype,\n $src: def.$src,\n ...resolvedConfig,\n }),\n headers: { \"Content-Type\": \"application/json\" },\n method: \"POST\",\n }).then((r) => {\n if (!r.ok) {\n throw new Error(`Jx dev proxy ${r.status} for \"${key}\"`);\n }\n return r.json();\n });\n\n // Always wrap in ref for reactivity\n const s: Ref<unknown> = ref(null);\n if (hasTemplates) {\n effect(() => {\n const resolvedConfig: JxScope = {};\n for (const [k, v] of Object.entries(config)) {\n resolvedConfig[k] = isTemplateString(v) ? evaluateTemplate(v, state) : v;\n }\n doResolve(resolvedConfig)\n .then((value: unknown) => {\n s.value = value;\n })\n .catch((error: unknown) => console.error(\"Jx dev proxy:\", error));\n });\n } else {\n doResolve(config)\n .then((value: unknown) => {\n s.value = value;\n })\n .catch((error: unknown) => console.error(\"Jx dev proxy:\", error));\n }\n return s;\n}\n\n// ─── Server function resolution (dev mode) ────────────────────────────────────\n\n/**\n * Resolve a timing: \"server\" entry in dev mode by executing the function client-side. In\n * production, the compiler replaces this with a fetch to the generated server handler.\n *\n * @param {JxScope} def\n * @param {JxScope} state\n * @param {string} key\n * @param {string} [base]\n * @returns {Promise<unknown>}\n */\nasync function resolveServerFunction(\n def: JxServerFnDef,\n state: JxScope,\n key: string,\n base?: string,\n) {\n const src = def.$src;\n const exportName = def.$export;\n\n let mod: ImportedModule;\n if (_moduleCache.has(src)) {\n mod = _moduleCache.get(src)!;\n } else {\n try {\n mod = (await import(src)) as ImportedModule;\n } catch {\n if (base) {\n try {\n const resolvedSrc = new URL(src, base).href;\n mod = (await import(resolvedSrc)) as ImportedModule;\n } catch {\n // Module cannot run in the browser — fall back to dev server proxy\n return resolveServerFunctionViaProxy(def, state, key, base);\n }\n } else {\n return resolveServerFunctionViaProxy(def, state, key, base);\n }\n }\n _moduleCache.set(src, mod);\n }\n\n const candidate = mod[exportName] ?? mod.default?.[exportName];\n if (!candidate) {\n throw new Error(`Jx: export \"${exportName}\" not found in \"${src}\" for \"${key}\"`);\n }\n if (typeof candidate !== \"function\") {\n throw new TypeError(`Jx: \"${exportName}\" from \"${src}\" is not a function`);\n }\n const fn = candidate as (args: JxScope) => Promise<unknown>;\n\n const rawArgs = def.arguments ?? {};\n const hasReactiveArg = Object.values(rawArgs).some((v: unknown) => isRefObj(v));\n const resolveArgs = () => {\n const args: JxScope = {};\n for (const [k, v] of Object.entries(rawArgs)) {\n args[k] = isRefObj(v) ? resolveRef(v.$ref, state) : v;\n }\n return args;\n };\n\n // Always wrap in ref for reactivity\n const s: Ref<unknown> = ref(null);\n if (hasReactiveArg) {\n effect(() => {\n const args = resolveArgs();\n onEffectCleanup(() => {});\n fn(args)\n .then((result: unknown) => {\n s.value = result;\n })\n .catch(() => {});\n });\n } else {\n s.value = await fn(resolveArgs());\n }\n return s;\n}\n\n/**\n * Dev-mode fallback: when a timing: \"server\" module cannot run in the browser, proxy the function\n * call through the Jx dev server (POST /**jx_server**). Supports reactive $ref arguments via Vue\n * effect().\n *\n * @param {JxScope} def\n * @param {JxScope} state\n * @param {string} key\n * @param {string} [base]\n * @returns {Promise<unknown>}\n */\nasync function resolveServerFunctionViaProxy(\n def: JxScope,\n state: JxScope,\n key: string,\n base?: string,\n) {\n const rawArgs = def.arguments ?? {};\n const hasReactiveArg = Object.values(rawArgs).some((v: unknown) => isRefObj(v));\n\n const resolveArgs = () => {\n const args: JxScope = {};\n for (const [k, v] of Object.entries(rawArgs)) {\n args[k] = isRefObj(v) ? resolveRef((v as { $ref: string }).$ref, state) : v;\n }\n return args;\n };\n\n /** @param {JxScope} args */\n const doResolve = (args: JxScope) =>\n fetch(resolveProxyPath(\"/__jx_server__\"), {\n body: JSON.stringify({\n $base: base,\n $export: def.$export,\n $src: def.$src,\n arguments: args,\n }),\n headers: { \"Content-Type\": \"application/json\" },\n method: \"POST\",\n }).then((r) => {\n if (!r.ok) {\n throw new Error(`Jx server proxy ${r.status} for \"${key}\"`);\n }\n return r.json();\n });\n\n // Always wrap in ref for reactivity\n const s: Ref<unknown> = ref(null);\n if (hasReactiveArg) {\n effect(() => {\n const args = resolveArgs();\n onEffectCleanup(() => {});\n doResolve(args)\n .then((result: unknown) => {\n s.value = result;\n })\n .catch((error: unknown) => console.error(\"Jx server proxy:\", error));\n });\n } else {\n doResolve(resolveArgs())\n .then((result: unknown) => {\n s.value = result;\n })\n .catch((error: unknown) => console.error(\"Jx server proxy:\", error));\n }\n return s;\n}\n\n/**\n * Resolve a $ref string to a value in scope.\n *\n * With Vue reactivity, this reads directly from the reactive proxy. When called inside a effect or\n * computed, the read is tracked.\n *\n * @param {string} ref\n * @param {JxScope} state - Reactive scope proxy (or child scope)\n * @returns {unknown}\n */\nexport function resolveRef(refPath: string, state: JxScope) {\n if (typeof refPath !== \"string\") {\n return refPath;\n }\n if (refPath.startsWith(\"$map/\")) {\n const parts = refPath.split(\"/\");\n const [, key] = parts; // \"item\" or \"index\"\n const map = state.$map as Record<string, unknown> | undefined;\n const base = map?.[key!] ?? state[`$map/${key}`];\n return parts.length > 2 ? getPath(base, parts.slice(2).join(\"/\")) : base;\n }\n if (refPath.startsWith(\"#/state/\")) {\n const sub = refPath.slice(\"#/state/\".length);\n const slash = sub.indexOf(\"/\");\n if (slash === -1) {\n return state[sub];\n }\n return getPath(state[sub.slice(0, slash)], sub.slice(slash + 1));\n }\n if (refPath.startsWith(\"parent#/\")) {\n return state[refPath.slice(\"parent#/\".length)];\n }\n if (refPath.startsWith(\"window#/\")) {\n return getPath(globalThis.window, refPath.slice(\"window#/\".length));\n }\n if (refPath.startsWith(\"document#/\")) {\n return getPath(globalThis.document, refPath.slice(\"document#/\".length));\n }\n return state[refPath] ?? null;\n}\n\n// ─── Utilities ────────────────────────────────────────────────────────────────\n\n/**\n * Check if v is a Vue ref (including computed).\n *\n * @param {unknown} v\n * @returns {boolean}\n */\nexport function isSignal(v: unknown) {\n return isRef(v);\n}\n\n/**\n * @param {unknown} v\n * @returns {v is import(\"@jxsuite/schema/types\").JxRef}\n */\nfunction isRefObj(v: unknown): v is JxRef {\n return isRefValue(v);\n}\n\n/**\n * @param {string} k\n * @returns {boolean}\n */\nfunction isNestedSelector(k: string) {\n return k.startsWith(\":\") || k.startsWith(\".\") || k.startsWith(\"&\") || k.startsWith(\"[\");\n}\n\n/**\n * @param {unknown} obj\n * @param {string} path\n * @returns {unknown}\n */\nfunction getPath(obj: unknown, path: string) {\n let current: unknown = obj;\n for (const k of path.split(/[./]/)) {\n current = (current as Record<string, unknown>)?.[k];\n }\n return current;\n}\n\n/**\n * @param {JxElement} def\n * @param {JxScope} parentState\n * @returns {JxScope}\n */\nfunction mergeProps(def: JxElement, parentState: JxScope): JxScope {\n const child = Object.create(parentState) as JxScope;\n for (const [k, v] of Object.entries(def.$props ?? {})) {\n child[k] = isRefObj(v) ? resolveRef(v.$ref, parentState) : v;\n }\n return child;\n}\n\n/**\n * Convert camelCase to kebab-case.\n *\n * @param {string} s\n * @returns {string}\n */\nexport function camelToKebab(s: string) {\n return s.replaceAll(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);\n}\n\n/**\n * Convert a style rules object to a CSS text string (skipping nested selectors).\n *\n * @param {Record<string, unknown> | object} rules\n * @returns {string}\n */\nexport function toCSSText(rules: Record<string, unknown> | object) {\n return Object.entries(rules)\n .filter(([k, v]) => !isNestedSelector(k) && (v === null || typeof v !== \"object\"))\n .map(([p, v]) => `${camelToKebab(p)}: ${transposeCanvasUnits(String(v))}`)\n .join(\"; \");\n}\n\n// ─── Color Schemes ────────────────────────────────────────────────────────────\n\n/**\n * Attribute on the root element (`<html>`) that forces a color scheme. Absent = auto (follow the OS\n * `prefers-color-scheme`). Values: \"light\" | \"dark\".\n *\n * @docs framework/concepts/color-schemes\n */\nexport const COLOR_SCHEME_ATTR = \"data-color-scheme\";\n\n/**\n * The localStorage key a site switcher persists the visitor's forced scheme under; read by the\n * compiler-injected pre-paint script. Values: \"light\" | \"dark\" (absent = auto).\n *\n * @docs framework/concepts/color-schemes\n */\nexport const COLOR_SCHEME_STORAGE_KEY = \"jx-color-scheme\";\n\n/**\n * The scheme a _pure_ `prefers-color-scheme` media query targets. Compound queries (any other\n * conditions attached) return null — they are not eligible for forced-scheme dual emission.\n *\n * @param {string} query\n * @returns {\"light\" | \"dark\" | null}\n * @docs framework/concepts/color-schemes\n */\nexport function pureSchemeOf(query: string): \"light\" | \"dark\" | null {\n const m = /^\\(\\s*prefers-color-scheme\\s*:\\s*(light|dark)\\s*\\)$/.exec(query.trim());\n return (m?.[1] as \"light\" | \"dark\") ?? null;\n}\n\n/**\n * Selector pair for a scheme-conditional rule: `auto` applies inside the scheme's media query only\n * while no scheme is forced; `forced` applies unconditionally when the root attribute forces the\n * scheme. Guards are wrapped in `:where()` so specificity matches the unguarded selector and source\n * order decides the cascade.\n *\n * @param {string} selector\n * @param {\"light\" | \"dark\"} scheme\n * @returns {{ auto: string; forced: string }}\n * @docs framework/concepts/color-schemes\n */\nexport function schemeSelectors(\n selector: string,\n scheme: \"light\" | \"dark\",\n): { auto: string; forced: string } {\n if (selector === \":root\" || selector === \"html\") {\n return {\n auto: `${selector}:where(:not([${COLOR_SCHEME_ATTR}]))`,\n forced: `${selector}:where([${COLOR_SCHEME_ATTR}=\"${scheme}\"])`,\n };\n }\n return {\n auto: `:where(:root:not([${COLOR_SCHEME_ATTR}])) ${selector}`,\n forced: `:where(:root[${COLOR_SCHEME_ATTR}=\"${scheme}\"]) ${selector}`,\n };\n}\n\n// ─── Custom Element Registration ──────────────────────────────────────────────\n\nlet _rootMedia: Record<string, string> = {};\nconst _elementDefs = new Map();\n\n/**\n * Seed the module-level root `$media` map used as the fallback for components that declare their\n * own `@--name` style blocks but carry no own `$media` (buildScope ~279-280). `Jx()` sets this from\n * the document during a full top-level render, but the Studio iframe canvas calls `buildScope`/\n * `renderNode` directly (never `Jx()`), so without seeding it a component's `@--md` would resolve\n * to the invalid `@media md`. Callers on the direct path MUST set it (with the merged `$media`)\n * before `buildScope`, and re-set it every render so a stale map from a previous document cannot\n * leak.\n *\n * @param {Record<string, string>} map\n */\nexport function setRootMedia(map: Record<string, string>): void {\n _rootMedia = map ?? {};\n}\n\n/**\n * Resolve and register $elements entries (depth-first).\n *\n * @param {JxDocument[\"$elements\"]} elements\n * @param {string} base\n * @returns {Promise<void>}\n */\nasync function registerElements(elements: NonNullable<JxDocument[\"$elements\"]>, base: string) {\n for (const entry of elements) {\n // Bare string: npm package side-effect import (registers custom elements)\n if (typeof entry === \"string\") {\n try {\n // Bare specifiers need a URL path for the browser; the dev server resolves\n // /node_modules/<pkg> to the package entry point via exports/module/main.\n const specifier =\n entry.startsWith(\"/\") || entry.startsWith(\".\") ? entry : `/node_modules/${entry}`;\n await import(specifier);\n } catch (error) {\n console.warn(`Jx: failed to import package \"${entry}\"`, error);\n }\n continue;\n }\n if (!isRefObj(entry)) {\n continue;\n }\n const { href } = new URL(entry.$ref, base);\n const doc = await resolve(href);\n if (!doc.tagName || !doc.tagName.includes(\"-\")) {\n continue;\n }\n if (customElements.get(doc.tagName)) {\n continue;\n }\n\n // Depth-first: register sub-dependencies first\n if (doc.$elements) {\n await registerElements(doc.$elements, href);\n }\n\n await defineElement(doc, href);\n }\n}\n\n/**\n * Inject head elements from $head declarations. Each entry is { tagName, attributes } — bare npm\n * specifiers in href/src are rewritten to /node_modules/ paths for the dev server.\n *\n * @param {import(\"@jxsuite/schema/types\").JxHeadEntry[]} entries\n * @param {string} _base - Document base URL for resolving relative paths\n */\nfunction injectHead(entries: JxHeadEntry[], _base: string) {\n for (const entry of entries) {\n if (!entry || !entry.tagName) {\n continue;\n }\n const tag = entry.tagName.toLowerCase();\n const attrs = { ...entry.attributes };\n // Resolve href/src: bare npm specifiers -> /node_modules/ path\n for (const key of [\"href\", \"src\"] as const) {\n const v = attrs[key];\n if (\n typeof v === \"string\" &&\n v &&\n !v.startsWith(\"/\") &&\n !v.startsWith(\".\") &&\n !v.startsWith(\"http\")\n ) {\n attrs[key] = `/node_modules/${v}`;\n }\n }\n\n // Deduplicate: skip if an identical element already exists\n const selector = `${tag}${attrs.href ? `[href=\"${attrs.href}\"]` : \"\"}${attrs.src ? `[src=\"${attrs.src}\"]` : \"\"}`;\n if (selector !== tag && document.head.querySelector(selector)) {\n continue;\n }\n\n const el = document.createElement(tag);\n for (const [k, v] of Object.entries(attrs)) {\n el.setAttribute(k, String(v));\n }\n if (entry.textContent) {\n el.textContent = entry.textContent;\n }\n document.head.append(el);\n }\n}\n\n/**\n * Register a custom element from a Jx document.\n *\n * @param {string | JxDocument} source - URL to .json file, or raw document object\n * @param {string} [base] - Base URL for resolving $src imports\n * @returns {Promise<void>}\n */\nconst _definedSources = new Set<string>();\n\nexport async function defineElement(source: string | JxDocument, baseUrl?: string) {\n let base = baseUrl;\n let doc = source;\n if (typeof source === \"string\") {\n base = new URL(source, base ?? location.href).href;\n if (_definedSources.has(base)) {\n return;\n }\n _definedSources.add(base);\n doc = await resolve(source);\n }\n base ??= location.href;\n\n const source_: JxDocument = doc as JxDocument;\n\n const { tagName } = source_;\n if (!tagName || !tagName.includes(\"-\")) {\n throw new Error(`Jx defineElement: tagName \"${tagName}\" must contain a hyphen`);\n }\n if (customElements.get(tagName)) {\n return;\n }\n\n // Register sub-dependencies first\n if (source_.$elements) {\n await registerElements(source_.$elements, base);\n }\n\n _elementDefs.set(tagName, { base, doc: source_ });\n\n const def = source_;\n const observedAttrs = def.observedAttributes ?? [];\n\n const ElementClass = class extends HTMLElement {\n _jxInitialized = false;\n _state: JxScope | null = null;\n\n static get observedAttributes() {\n return observedAttrs;\n }\n\n async connectedCallback() {\n // An element carrying `data-jx-definition-root` IS the definition being rendered by an\n // External renderer (the studio canvas editing this component's own document) — its subtree\n // Is authored DOM, not an instantiation site. Self-initializing here would wipe that tree\n // And re-render it with default state (the \"component editor shows a live instance\" bug).\n if (this.dataset.jxDefinitionRoot !== undefined) {\n return;\n }\n if (this._jxInitialized) {\n return;\n }\n this._jxInitialized = true;\n\n const state = await buildScope(def, {}, base);\n\n // Read properties from directive encoding (markdown → data-jx-props)\n const propsAttr = this.dataset.jxProps;\n if (propsAttr) {\n try {\n const props = JSON.parse(propsAttr) as Record<string, unknown>;\n for (const [key, val] of Object.entries(props)) {\n if (key in (def.state ?? {})) {\n state[key] = val;\n }\n }\n } catch {}\n delete this.dataset.jxProps;\n }\n\n // Read literal `props.*` attributes (JSON-authored instances pass props this way; the\n // Compiler lifts them into $props at build, and this is the live-render mirror). String\n // Values only — HTML lowercases attribute names, so state keys must be lowercase to match.\n // Collect first: removing while iterating the live NamedNodeMap skips entries.\n const propAttrNames = this.getAttributeNames().filter(\n (name) => name.startsWith(\"props.\") && name.length > \"props.\".length,\n );\n for (const name of propAttrNames) {\n const key = name.slice(\"props.\".length);\n if (key in (def.state ?? {})) {\n state[key] = this.getAttribute(name);\n this.removeAttribute(name);\n }\n }\n\n // Merge $props set as JS properties by parent before connection\n for (const key of Object.keys(def.state ?? {})) {\n if (key in this && (this as Record<string, unknown>)[key] !== undefined) {\n state[key] = (this as Record<string, unknown>)[key];\n }\n }\n // Set up property getters/setters that forward into reactive state\n for (const key of Object.keys(def.state ?? {})) {\n if (!(key in HTMLElement.prototype)) {\n Object.defineProperty(this, key, {\n configurable: true,\n get: () => state[key],\n set: (v: unknown) => {\n state[key] = v;\n },\n });\n }\n }\n\n this._state = state;\n\n // Capture light DOM children (for slot distribution) before rendering\n const slottedChildren = [...this.childNodes];\n this.innerHTML = \"\";\n\n // Custom elements default to display:inline — use block so they behave as\n // Containers (matching <div> semantics). The component's own style can\n // Override this if needed.\n if (!this.style.display) {\n this.style.display = \"block\";\n }\n\n // Render template into light DOM (once, not in effect — inner effects handle reactivity)\n applyStyle(this, def.style ?? {}, (state[\"$media\"] as Record<string, string>) ?? {}, state);\n applyAttributes(this, def.attributes ?? {}, state);\n\n const children = Array.isArray(def.children) ? def.children : [];\n for (const childDef of children) {\n this.append(renderNode(childDef, state));\n }\n\n // Slot distribution (light DOM)\n distributeSlots(this, slottedChildren);\n\n // Lifecycle: onMount\n const { onMount } = state;\n if (typeof onMount === \"function\") {\n queueMicrotask(() => (onMount as (s: JxScope) => unknown)(state));\n }\n }\n\n disconnectedCallback() {\n if (typeof this._state?.onUnmount === \"function\") {\n (this._state.onUnmount as (s: JxScope) => unknown)(this._state);\n }\n }\n\n adoptedCallback() {\n if (typeof this._state?.onAdopted === \"function\") {\n (this._state.onAdopted as (s: JxScope) => unknown)(this._state);\n }\n }\n\n attributeChangedCallback(name: string, oldVal: string | null, newVal: string | null) {\n if (!this._state || oldVal === newVal) {\n return;\n }\n const camelKey = name.replaceAll(/-([a-z])/g, (_: string, c: string) => c.toUpperCase());\n const current = this._state[camelKey];\n if (typeof current === \"number\") {\n this._state[camelKey] = Number(newVal);\n } else if (typeof current === \"boolean\") {\n this._state[camelKey] = newVal !== null && newVal !== \"false\";\n } else {\n this._state[camelKey] = newVal;\n }\n }\n };\n\n customElements.define(tagName, ElementClass);\n}\n\n/**\n * Render a registered custom element with $props (property-first interface).\n *\n * @param {JxElement} def\n * @param {JxScope} state\n * @param {JxRenderOptions} [options]\n * @param {JxPath} [path]\n * @returns {HTMLElement}\n */\nfunction renderCustomElementWithProps(\n def: JxElement,\n state: JxScope,\n options?: JxRenderOptions,\n path?: JxPath,\n) {\n const el = document.createElement(def.tagName ?? \"div\");\n\n if (options?.onNodeCreated) {\n options.onNodeCreated(el, path ?? [], def, state);\n }\n\n // Set JS properties from $props (before connection)\n for (const [key, val] of Object.entries(def.$props ?? {})) {\n if (isRefObj(val)) {\n const refVal = val;\n const resolved = resolveRef(refVal.$ref, state);\n (el as unknown as Record<string, unknown>)[key] = resolved;\n // Reactive forwarding: re-set the property when the source changes\n effect(() => {\n (el as unknown as Record<string, unknown>)[key] = resolveRef(refVal.$ref, state);\n });\n } else if (isTemplateString(val)) {\n effect(() => {\n (el as unknown as Record<string, unknown>)[key] = evaluateTemplate(val, state);\n });\n } else {\n (el as unknown as Record<string, unknown>)[key] = val;\n }\n }\n\n // Apply host-level style and attributes from the usage site\n applyStyle(el, def.style ?? {}, (state[\"$media\"] as Record<string, string>) ?? {}, state);\n applyAttributes(el, def.attributes ?? {}, state);\n\n // Append slotted children\n const children = Array.isArray(def.children) ? def.children : [];\n for (let i = 0; i < children.length; i++) {\n const childOpts = options && path ? { ...options, _path: [...path, \"children\", i] } : undefined;\n el.append(renderNode(children[i]!, state, childOpts));\n }\n\n return el;\n}\n\n/**\n * Light DOM slot distribution.\n *\n * @param {HTMLElement} host\n * @param {ChildNode[]} slottedChildren\n */\nfunction distributeSlots(host: HTMLElement, slottedChildren: ChildNode[]) {\n if (slottedChildren.length === 0) {\n return;\n }\n\n const slots = host.querySelectorAll(\"slot\");\n if (slots.length === 0) {\n return;\n }\n\n const named = new Map<string | null, ChildNode[]>();\n const unnamed: ChildNode[] = [];\n\n for (const child of slottedChildren) {\n if (child.nodeType === Node.ELEMENT_NODE && (child as Element).getAttribute(\"slot\")) {\n const name = (child as Element).getAttribute(\"slot\");\n if (!named.has(name)) {\n named.set(name, []);\n }\n (named.get(name) as ChildNode[]).push(child);\n } else {\n unnamed.push(child);\n }\n }\n\n for (const slot of slots) {\n const name = slot.getAttribute(\"name\");\n const matches = name ? (named.get(name) ?? []) : unnamed;\n if (matches.length > 0) {\n slot.innerHTML = \"\";\n for (const child of matches) {\n slot.append(child);\n }\n }\n }\n}\n",
|
|
28
|
-
"/// <reference lib=\"dom\" />\n/**\n * Parent-realm live component preview — registers a project component's custom element and\n * instantiates it in the editor document. Used by the browse grid and the components-palette DnD\n * cards. (The stylebook renders components inside the canvas iframe instead, via `$elements` refs\n * in its generated specimen doc.)\n */\n\nimport { defineElement, setSkipServerFunctions } from \"@jxsuite/runtime\";\nimport { projectState } from \"../store\";\nimport type { ComponentEntry } from \"../files/components\";\n\n/**\n * Render a live component preview by registering its custom element and instantiating it.\n *\n * @param {ComponentEntry} comp\n * @returns {Promise<HTMLElement>}\n */\nexport async function renderComponentPreview(comp: ComponentEntry) {\n setSkipServerFunctions(true);\n try {\n if (comp.source === \"npm\") {\n if (!customElements.get(comp.tagName)) {\n return _componentFallback(comp.tagName);\n }\n } else {\n if (comp.path && !comp.path.endsWith(\".json\")) {\n // Format-class component sources (e.g. markdown) can't be imported as modules\n return _componentFallback(comp.tagName);\n }\n const root = projectState?.projectRoot;\n const url = `${location.origin}/${root ? `${root}/` : \"\"}${comp.path}`;\n await defineElement(url);\n }\n const el = document.createElement(comp.tagName);\n for (const p of comp.props || []) {\n if (p.default !== undefined && p.default !== \"false\" && p.default !== \"''\") {\n const val = String(p.default).replaceAll(/^'|'$/g, \"\");\n el.setAttribute(p.name, val);\n }\n }\n return el;\n } catch (error) {\n console.warn(\"Component preview failed:\", comp.tagName, error);\n return _componentFallback(comp.tagName);\n }\n}\n\n/** @param {string} tagName */\nfunction _componentFallback(tagName: string) {\n const fallback = document.createElement(\"div\");\n fallback.style.cssText =\n \"padding:12px;border:1px dashed var(--border);border-radius:var(--radius);color:var(--fg-dim)\";\n fallback.textContent = `<${tagName}>`;\n return fallback;\n}\n",
|
|
29
|
-
"/// <reference lib=\"dom\" />\n/**\n * DnD registration functions — extracted from studio.js (Phase 4). Registers drag-and-drop behavior\n * on layer rows, component cards, and element cards.\n */\n\nimport {\n draggable,\n dropTargetForElements,\n monitorForElements,\n} from \"@atlaskit/pragmatic-drag-and-drop/element/adapter\";\nimport { combine } from \"@atlaskit/pragmatic-drag-and-drop/combine\";\nimport { disableNativeDragPreview } from \"@atlaskit/pragmatic-drag-and-drop/element/disable-native-drag-preview\";\nimport {\n attachInstruction,\n extractInstruction,\n} from \"@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item\";\n\nimport {\n childIndex,\n childList,\n getNodeAtPath,\n isAncestor,\n leftPanel,\n parentElementPath,\n renderOnly,\n} from \"../store\";\nimport { mutateInsertNode, mutateMoveNode, transact, transactDoc } from \"../tabs/transact\";\nimport { activeTab } from \"../workspace/workspace\";\nimport { view } from \"../view\";\nimport {\n buildComponentInstance,\n componentRegistry,\n computeRelativePath,\n} from \"../files/components\";\nimport { renderComponentPreview } from \"./component-preview\";\nimport { defaultDef, unsafeTags } from \"./shared\";\nimport { elementAtPoint } from \"../utils/geometry\";\nimport type { JxPath } from \"../state\";\nimport type { Tab } from \"../tabs/tab\";\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\nimport type { ComponentEntry } from \"../files/components.js\";\n\ninterface DragCanDragArgs {\n element: HTMLElement;\n input: { clientX: number; clientY: number };\n}\n\n/** The `onGenerateDragPreview` argument subset we forward to {@link disableNativeDragPreview}. */\ninterface DragPreviewArgs {\n nativeSetDragImage: ((image: Element, x: number, y: number) => void) | null;\n}\n\ninterface DragDropSourceArgs {\n source: { data: Record<string, unknown>; element: HTMLElement };\n}\n\ninterface DragSelfArgs {\n self: { data: Record<string, unknown> };\n}\n\ninterface DragMonitorDropArgs {\n source: { data: Record<string, unknown>; element: HTMLElement };\n location: { current: { dropTargets: { data: Record<string, unknown> }[] } };\n}\n\n/** Register DnD on layer rows — called from left-panel.js after render */\nexport function registerLayersDnD() {\n requestAnimationFrame(() => {\n const container = leftPanel?.querySelector(\".layers-container\") as HTMLElement | null;\n if (!container) {\n return;\n }\n\n for (const row of container.querySelectorAll(\"[data-dnd-row]\") as NodeListOf<HTMLElement>) {\n const rowPath = (row.dataset.path as string)\n .split(\"/\")\n .map((s: string) => (/^\\d+$/.test(s) ? Math.trunc(Number(s)) : s)) as JxPath;\n const rowDepth = Math.trunc(Number(row.dataset.dndDepth as string)) || 0;\n const isVoid = Object.hasOwn(row.dataset, \"dndVoid\");\n const isExpanded = Object.hasOwn(row.dataset, \"dndExpanded\");\n\n const cleanup = combine(\n draggable({\n canDrag({ element: _el, input }: DragCanDragArgs) {\n const target = elementAtPoint(input.clientX, input.clientY) as HTMLElement;\n if (target?.closest(\".layer-actions\")) {\n return false;\n }\n return true;\n },\n element: row,\n getInitialData() {\n return { path: rowPath, type: \"tree-node\" };\n },\n onGenerateDragPreview({ nativeSetDragImage }: DragPreviewArgs) {\n // Suppress the browser's native drag image — the cross-frame ghost (Phase 4c) is the\n // Only drag affordance, so a duplicate native preview would double up.\n disableNativeDragPreview({ nativeSetDragImage });\n },\n onDragStart() {\n row.classList.add(\"dragging\");\n view.layerDragSourceHeight = row.offsetHeight;\n if (isExpanded) {\n hideDescendantRows(row, container);\n }\n },\n onDrop() {\n row.classList.remove(\"dragging\");\n if (isExpanded) {\n renderOnly(\"leftPanel\");\n }\n },\n }),\n dropTargetForElements({\n element: row,\n canDrop({ source }: DragDropSourceArgs) {\n const srcPath = source.data.path as JxPath | undefined;\n if (srcPath && isAncestor(srcPath, rowPath)) {\n return false;\n }\n return true;\n },\n getData({\n input,\n element,\n }: {\n input: Parameters<typeof attachInstruction>[1][\"input\"];\n element: Element;\n }) {\n return attachInstruction(\n { path: rowPath },\n {\n block: isVoid ? [\"make-child\"] : [],\n currentLevel: rowDepth,\n element,\n indentPerLevel: 16,\n input,\n mode: isExpanded ? \"expanded\" : \"standard\",\n },\n ) as Record<string | symbol, unknown>;\n },\n onDragEnter({ self }: DragSelfArgs) {\n showLayerDropGap(row, self.data, container);\n },\n onDrag({ self }: DragSelfArgs) {\n showLayerDropGap(row, self.data, container);\n },\n // No onDragLeave clear — the gap persists while the pointer crosses dead space\n // Between rows; the monitor clears it when the drag moves to a non-tree target.\n onDrop() {\n clearLayerDropGap(container);\n },\n }),\n );\n view.dndCleanups.push(cleanup);\n }\n\n // Global monitor\n const monitorCleanup = monitorForElements({\n onDrop({ source, location }: DragMonitorDropArgs) {\n clearLayerDropGap(container);\n const [target] = location.current.dropTargets;\n if (!target) {\n return;\n }\n const instruction = extractInstruction(target.data);\n if (!instruction || instruction.type === \"instruction-blocked\") {\n return;\n }\n const srcData = source.data;\n const targetPath = target.data.path as JxPath;\n\n // If the source had children, persist collapse at the new location\n const srcRow = srcData.type === \"tree-node\" && source.element;\n const wasExpanded = srcRow && Object.hasOwn(srcRow.dataset, \"dndExpanded\");\n\n // Parent-originated layer drops legitimately target the active tab.\n applyDropInstruction(activeTab.value, instruction, srcData, targetPath);\n\n if (wasExpanded) {\n const tab = activeTab.value;\n const newPath = tab?.session.selection;\n if (newPath) {\n const collapsed = (view._layersCollapsed ||= new Set());\n collapsed.add(newPath.join(\"/\"));\n }\n }\n },\n onDropTargetChange({ location }: DragMonitorDropArgs) {\n // Clear the layer gap when the drag moves onto a non-tree target (e.g. a canvas\n // Element). When there is no target at all, keep the gap so it persists.\n const [inner] = location.current.dropTargets;\n if (inner && !extractInstruction(inner.data)) {\n clearLayerDropGap(container);\n }\n },\n });\n view.dndCleanups.push(monitorCleanup);\n });\n}\n\n/** Register DnD on component rows — called from renderLeftPanel when tab=components */\nexport function registerComponentsDnD() {\n requestAnimationFrame(() => {\n const container = leftPanel?.querySelector(\".components-section\") as HTMLElement | null;\n if (!container) {\n return;\n }\n\n for (const row of container.querySelectorAll(\n \"[data-component-tag]\",\n ) as NodeListOf<HTMLElement>) {\n const tagName = row.dataset.componentTag;\n if (!tagName) {\n continue;\n }\n const comp = componentRegistry.find((c: ComponentEntry) => c.tagName === tagName);\n if (!comp) {\n continue;\n }\n\n // Fill preview with live rendered component\n const preview = row.querySelector(\".element-card-preview\");\n if (preview && !preview.querySelector(tagName)) {\n void renderComponentPreview(comp).then((el: HTMLElement) => {\n preview.textContent = \"\";\n preview.append(el);\n });\n }\n\n const instanceDef = buildComponentInstance(comp);\n const cleanup = draggable({\n element: row,\n getInitialData() {\n return { fragment: structuredClone(instanceDef), type: \"block\" };\n },\n onGenerateDragPreview({ nativeSetDragImage }: DragPreviewArgs) {\n disableNativeDragPreview({ nativeSetDragImage });\n },\n });\n view.dndCleanups.push(cleanup);\n }\n });\n}\n\n/** Register DnD on element (HTML block) rows */\nexport function registerElementsDnD() {\n requestAnimationFrame(() => {\n const container = leftPanel?.querySelector(\".panel-body\") as HTMLElement | null;\n if (!container) {\n return;\n }\n for (const row of container.querySelectorAll(\"[data-block-tag]\") as NodeListOf<HTMLElement>) {\n const tag = row.dataset.blockTag as string;\n const preview = row.querySelector(\".element-card-preview\");\n if (preview && !preview.firstChild) {\n const el = document.createElement(unsafeTags.has(tag) ? \"span\" : tag);\n el.textContent = tag;\n preview.append(el);\n }\n const def = defaultDef(tag);\n const cleanup = draggable({\n element: row,\n getInitialData() {\n return { fragment: structuredClone(def), type: \"block\" };\n },\n onGenerateDragPreview({ nativeSetDragImage }: DragPreviewArgs) {\n disableNativeDragPreview({ nativeSetDragImage });\n },\n });\n view.dndCleanups.push(cleanup);\n }\n });\n}\n\n/**\n * Hide descendant rows of the dragged item so it appears collapsed during drag.\n *\n * @param {HTMLElement} parentRow\n * @param {HTMLElement} container\n */\nfunction hideDescendantRows(parentRow: HTMLElement, container: HTMLElement) {\n const prefix = `${parentRow.dataset.path}/`;\n const rows = container.querySelectorAll(\".layers-tree .layer-row\");\n for (const r of rows) {\n if ((r as HTMLElement).dataset.path?.startsWith(prefix)) {\n (r as HTMLElement).style.display = \"none\";\n }\n }\n}\n\n/**\n * @param {HTMLElement} rowEl\n * @param {Record<string, unknown>} data\n * @param {HTMLElement} container\n */\nexport function showLayerDropGap(\n rowEl: HTMLElement,\n data: Record<string, unknown>,\n container: HTMLElement,\n) {\n const instruction = extractInstruction(data);\n\n // Clear previous drop-target highlight\n if (view._currentDropTargetRow && view._currentDropTargetRow !== rowEl) {\n view._currentDropTargetRow.classList.remove(\"drop-target\");\n }\n\n if (!instruction || instruction.type === \"instruction-blocked\") {\n clearLayerDropGap(container);\n return;\n }\n\n if (instruction.type === \"make-child\") {\n clearLayerDropGap(container);\n rowEl.classList.add(\"drop-target\");\n view._currentDropTargetRow = rowEl;\n return;\n }\n\n rowEl.classList.remove(\"drop-target\");\n view._currentDropTargetRow = rowEl;\n\n // Shift rows to create gap\n const rows = [...container.querySelectorAll(\".layers-tree .layer-row\")];\n const targetIdx = rows.indexOf(rowEl);\n const gap = view.layerDragSourceHeight;\n\n for (let i = 0; i < rows.length; i++) {\n if ((rows[i] as HTMLElement).classList.contains(\"dragging\")) {\n continue;\n }\n if (instruction.type === \"reorder-above\") {\n (rows[i] as HTMLElement).style.transform = i >= targetIdx ? `translateY(${gap}px)` : \"\";\n } else {\n (rows[i] as HTMLElement).style.transform = i > targetIdx ? `translateY(${gap}px)` : \"\";\n }\n }\n}\n\n/** @param {HTMLElement} container */\nexport function clearLayerDropGap(container: HTMLElement) {\n if (view._currentDropTargetRow) {\n view._currentDropTargetRow.classList.remove(\"drop-target\");\n view._currentDropTargetRow = null;\n }\n const rows = container.querySelectorAll(\".layers-tree .layer-row\");\n for (const r of rows) {\n (r as HTMLElement).style.transform = \"\";\n // Also clear `display:none` left by hideDescendantRows. The `.layer-row` div has no `style`\n // Lit binding and rows aren't keyed, so lit reuses these DOM nodes positionally on the\n // Post-drop re-render — a stale `display:none` would otherwise hide whichever row lands on the\n // Reused node (e.g. a sibling of the moved subtree).\n (r as HTMLElement).style.display = \"\";\n }\n}\n\n/**\n * Apply a DnD instruction to `tab`'s document. `tab` is the tab whose canvas the drop resolved in\n * (host-routed for iframe drops — never the active tab at message time, which may have changed\n * while the dropResult was in flight); a null tab is a no-op.\n *\n * @param {Tab | null} tab\n * @param {{ type: string }} instruction\n * @param {Record<string, unknown>} srcData\n * @param {JxPath} targetPath\n */\nexport function applyDropInstruction(\n tab: Tab | null,\n instruction: { type: string },\n srcData: Record<string, unknown>,\n targetPath: JxPath,\n) {\n if (!tab) {\n return;\n }\n const doc = tab.doc.document as JxMutableNode;\n if (srcData.type === \"tree-node\") {\n const fromPath = srcData.path as JxPath;\n const targetParent = parentElementPath(targetPath) as JxPath;\n const targetIdx = childIndex(targetPath) as number;\n // Reordering requires a parent and a numeric index; root-level paths can't be\n // Reordered around.\n if (instruction.type !== \"make-child\" && (!targetParent || typeof targetIdx !== \"number\")) {\n return;\n }\n\n switch (instruction.type) {\n case \"reorder-above\": {\n transactDoc(tab, (t) => mutateMoveNode(t, fromPath, targetParent, targetIdx));\n break;\n }\n case \"reorder-below\": {\n transactDoc(tab, (t) => mutateMoveNode(t, fromPath, targetParent, targetIdx + 1));\n break;\n }\n case \"make-child\": {\n const target = getNodeAtPath(doc, targetPath);\n const len = childList(target).length;\n transactDoc(tab, (t) => mutateMoveNode(t, fromPath, targetPath, len));\n break;\n }\n default: {\n break;\n }\n }\n } else if (srcData.type === \"block\") {\n const targetParent = parentElementPath(targetPath) as JxPath;\n const targetIdx = childIndex(targetPath) as number;\n if (instruction.type !== \"make-child\" && (!targetParent || typeof targetIdx !== \"number\")) {\n return;\n }\n\n switch (instruction.type) {\n case \"reorder-above\": {\n transactDoc(tab, (t) =>\n mutateInsertNode(\n t,\n targetParent,\n targetIdx,\n structuredClone(srcData.fragment as JxMutableNode),\n ),\n );\n break;\n }\n case \"reorder-below\": {\n transactDoc(tab, (t) =>\n mutateInsertNode(\n t,\n targetParent,\n targetIdx + 1,\n structuredClone(srcData.fragment as JxMutableNode),\n ),\n );\n break;\n }\n case \"make-child\": {\n const target = getNodeAtPath(doc, targetPath);\n const len = childList(target).length;\n transactDoc(tab, (t) =>\n mutateInsertNode(t, targetPath, len, structuredClone(srcData.fragment as JxMutableNode)),\n );\n break;\n }\n default: {\n break;\n }\n }\n\n // Auto-import to $elements if the dropped block is a custom component\n const fragment = srcData.fragment as JxMutableNode | undefined;\n const tag = fragment?.tagName;\n if (tag && tag.includes(\"-\")) {\n const comp = componentRegistry.find((c: ComponentEntry) => c.tagName === tag);\n if (comp) {\n const elements = tab.doc.document?.$elements || [];\n if (comp.source === \"npm\") {\n const specifier = comp.modulePath ? `${comp.package}/${comp.modulePath}` : comp.package;\n if (!specifier) {\n return;\n }\n const alreadyImported = elements.some(\n (e: JxMutableNode | string | { $ref: string }) => e === specifier || e === comp.package,\n );\n if (!alreadyImported) {\n transact(tab, (d: JxMutableNode) => {\n if (!d.$elements) {\n d.$elements = [];\n }\n d.$elements.push(specifier);\n });\n }\n } else {\n const alreadyImported = elements.some((e: JxMutableNode | string | { $ref: string }) => {\n const ref = typeof e === \"object\" && e !== null ? e.$ref : undefined;\n const compPath = comp.path;\n return (\n ref &&\n compPath &&\n (ref === `./${compPath}` || ref.endsWith(compPath.split(\"/\").pop() as string))\n );\n });\n if (!alreadyImported && comp.path) {\n const relPath = computeRelativePath(tab?.documentPath ?? null, comp.path);\n transact(tab, (d: JxMutableNode) => {\n if (!d.$elements) {\n d.$elements = [];\n }\n d.$elements.push({ $ref: relPath });\n });\n }\n }\n }\n }\n }\n}\n",
|
|
30
|
-
"/// <reference lib=\"dom\" />\n/**\n * IframeChannel — the typed message boundary between the editor (parent) and the canvas iframe.\n *\n * Per the migration's cross-origin bridge decision, the parent never touches the iframe's\n * `contentDocument`; everything (render commands, patches, geometry, selection, hit-tests) crosses\n * as serializable messages through this one interface. Phases 1+ instantiate it with concrete\n * message unions (`ParentToIframe`/`IframeToParent`); this module owns only the transport contract\n * plus an in-memory `fakeChannelPair` so cross-frame logic is unit-testable without a live iframe.\n */\n\n/**\n * A typed, bidirectional message channel. `TOut` is what this side sends; `TIn` is what it\n * receives. Implementations: a real `postMessage` channel over an `<iframe>` (added with the iframe\n * host), and {@link fakeChannelPair} for tests.\n */\nexport interface IframeChannel<TOut, TIn> {\n /** Send a message to the other side. */\n post: (message: TOut) => void;\n /** Subscribe to messages from the other side. Returns an unsubscribe function. */\n onMessage: (handler: (message: TIn) => void) => () => void;\n /** Detach all handlers and release the transport. */\n dispose: () => void;\n}\n\n/** Envelope key that tags every cross-frame message so foreign `message` events are ignored. */\nconst ENVELOPE = \"jx:canvas\";\n\ninterface PostMessageTarget {\n postMessage: (message: unknown, targetOrigin: string) => void;\n}\n\ninterface MessageSource {\n addEventListener: (type: \"message\", listener: (event: MessageEvent) => void) => void;\n removeEventListener: (type: \"message\", listener: (event: MessageEvent) => void) => void;\n}\n\n/**\n * A real `IframeChannel` over `window.postMessage`. Outbound messages are wrapped in an envelope\n * tagged with a shared `token`; inbound messages are dropped unless their `event.origin` matches\n * `acceptOrigin` (pass `\"*\"` to skip the origin check) AND they carry the same token. This is the\n * origin + secret-token authentication that keeps other local pages from driving the canvas.\n *\n * Parent side: `target` = the iframe's `contentWindow`, `source` = `window`, origins = the iframe\n * origin. Iframe side: `target` = `window.parent`, `source` = `window`, origins = the editor\n * origin.\n */\nexport function postMessageChannel<TOut, TIn>(opts: {\n target: PostMessageTarget;\n source: MessageSource;\n targetOrigin: string;\n acceptOrigin: string;\n token: string;\n}): IframeChannel<TOut, TIn> {\n const { target, source, targetOrigin, acceptOrigin, token } = opts;\n const handlers = new Set<(message: TIn) => void>();\n\n const listener = (event: MessageEvent) => {\n if (acceptOrigin !== \"*\" && event.origin !== acceptOrigin) {\n return;\n }\n const data = event.data as { [ENVELOPE]?: string; payload?: TIn } | null;\n if (!data || typeof data !== \"object\" || data[ENVELOPE] !== token) {\n return;\n }\n for (const handler of handlers) {\n handler(data.payload as TIn);\n }\n };\n source.addEventListener(\"message\", listener);\n\n return {\n dispose() {\n handlers.clear();\n source.removeEventListener(\"message\", listener);\n },\n onMessage(handler) {\n handlers.add(handler);\n return () => handlers.delete(handler);\n },\n post(message) {\n target.postMessage({ [ENVELOPE]: token, payload: message }, targetOrigin);\n },\n };\n}\n\n/**\n * Two in-memory channels wired to each other for tests. A message `parent.post(x)` is delivered to\n * the `iframe` side's handlers (and vice versa) only when `flush()` is called — so tests drive the\n * inherently-async postMessage ordering deterministically. Messages posted _during_ a flush are\n * queued for the next flush, never delivered re-entrantly.\n */\nexport function fakeChannelPair<ParentOut, IframeOut>(): {\n parent: IframeChannel<ParentOut, IframeOut>;\n iframe: IframeChannel<IframeOut, ParentOut>;\n flush: () => void;\n /** Number of messages waiting to be delivered (both directions). */\n pending: () => number;\n} {\n let toIframe: ParentOut[] = [];\n let toParent: IframeOut[] = [];\n const iframeHandlers = new Set<(m: ParentOut) => void>();\n const parentHandlers = new Set<(m: IframeOut) => void>();\n\n const parent: IframeChannel<ParentOut, IframeOut> = {\n dispose() {\n parentHandlers.clear();\n },\n onMessage(handler) {\n parentHandlers.add(handler);\n return () => parentHandlers.delete(handler);\n },\n post(message) {\n toIframe.push(message);\n },\n };\n\n const iframe: IframeChannel<IframeOut, ParentOut> = {\n dispose() {\n iframeHandlers.clear();\n },\n onMessage(handler) {\n iframeHandlers.add(handler);\n return () => iframeHandlers.delete(handler);\n },\n post(message) {\n toParent.push(message);\n },\n };\n\n function flush() {\n const forIframe = toIframe;\n const forParent = toParent;\n toIframe = [];\n toParent = [];\n for (const message of forIframe) {\n for (const handler of iframeHandlers) {\n handler(message);\n }\n }\n for (const message of forParent) {\n for (const handler of parentHandlers) {\n handler(message);\n }\n }\n }\n\n return {\n flush,\n iframe,\n parent,\n pending: () => toIframe.length + toParent.length,\n };\n}\n",
|
|
31
|
-
"/**\n * Where a Preview link goes.\n *\n * Preview keeps anchors live (editable modes de-link them onto `data-jx-href`), so a click would\n * navigate the canvas iframe and destroy the render along with the editing session. The iframe\n * reports the intent instead and the shell opens the target for real — see `specs/studio.md` §4.2.\n *\n * A separate module from the canvas host so an embedder can override the destination without\n * importing the host's internals: the desktop app routes it through the OS so the page opens in the\n * user's own browser rather than a webview with no address bar, history or devtools.\n */\n\n/** Handles a fully-resolved absolute URL. */\nexport type PreviewNavigateHandler = (url: string) => void;\n\nlet handler: PreviewNavigateHandler | null = null;\n\n/** Override where preview links open. Pass null to restore the default (a new browser tab). */\nexport function setPreviewNavigateHandler(next: PreviewNavigateHandler | null): void {\n handler = next;\n}\n\n/** The registered override, or null when the default applies. */\nexport function getPreviewNavigateHandler(): PreviewNavigateHandler | null {\n return handler;\n}\n",
|
|
32
|
-
"/**\n * Slicing a block's content by CHARACTER OFFSET, preserving inline markup.\n *\n * A selection that spans blocks cuts through the middle of the first and last of them, so deleting\n * it means keeping `[0, from)` of one block and `[to, end)` of another — by rendered character\n * position, across whatever nesting of `<strong>`, `<em>`, `<code>` and links the author has built.\n * Cutting \"he**ll**o\" at offset 3 has to yield \"he\" + a bold \"l\", not a truncated string.\n *\n * The offsets here are the same ones {@link file://../canvas/iframe-position.ts} produces from the\n * DOM, so a caret position and a content slice always agree on what \"offset 3\" means.\n *\n * Pure: no DOM, no document, no reactivity — the whole thing is exercisable as data.\n *\n * @docs studio/editing/writing\n */\n\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\n\n/** A block's content as a children array — the form both storage shapes normalize to. */\nexport type Content = (JxMutableNode | string)[];\n\n/**\n * The content of `node` as a children array, whichever way it is stored.\n *\n * A block holds its text either as `textContent` (all-plain) or as `children` (mixed inline\n * markup), and every operation that joins or cuts blocks has to handle both.\n */\nexport function contentOf(node: JxMutableNode | undefined | null): Content {\n if (!node) {\n return [];\n }\n if (Array.isArray(node.children)) {\n return node.children as Content;\n }\n return typeof node.textContent === \"string\" && node.textContent.length > 0\n ? [node.textContent]\n : [];\n}\n\n/** The rendered text length of a content array. */\nexport function contentLength(children: Content): number {\n let n = 0;\n for (const child of children) {\n n += typeof child === \"string\" ? child.length : contentLength(contentOf(child));\n }\n return n;\n}\n\n/**\n * The sub-content covering characters `[start, end)`, with inline elements preserved.\n *\n * An inline element that straddles a boundary is kept with its content clipped — so cutting a bold\n * run in half leaves a shorter bold run, not plain text. Elements that fall entirely outside the\n * range are dropped; empty results are omitted rather than left as empty tags.\n */\nexport function sliceContent(children: Content, start: number, end: number): Content {\n const out: Content = [];\n let pos = 0;\n for (const child of children) {\n if (pos >= end) {\n break;\n }\n if (typeof child === \"string\") {\n const childEnd = pos + child.length;\n if (childEnd > start) {\n const text = child.slice(\n Math.max(0, start - pos),\n Math.max(0, Math.min(end, childEnd) - pos),\n );\n if (text) {\n out.push(text);\n }\n }\n pos = childEnd;\n continue;\n }\n const inner = contentOf(child);\n const len = contentLength(inner);\n const childEnd = pos + len;\n if (len === 0) {\n // A void inline (a `<br>`, an `<img>`) contributes no characters, so it can never satisfy a\n // Length-based overlap test — it sits AT a position rather than spanning one. Keep it when\n // The range covers that position, or every slice would silently drop it.\n if (pos >= start && pos < end) {\n // Copied verbatim: giving a `<br>` an empty `textContent` would be noise in the source.\n out.push({ ...child });\n }\n } else if (childEnd > start) {\n const kept = sliceContent(inner, Math.max(0, start - pos), Math.min(end, childEnd) - pos);\n if (kept.length > 0) {\n out.push(withContent(child, kept));\n }\n }\n pos = childEnd;\n }\n return out;\n}\n\n/** A copy of `node` carrying `children`, folded back to `textContent` when it is all plain text. */\nfunction withContent(node: JxMutableNode, children: Content): JxMutableNode {\n const { children: _drop, textContent: _dropText, ...rest } = node;\n if (children.length === 0) {\n return { ...rest, textContent: \"\" };\n }\n if (children.length === 1 && typeof children[0] === \"string\") {\n return { ...rest, textContent: children[0] };\n }\n return { ...rest, children };\n}\n\n/**\n * Merge adjacent plain strings and drop empties, so a spliced result does not carry the seams of\n * how it was built. Mirrors the normalization a contenteditable commit performs.\n */\nexport function normalizeContent(children: Content): Content {\n const out: Content = [];\n for (const child of children) {\n if (typeof child === \"string\") {\n if (child.length === 0) {\n continue;\n }\n const prev = out.at(-1);\n if (typeof prev === \"string\") {\n out[out.length - 1] = prev + child;\n continue;\n }\n }\n out.push(child);\n }\n return out;\n}\n\n/**\n * The content a block should hold after `[from, to)` is replaced by `text`, where `head` is the\n * block the range starts in and `tail` the block it ends in.\n *\n * Collapsing a cross-block range is the same shape as a merge: keep the head's prefix, keep the\n * tail's suffix, and join them — with any typed replacement between.\n */\nexport function spliceAcross(\n head: Content,\n from: number,\n tail: Content,\n to: number,\n text = \"\",\n): Content {\n return normalizeContent([\n ...sliceContent(head, 0, from),\n ...(text ? [text] : []),\n ...sliceContent(tail, to, contentLength(tail)),\n ]);\n}\n\n/** `{ children }` when the content carries markup, else the folded `{ textContent }` form. */\nexport function toStored(children: Content): {\n children?: Content;\n textContent?: string;\n} {\n const normalized = normalizeContent(children);\n if (normalized.length === 0) {\n return { textContent: \"\" };\n }\n if (normalized.length === 1 && typeof normalized[0] === \"string\") {\n return { textContent: normalized[0] };\n }\n return { children: normalized };\n}\n",
|
|
33
|
-
"/// <reference lib=\"dom\" />\n/**\n * Inline-edit apply logic — turns the serializable result of a contenteditable session (committed\n * children/text, a split, or a slash-insert) into `transactDoc` mutations. The inline editing\n * session lives inside the canvas iframe, which posts these plain-JSON results across the bridge\n * for this apply. Every input here is plain JSON — no DOM, no Range — so it crosses the frame\n * boundary.\n */\n\nimport { childIndex, getNodeAtPath, parentElementPath } from \"../store\";\nimport { isAncestor } from \"../state\";\nimport { isTabActive } from \"../workspace/workspace\";\nimport {\n mutateInsertNode,\n mutateRemoveNode,\n mutateUpdateProp,\n mutateUpdateProperty,\n transactDoc,\n} from \"../tabs/transact\";\nimport { defaultDef } from \"../panels/shared\";\n\nimport { contentLength, contentOf, spliceAcross, toStored } from \"./content-slice\";\nimport type { JxContentResult, SlashCommand } from \"./inline-edit\";\nimport type { JxPath } from \"../state\";\nimport type { Tab } from \"../tabs/tab\";\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\n\n/**\n * Whether a committed inline-edit result is effectively empty (blank text / lone whitespace /\n * `<br>`).\n */\nexport function isEmptyContent(commitData?: JxContentResult): boolean {\n if (!commitData) {\n return true;\n }\n if (commitData.textContent != null && commitData.textContent.trim() === \"\") {\n return true;\n }\n const kids = commitData.children;\n if (!kids) {\n return false;\n }\n if (kids.length === 0) {\n return true;\n }\n if (kids.length === 1 && typeof kids[0] === \"string\" && kids[0].trim() === \"\") {\n return true;\n }\n return kids.length === 1 && typeof kids[0] === \"object\" && kids[0]?.tagName === \"br\";\n}\n\n/**\n * Commit edited content to the node at `path` of `tab`'s document (children when rich, else\n * textContent). No-op if unchanged or the originating tab is gone. `tab` is the tab the edit\n * session belonged to (resolved host-side from the posting iframe) — NEVER the active tab at\n * message time, which may have changed while the commit was in flight.\n */\nexport function applyInlineCommit(\n tab: Tab | null,\n path: JxPath,\n children: (JxMutableNode | string)[] | null,\n textContent: string | null,\n opts: { coalesceKey?: string | null } = {},\n): void {\n if (!tab) {\n return;\n }\n const node = getNodeAtPath(tab.doc.document, path);\n // Only clear the counterpart key when it actually exists: deleting an absent key is a semantic\n // No-op, but the recorded op isn't — a spurious `set-prop children` turns a cheap in-place text\n // Patch into a subtree re-render (and, pre-relaxation, forced a full render inside components).\n if (children) {\n if (node && JSON.stringify(node.children) === JSON.stringify(children)) {\n return;\n }\n transactDoc(\n tab,\n (t) => {\n if (node?.textContent != null) {\n mutateUpdateProperty(t, path, \"textContent\");\n }\n mutateUpdateProperty(t, path, \"children\", children);\n },\n { coalesceKey: opts.coalesceKey ?? null },\n );\n } else if (textContent != null) {\n if (node && node.textContent === textContent && !node.children) {\n return;\n }\n transactDoc(\n tab,\n (t) => {\n if (node?.children) {\n mutateUpdateProperty(t, path, \"children\");\n }\n mutateUpdateProperty(t, path, \"textContent\", textContent);\n },\n { coalesceKey: opts.coalesceKey ?? null },\n );\n }\n}\n\n/**\n * Commit a prop-bound inline edit: persist `value` into `$props[prop]` of the component instance at\n * `path`. The unchanged-value no-op is LOAD-BEARING, not cosmetic: Escape-cancel and\n * patch-disturbed sessions post unchanged values, and without the equality check a commit→patch→\n * disturb→re-commit cycle loops (and pollutes undo history). An empty value deletes the prop\n * (mutateUpdateProp), reverting the instance to the definition default — same as clearing the\n * sidebar field.\n */\nexport function applyInlinePropCommit(\n tab: Tab | null,\n path: JxPath,\n prop: string,\n value: string,\n): void {\n if (!tab) {\n return;\n }\n const node = getNodeAtPath(tab.doc.document, path);\n if (!node) {\n return;\n }\n const current = (node.$props as Record<string, unknown> | undefined)?.[prop];\n if (`${current ?? \"\"}` === value) {\n return;\n }\n transactDoc(tab, (t) => {\n mutateUpdateProp(t, path, prop, value);\n });\n}\n\n/**\n * Join the block at `fromPath` onto the end of the block at `intoPath`, removing the former.\n *\n * Backspace at a block's start and Delete at a block's end are the same operation approached from\n * either side, so both land here. Returns the caret's document position at the seam — the join\n * point, not the end — or null when the merge was refused.\n *\n * Refused when either block is missing, or when one contains the other: a `<li>` and the `<p>`\n * inside it are adjacent in document order but merging them would mean a node absorbing its own\n * parent.\n */\nexport function applyBlockMerge(\n tab: Tab | null,\n fromPath: JxPath,\n intoPath: JxPath,\n): { path: JxPath; offset: number } | null {\n if (!tab) {\n return null;\n }\n const from = getNodeAtPath(tab.doc.document, fromPath) as JxMutableNode | undefined;\n const into = getNodeAtPath(tab.doc.document, intoPath) as JxMutableNode | undefined;\n if (!from || !into) {\n return null;\n }\n if (isAncestor(fromPath, intoPath) || isAncestor(intoPath, fromPath)) {\n return null;\n }\n\n const head = contentOf(into);\n const tail = contentOf(from);\n const seam = contentLength(head);\n const merged = toStored([...head, ...tail]);\n\n transactDoc(tab, (t) => {\n // Write the joined content BEFORE removing the source: updating a node never shifts indices,\n // So `fromPath` is still valid when the removal runs.\n if (merged.children) {\n if (into.textContent != null) {\n mutateUpdateProperty(t, intoPath, \"textContent\");\n }\n mutateUpdateProperty(t, intoPath, \"children\", merged.children);\n } else {\n if (into.children) {\n mutateUpdateProperty(t, intoPath, \"children\");\n }\n mutateUpdateProperty(t, intoPath, \"textContent\", merged.textContent ?? \"\");\n }\n mutateRemoveNode(t, fromPath);\n // A container emptied by the removal (the `<ul>` behind a list's last item) would otherwise\n // Linger as invisible structure that still occupies layout and shows up in the layers panel.\n pruneEmptyAncestors(t, parentElementPath(fromPath) as JxPath);\n if (isTabActive(tab)) {\n t.session.selection = intoPath;\n }\n });\n\n return { offset: seam, path: intoPath };\n}\n\n/**\n * Remove `path` and its now-childless ancestors, stopping at the document root or the first\n * ancestor that still has content.\n */\nfunction pruneEmptyAncestors(tab: Tab, path: JxPath): void {\n let cur = path;\n while (cur.length > 0) {\n const node = getNodeAtPath(tab.doc.document, cur) as JxMutableNode | undefined;\n const kids = node?.children;\n if (!node || !Array.isArray(kids) || kids.length > 0) {\n return;\n }\n const parent = parentElementPath(cur) as JxPath | null;\n mutateRemoveNode(tab, cur);\n if (!parent) {\n return;\n }\n cur = parent;\n }\n}\n\n/**\n * Apply a paragraph split to `tab`'s document: keep `before` in the node, insert a new `<p>` with\n * `after`. Returns its path (unchanged when `tab` is gone — the caller may still use it for\n * bookkeeping, but nothing is mutated).\n */\nexport function applyInlineSplit(\n tab: Tab | null,\n path: JxPath,\n before: JxContentResult,\n after: JxContentResult,\n): JxPath {\n const parentPath = parentElementPath(path) as JxPath;\n const idx = childIndex(path) as number;\n const newPath = [...parentPath, \"children\", idx + 1];\n if (!tab) {\n return newPath;\n }\n const newNode: JxMutableNode = { tagName: \"p\" };\n if (after.textContent != null) {\n newNode.textContent = after.textContent;\n } else if (after.children) {\n newNode.children = after.children;\n } else {\n newNode.textContent = \"\";\n }\n\n transactDoc(tab, (t) => {\n if (before.textContent != null) {\n mutateUpdateProperty(t, path, \"children\");\n mutateUpdateProperty(t, path, \"textContent\", before.textContent);\n } else if (before.children) {\n mutateUpdateProperty(t, path, \"textContent\");\n mutateUpdateProperty(t, path, \"children\", before.children);\n }\n mutateInsertNode(t, parentPath, idx + 1, newNode);\n // A background tab's selection stays exactly as the user left it — only the visible tab's\n // Selection follows the split.\n if (isTabActive(tab)) {\n t.session.selection = newPath;\n }\n });\n return newPath;\n}\n\n/**\n * Apply a slash-insert at `path` of `tab`'s document: swap the (empty) node's tag in place, or\n * commit pending content and insert a new element after it. Returns the path to edit next (the\n * swapped node or the new one); nothing is mutated when `tab` is gone.\n */\nexport function applyInlineInsert(\n tab: Tab | null,\n path: JxPath,\n cmd: SlashCommand,\n commitData: JxContentResult | undefined,\n): JxPath {\n if (isEmptyContent(commitData)) {\n if (!tab) {\n return path;\n }\n transactDoc(tab, (t) => {\n mutateUpdateProperty(t, path, \"tagName\", cmd.tag);\n mutateUpdateProperty(t, path, \"children\");\n const def = defaultDef(cmd.tag);\n if (def.textContent && def.textContent !== \"Paragraph text\") {\n mutateUpdateProperty(t, path, \"textContent\", def.textContent);\n } else {\n mutateUpdateProperty(t, path, \"textContent\");\n }\n if (isTabActive(tab)) {\n t.session.selection = path;\n }\n });\n return path;\n }\n\n const parentPath = parentElementPath(path) as JxPath;\n const idx = childIndex(path) as number;\n const newPath = [...parentPath, \"children\", idx + 1];\n if (!tab) {\n return newPath;\n }\n const elementDef = defaultDef(cmd.tag);\n\n transactDoc(tab, (t) => {\n if (commitData?.children) {\n mutateUpdateProperty(t, path, \"textContent\");\n mutateUpdateProperty(t, path, \"children\", commitData.children);\n } else if (commitData?.textContent != null) {\n mutateUpdateProperty(t, path, \"children\");\n mutateUpdateProperty(t, path, \"textContent\", commitData.textContent);\n }\n mutateInsertNode(t, parentPath, idx + 1, structuredClone(elementDef));\n if (isTabActive(tab)) {\n t.session.selection = newPath;\n }\n });\n return newPath;\n}\n\n/**\n * Replace a selection that spans blocks with `text` (empty for a deletion).\n *\n * Collapsing a cross-block range is a merge with both ends clipped: the first block keeps what\n * precedes the selection, the last keeps what follows it, the two are joined, and every block\n * between them is removed. `between` is supplied by the iframe because document order lives in the\n * rendered DOM — the same reason a boundary merge names its neighbour there.\n *\n * Returns the caret's position after the collapse (the join point, plus any typed text), or null\n * when the range does not resolve.\n */\nexport function applyRangeReplace(\n tab: Tab | null,\n from: { path: JxPath; offset: number },\n to: { path: JxPath; offset: number },\n between: JxPath[],\n text: string,\n): { path: JxPath; offset: number } | null {\n if (!tab) {\n return null;\n }\n const head = getNodeAtPath(tab.doc.document, from.path) as JxMutableNode | undefined;\n const tail = getNodeAtPath(tab.doc.document, to.path) as JxMutableNode | undefined;\n if (!head || !tail) {\n return null;\n }\n if (isAncestor(from.path, to.path) || isAncestor(to.path, from.path)) {\n return null;\n }\n\n const joined = toStored(\n spliceAcross(contentOf(head), from.offset, contentOf(tail), to.offset, text),\n );\n // Remove the deepest/last paths first so an earlier removal cannot shift a later one's index.\n const removals = [...between, to.path].toSorted(comparePathsDescending);\n\n transactDoc(tab, (t) => {\n if (joined.children) {\n if (head.textContent != null) {\n mutateUpdateProperty(t, from.path, \"textContent\");\n }\n mutateUpdateProperty(t, from.path, \"children\", joined.children);\n } else {\n if (head.children) {\n mutateUpdateProperty(t, from.path, \"children\");\n }\n mutateUpdateProperty(t, from.path, \"textContent\", joined.textContent ?? \"\");\n }\n for (const path of removals) {\n if (getNodeAtPath(t.doc.document, path)) {\n mutateRemoveNode(t, path);\n pruneEmptyAncestors(t, parentElementPath(path) as JxPath);\n }\n }\n if (isTabActive(tab)) {\n t.session.selection = from.path;\n }\n });\n\n return { offset: from.offset + text.length, path: from.path };\n}\n\n/**\n * Order two paths so the LATER one in the document sorts first — the order removals must run in,\n * since removing an earlier sibling renumbers every path after it.\n */\nfunction comparePathsDescending(a: JxPath, b: JxPath): number {\n const len = Math.min(a.length, b.length);\n for (let i = 0; i < len; i++) {\n const av = a[i];\n const bv = b[i];\n if (av === bv) {\n continue;\n }\n if (typeof av === \"number\" && typeof bv === \"number\") {\n return bv - av;\n }\n return String(bv).localeCompare(String(av));\n }\n return b.length - a.length;\n}\n",
|
|
34
|
-
"/// <reference lib=\"dom\" />\n/**\n * Parent-side canvas overlay layer for the iframe host. Because the cross-origin bridge forbids the\n * parent from reading the iframe's DOM, selection/hover boxes are drawn from rects the iframe posts\n * back (see {@link measureHits}/`hover`). This module owns the pure rect→overlay math ({@link\n * canvasRectToParent}) and a small DOM layer that floats above the iframe, reusing the same\n * `overlay-box`/`overlay-selection`/`overlay-hover` classes as the legacy canvas for visual\n * parity.\n */\n\nimport type { SerializableRect } from \"./iframe-protocol\";\n\n/** An overlay box position in the parent overlay layer's local coordinates. */\nexport interface OverlayPlacement {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\n/**\n * Map a rect measured in the iframe's own viewport to the parent overlay layer's coordinates. The\n * overlay layer is positioned exactly over the iframe (same top-left), so the only transform is the\n * zoom `scale` (applied as a CSS `transform: scale()` on the iframe element, hence a plain multiply\n * here). Kept pure so the zoom math is unit-tested independently of the DOM.\n */\nexport function canvasRectToParent(rect: SerializableRect, scale = 1): OverlayPlacement {\n return {\n height: rect.height * scale,\n left: rect.x * scale,\n top: rect.y * scale,\n width: rect.width * scale,\n };\n}\n\n/**\n * Map a parent-viewport cursor (e.g. a pragmatic `location.current.input`, in true post-transform\n * parent px) into the iframe's own viewport coordinates. The iframe + overlay are descendants of\n * the scaled `panzoom-wrap`, so the cursor must be DIVIDED by the zoom `scale` (the inverse of the\n * CSS `transform: scale()` the browser already applied). `iframeRect` is `rectOf(iframe)` (its GBCR\n * bakes in pan + scale, so subtracting its `left`/`top` cancels the pan offset). Pure, so the\n * sign/order of the transform is unit-tested independently of the DOM. Empirical `scale` is derived\n * by the caller as `rectOf(iframe).width / iframe.clientWidth` (NOT `effectiveZoom()` — a separate\n * path that can desync).\n */\nexport function parentCursorToIframe(\n cursor: { x: number; y: number },\n iframeRect: { left: number; top: number },\n scale = 1,\n): { x: number; y: number } {\n return {\n x: (cursor.x - iframeRect.left) / scale,\n y: (cursor.y - iframeRect.top) / scale,\n };\n}\n\n/** The geometric side a drop indicator draws on (mirrors {@link DropPreview}'s `edge`). */\nexport type DropEdge = \"top\" | \"bottom\" | \"inside\";\n\n/** A floating overlay layer over the iframe that draws a selection box and a hover box. */\nexport interface OverlayLayer {\n /**\n * Position the selection box (or hide it when `placement` is null). `label` shows a small badge\n * on the box (stylebook draws the selected tag, e.g. \"<p>\", via the legacy `.overlay-label` CSS);\n * omitted/null hides it.\n */\n setSelection: (placement: OverlayPlacement | null, label?: string | null) => void;\n /**\n * Draw remote collaborators' selection boxes (colored outline + name tag). Replaces the whole set\n * each call; pass [] to clear. Placements are overlay-local coords like setSelection's.\n */\n setPresence: (items: { placement: OverlayPlacement; color: string; label: string }[]) => void;\n /** Position the hover box (or hide it when `placement` is null). */\n setHover: (placement: OverlayPlacement | null) => void;\n /**\n * Draw the drop indicator for a drag-over (Phase 4c). `placement` is the reference node's rect in\n * overlay-local coords (the caller maps the iframe-space `referenceRect` via\n * {@link canvasRectToParent} at scale=1 — the overlay is INSIDE the scaled panzoom-wrap, so the\n * browser already scales it; multiplying by zoom would double-scale, D-2). `edge` \"inside\" → a\n * dashed box over the reference; \"top\"/\"bottom\" → a thin line at the reference's top/bottom edge.\n * Pass null to hide.\n */\n setDropIndicator: (placement: OverlayPlacement | null, edge?: DropEdge) => void;\n /**\n * Position the clickable insertion \"+\" at `placement` (overlay-local coords, mapped via\n * {@link canvasRectToParent} at scale=1 like the drop indicator, D-2), centered on the anchor box\n * and tagged with `edge` (for the `[data-edge]` styling). Pass null to hide it. This is the ONE\n * element on the otherwise `pointer-events:none` overlay that captures pointer events, so the\n * author can actually click it; the caller wires its click/mouseenter/mouseleave via\n * {@link insertButton}.\n */\n setInsertZone: (placement: OverlayPlacement | null, edge?: InsertButtonEdge) => void;\n /**\n * Highlight the image an external file drop would REPLACE (flow 5). Distinct from\n * {@link setDropIndicator}, which shows where a new element would be inserted — the two answer\n * different questions (\"this picture is about to change\" vs. \"the element lands here\"), so a drop\n * shows exactly one of them. `placement` is overlay-local like the others; null hides it.\n */\n setReplaceTarget: (placement: OverlayPlacement | null) => void;\n /** The clickable \"+\" button, so the caller can attach click + hover (grace-timer) listeners. */\n readonly insertButton: HTMLButtonElement;\n /** The layer root element (caller appends it over the iframe). */\n readonly root: HTMLElement;\n /** Remove the layer from the DOM. */\n dispose: () => void;\n}\n\n/** The geometric side the insertion \"+\" anchors to (mirrors {@link InsertZone}'s `edge`). */\nexport type InsertButtonEdge = \"top\" | \"bottom\" | \"left\" | \"right\" | \"center\";\n\nfunction place(box: HTMLElement, placement: OverlayPlacement | null): void {\n if (!placement) {\n box.style.display = \"none\";\n return;\n }\n box.style.display = \"block\";\n box.style.left = `${placement.left}px`;\n box.style.top = `${placement.top}px`;\n box.style.width = `${placement.width}px`;\n box.style.height = `${placement.height}px`;\n}\n\n/** Build (but do not mount) an overlay layer with hidden selection + hover boxes. */\nexport function createOverlayLayer(doc: Document = document): OverlayLayer {\n const root = doc.createElement(\"div\");\n root.className = \"jx-canvas-iframe-overlay\";\n // Float over the iframe without intercepting pointer events (the iframe handles its own hit-test).\n root.style.cssText = \"position:absolute;inset:0;pointer-events:none;overflow:hidden;z-index:2\";\n\n const selectionBox = doc.createElement(\"div\");\n selectionBox.className = \"overlay-box overlay-selection\";\n selectionBox.style.display = \"none\";\n\n const selectionLabel = doc.createElement(\"div\");\n selectionLabel.className = \"overlay-label\";\n selectionLabel.style.display = \"none\";\n selectionBox.append(selectionLabel);\n\n const hoverBox = doc.createElement(\"div\");\n hoverBox.className = \"overlay-box overlay-hover\";\n hoverBox.style.display = \"none\";\n\n // Reuses the legacy `.canvas-drop-indicator` CSS (`.line` = thin bar, `.inside` = dashed box).\n const dropBox = doc.createElement(\"div\");\n dropBox.className = \"canvas-drop-indicator\";\n dropBox.style.display = \"none\";\n\n // The clickable insertion \"+\" — reuses the legacy `.insertion-helper` circle styling. It is the\n // ONE element on the `pointer-events:none` overlay that re-enables pointer events, so the author\n // Can click it (the legacy CSS-anchor positioning rules are inert here — no `position-anchor` is\n // Set — so it is positioned explicitly via left/top by placeInsertButton).\n const insertButton = doc.createElement(\"button\");\n insertButton.className = \"insertion-helper\";\n insertButton.textContent = \"+\";\n insertButton.style.pointerEvents = \"auto\";\n insertButton.style.display = \"none\";\n\n // The \"this picture will be replaced\" highlight for an external file drop.\n const replaceBox = doc.createElement(\"div\");\n replaceBox.className = \"canvas-replace-target\";\n replaceBox.style.display = \"none\";\n\n // Remote collaborators' selection boxes live in their own container, replaced wholesale.\n const presenceGroup = doc.createElement(\"div\");\n presenceGroup.className = \"overlay-presence-group\";\n\n root.append(hoverBox, selectionBox, dropBox, replaceBox, insertButton, presenceGroup);\n\n return {\n dispose: () => root.remove(),\n insertButton,\n root,\n setDropIndicator: (placement, edge = \"inside\") => placeDropIndicator(dropBox, placement, edge),\n setHover: (placement) => place(hoverBox, placement),\n setInsertZone: (placement, edge = \"center\") => placeInsertButton(insertButton, placement, edge),\n setReplaceTarget: (placement) => place(replaceBox, placement),\n setPresence: (items) => {\n presenceGroup.replaceChildren();\n for (const item of items) {\n const box = doc.createElement(\"div\");\n box.className = \"overlay-box overlay-presence\";\n box.style.cssText =\n `position:absolute;display:block;pointer-events:none;` +\n `outline:1.5px solid ${item.color};outline-offset:1px;` +\n `left:${item.placement.left}px;top:${item.placement.top}px;` +\n `width:${item.placement.width}px;height:${item.placement.height}px`;\n const tag = doc.createElement(\"div\");\n tag.className = \"overlay-presence-tag\";\n tag.textContent = item.label;\n tag.style.cssText =\n `position:absolute;top:-18px;left:-2px;padding:1px 5px;border-radius:3px;` +\n `font:10px/1.4 sans-serif;color:#fff;white-space:nowrap;background:${item.color}`;\n box.append(tag);\n presenceGroup.append(box);\n }\n },\n setSelection: (placement, label = null) => {\n place(selectionBox, placement);\n if (placement && label) {\n selectionLabel.textContent = label;\n selectionLabel.style.display = \"block\";\n } else {\n selectionLabel.style.display = \"none\";\n }\n },\n };\n}\n\n/**\n * Position the insertion \"+\" centered on the anchor `placement` (a zero-thickness edge box from the\n * iframe), or hide it when null. Sets `data-edge` for the `[data-edge]` styling and toggles the\n * `visible` class the legacy CSS uses (display + opacity). Explicit left/top centering replaces the\n * legacy CSS-anchor positioning, which can't reach across the iframe boundary.\n */\nfunction placeInsertButton(\n btn: HTMLButtonElement,\n placement: OverlayPlacement | null,\n edge: InsertButtonEdge,\n): void {\n if (!placement) {\n btn.style.display = \"none\";\n btn.classList.remove(\"visible\");\n return;\n }\n btn.dataset.edge = edge;\n btn.classList.add(\"visible\");\n // Center the 20×20 circle on the anchor box's midpoint (the edge for a zero-thickness box).\n btn.style.display = \"grid\";\n btn.style.left = `${placement.left + placement.width / 2}px`;\n btn.style.top = `${placement.top + placement.height / 2}px`;\n btn.style.translate = \"-50% -50%\";\n}\n\n/**\n * Position the drop indicator box. `inside` → a dashed box over the reference rect; `top`/`bottom`\n * → a thin horizontal line at the reference's top/bottom (full reference width, zero-height bar).\n * The placement is already in overlay-local coords at scale=1 (D-2).\n */\nfunction placeDropIndicator(\n box: HTMLElement,\n placement: OverlayPlacement | null,\n edge: DropEdge,\n): void {\n if (!placement) {\n box.style.display = \"none\";\n return;\n }\n box.style.display = \"block\";\n box.style.left = `${placement.left}px`;\n box.style.width = `${placement.width}px`;\n if (edge === \"inside\") {\n box.className = \"canvas-drop-indicator inside\";\n box.style.top = `${placement.top}px`;\n box.style.height = `${placement.height}px`;\n return;\n }\n box.className = \"canvas-drop-indicator line\";\n box.style.height = \"\";\n box.style.top = `${edge === \"top\" ? placement.top : placement.top + placement.height}px`;\n}\n",
|
|
35
|
-
"/// <reference lib=\"dom\" />\n/**\n * Render-path mapping — pure logic shared by the legacy in-realm path mapper (which stores paths in\n * the `elToPath` WeakMap) and the iframe host (which stamps them as `data-jx-path` attributes).\n *\n * The runtime fires `onNodeCreated(el, renderPath, def, state)` for every node. The render path is\n * not always the document path: layout-wrapped pages shift page content under a layout prefix, and\n * `prepareForEditMode` renders mapped arrays (`$prototype: Array`) as a `repeater-perimeter` whose\n * single child hop must be collapsed back to a `map` segment. {@link classifyRenderNode} resolves a\n * render path to either a document path or a \"layout\" marker; {@link serializeJxPath} encodes the\n * result for the `data-jx-path` attribute.\n */\n\nimport type { JxPath } from \"../state\";\n\n/** Context the mapper needs, computed once per render by whoever prepared the document. */\nexport interface PathMapCtx {\n canvasMode: string;\n layoutWrapped: boolean;\n pageContentPrefix: JxPath | null;\n pageContentOffset: number | null;\n arrayPaths: Set<string>;\n}\n\n/** A render node either belongs to the layout chrome (no document path) or maps to a document path. */\nexport type RenderNodeClass = { kind: \"layout\" } | { kind: \"path\"; path: JxPath };\n\n/**\n * Resolve a runtime render path to a document path (or flag it as layout-originated). Pure — the\n * caller decides whether to record the result in a WeakMap or a `data-jx-path` attribute.\n */\nexport function classifyRenderNode(path: JxPath, def: unknown, ctx: PathMapCtx): RenderNodeClass {\n // Layout-originated nodes have no page-document path; the caller marks them (data-jx-layout).\n if (ctx.layoutWrapped && typeof def === \"object\" && (def as { $__layout?: unknown })?.$__layout) {\n return { kind: \"layout\" };\n }\n\n let mappedPath = path;\n\n // Strip the layout prefix so paths are relative to the original page document.\n // Page children render at indices [offset, offset+1, …] when the layout places siblings before\n // The <slot>, so subtract the offset to recover the page's 0-based child indices.\n if (ctx.layoutWrapped && ctx.pageContentPrefix) {\n const pfx = ctx.pageContentPrefix;\n if (path.length >= pfx.length && pfx.every((seg, i) => path[i] === seg)) {\n const rest = path.slice(pfx.length);\n const [containerIdx] = rest;\n mappedPath =\n typeof containerIdx === \"number\"\n ? [\"children\", containerIdx - (ctx.pageContentOffset ?? 0), ...rest.slice(1)]\n : [\"children\", ...rest];\n }\n }\n\n // Collapse repeater-perimeter template hops: for an array document path P, a render path of\n // `[...P, \"children\", 0, ...rest]` maps to `[...P, \"map\", ...rest]`. Loop for nested repeaters.\n if ((ctx.canvasMode === \"design\" || ctx.canvasMode === \"edit\") && ctx.arrayPaths.size > 0) {\n let changed = true;\n while (changed) {\n changed = false;\n for (let i = 1; i < mappedPath.length - 1; i++) {\n if (\n mappedPath[i] === \"children\" &&\n mappedPath[i + 1] === 0 &&\n ctx.arrayPaths.has(mappedPath.slice(0, i).join(\"/\"))\n ) {\n mappedPath = [...mappedPath.slice(0, i), \"map\", ...mappedPath.slice(i + 2)];\n changed = true;\n break;\n }\n }\n }\n }\n\n return { kind: \"path\", path: mappedPath };\n}\n\n/** Encode a document path for the `data-jx-path` attribute (preserves string-vs-number segments). */\nexport function serializeJxPath(path: JxPath): string {\n return JSON.stringify(path);\n}\n\n/** Decode a `data-jx-path` attribute back into a document path. */\nexport function parseJxPath(serialized: string): JxPath {\n return JSON.parse(serialized) as JxPath;\n}\n",
|
|
36
|
-
"/// <reference lib=\"dom\" />\n/**\n * Cross-frame drag GHOST (Phase 4c, commit 5). A single parent-realm `position:fixed` layer that\n * follows the raw pointer 1:1 during a canvas drag. It lives OUTSIDE the scaled `panzoom-wrap`\n * (D-3) — a sibling of `#canvas-wrap` on `<body>` — so it tracks `clientX`/`clientY` directly and\n * is NEVER subject to the canvas zoom transform (drawing it in the scaled overlay would shrink/grow\n * it with zoom). pragmatic's native drag image is suppressed per source via\n * `disableNativeDragPreview`, so this is the only drag affordance the user sees.\n *\n * One ghost is reused across drags + panels: {@link setDragGhost} shows it with a label and moves\n * it to a cursor; {@link clearDragGhost} hides it. The element is created lazily on first show so\n * the module has no import-time DOM side effect (and stays inert in tests until used).\n */\n\nlet ghostEl: HTMLElement | null = null;\n\n/** Lazily create (once) the fixed ghost element appended to `<body>`. */\nfunction ensureGhost(doc: Document): HTMLElement {\n if (ghostEl?.isConnected) {\n return ghostEl;\n }\n const el = doc.createElement(\"div\");\n el.className = \"jx-drag-ghost\";\n // Fixed + non-interactive + above the canvas; offset slightly from the cursor so it doesn't sit\n // Under the pointer and block hit-testing visuals. Positioned via left/top on each move.\n el.style.cssText =\n \"position:fixed;left:0;top:0;z-index:9999;pointer-events:none;display:none;\" +\n \"padding:2px 8px;border-radius:4px;font-size:12px;line-height:1.4;white-space:nowrap;\" +\n \"background:var(--accent,#3b82f6);color:var(--accent-fg,#fff);box-shadow:0 2px 8px rgba(0,0,0,0.25);\" +\n \"transform:translate(8px,8px)\";\n doc.body.append(el);\n ghostEl = el;\n return el;\n}\n\n/**\n * Show the ghost with `label`, positioned at the raw pointer (`x`,`y` in parent-viewport px). Safe\n * to call every pointermove; reuses the one element.\n */\nexport function setDragGhost(label: string, x: number, y: number, doc: Document = document): void {\n const el = ensureGhost(doc);\n el.textContent = label;\n el.style.left = `${x}px`;\n el.style.top = `${y}px`;\n el.style.display = \"block\";\n}\n\n/** Move the ghost to a new pointer position without changing its label (no-op when hidden). */\nexport function moveDragGhost(x: number, y: number): void {\n if (!ghostEl || ghostEl.style.display === \"none\") {\n return;\n }\n ghostEl.style.left = `${x}px`;\n ghostEl.style.top = `${y}px`;\n}\n\n/** Hide the ghost (between drags). The element is retained for reuse. */\nexport function clearDragGhost(): void {\n if (ghostEl) {\n ghostEl.style.display = \"none\";\n }\n}\n",
|
|
37
|
-
"/**\n * Constraints — generic interpreter for a format class's `$studio.elements` metadata.\n *\n * Element allowlists and nesting rules are declared by the format (.class.json), not the studio;\n * this module turns that declaration into the validation helpers the editing surfaces use. Replaces\n * the hard-coded markdown allowlist.\n */\n\nimport type { StudioFormatHints } from \"./format-host\";\n\ntype ElementsHints = NonNullable<StudioFormatHints[\"elements\"]>;\n\nexport interface NestingValidator {\n blockTags: ReadonlySet<string>;\n inlineTags: ReadonlySet<string>;\n allTags: ReadonlySet<string>;\n isVoid: (tag: string) => boolean;\n isTextOnly: (tag: string) => boolean;\n /** Whether childTag may appear inside parentTag (\"_root\" for the document root). */\n isValidChild: (parentTag: string, childTag: string) => boolean;\n}\n\n/** Build a nesting validator from a format's `$studio.elements` declaration. */\nexport function createNestingValidator(elements?: ElementsHints): NestingValidator {\n const blockTags = new Set(elements?.block);\n const inlineTags = new Set(elements?.inline);\n const allTags = new Set([...blockTags, ...inlineTags]);\n const voidTags = new Set(elements?.void);\n const textOnly = new Set(elements?.textOnly);\n const nesting = elements?.nesting ?? {};\n\n return {\n allTags,\n blockTags,\n inlineTags,\n isTextOnly: (tag) => textOnly.has(tag),\n isValidChild(parentTag, childTag) {\n const rule = nesting[parentTag];\n if (!rule) {\n return true;\n } // Unknown parents (directive components) allow anything\n\n if (rule.only) {\n return rule.only.includes(childTag);\n }\n\n const isBlock = blockTags.has(childTag);\n const isInline = inlineTags.has(childTag);\n const isDirective = !allTags.has(childTag);\n\n if (isBlock && rule.block) {\n return true;\n }\n if (isInline && rule.inline) {\n return true;\n }\n if (isDirective && rule.directive) {\n return true;\n }\n\n return false;\n },\n isVoid: (tag) => voidTags.has(tag),\n };\n}\n\n/**\n * The format's verdict on which of ITS tags can hold a text caret, as a plain `tag → boolean` map.\n *\n * A caret belongs in a tag that accepts inline children. The format's `nesting` declaration already\n * says exactly that, so nothing needs re-deriving from tag names:\n *\n * - `nesting[tag].inline === true` — the tag holds text. Headings, paragraphs, list items, cells.\n * - `nesting[tag]` present without it — a container. Markdown's `blockquote` is `inline: false`\n * because it holds paragraphs, so the caret belongs in the `<p>` inside it, not the quote; `ul`,\n * `table` and `pre` use `only: [...]` and hold no text at all.\n * - The tag is in the format's `inline` list — it is markup WITHIN a block, not a block. Without\n * this, clicking a link would make the link itself the active block, and typing would commit to\n * the anchor's path rather than the paragraph's.\n *\n * Only tags the format actually mentions appear here. A tag it says nothing about — HTML that\n * reaches the canvas through a directive — is left to the studio's own element metadata, so this\n * map is a set of OVERRIDES rather than a complete answer.\n *\n * Returned as a plain object because it crosses to the canvas frame with the render message.\n */\nexport function formatEditableVerdicts(elements?: ElementsHints): Record<string, boolean> {\n const verdicts: Record<string, boolean> = {};\n for (const [tag, rule] of Object.entries(elements?.nesting ?? {})) {\n // \"_root\" is the document itself, not an element.\n if (tag !== \"_root\") {\n verdicts[tag] = rule?.inline === true;\n }\n }\n for (const tag of elements?.inline ?? []) {\n verdicts[tag] = false;\n }\n return verdicts;\n}\n",
|
|
38
|
-
"/// <reference lib=\"dom\" />\n/**\n * Parent-side iframe canvas host — manages the `<iframe>` that renders a panel's document. It keeps\n * one iframe per canvas element (reused across re-renders), resolves the document parent-side via\n * {@link resolveCanvasDocument}, and posts it over the authenticated channel once the iframe\n * signals `ready`. The parent never reads the iframe's DOM (cross-origin bridge model); it only\n * sends.\n */\n\nimport { postMessageChannel } from \"./iframe-channel\";\nimport { canvasBaseOrigin } from \"./canvas-origin\";\nimport { getPreviewNavigateHandler } from \"./preview-navigate\";\nimport { resolveCanvasDocument } from \"./canvas-live-render\";\nimport {\n applyBlockMerge,\n applyInlineCommit,\n applyRangeReplace,\n applyInlinePropCommit,\n applyInlineInsert,\n applyInlineSplit,\n} from \"../editor/inline-edit-apply\";\nimport { canvasRectToParent, createOverlayLayer } from \"./iframe-overlay\";\nimport { serializeJxPath } from \"./path-mapping\";\nimport { getActivePanel, panelMediaToActiveMedia } from \"./canvas-helpers\";\nimport { panToParentRect } from \"./canvas-utils\";\nimport { clearDragGhost, moveDragGhost } from \"../panels/drag-ghost\";\nimport { applyDropInstruction } from \"../panels/dnd\";\nimport { rectOf } from \"../utils/geometry\";\nimport { effect, effectScope } from \"../reactivity\";\nimport {\n canvasPanels,\n canvasWrap,\n pathsEqual,\n projectState,\n renderOnly,\n updateCanvas,\n updateUi,\n} from \"../store\";\nimport { activeTab, workspace } from \"../workspace/workspace\";\nimport { formatEditableVerdicts } from \"../format/constraints\";\nimport { formatByName } from \"../format/format-host\";\nimport { collabState } from \"../collab/collab-state\";\nimport { getPlatform, hasPlatform } from \"../platform\";\nimport type {\n ApplyFormatIntent,\n CanvasMode,\n DragSrcKind,\n DropPreview,\n EvalExprResult,\n FileDropHit,\n IframeToParent,\n InsertZone,\n NodeHit,\n ParentToIframe,\n SelectionSnapshot,\n SerializedKey,\n WireDocOp,\n} from \"./iframe-protocol\";\nimport type { IframeChannel } from \"./iframe-channel\";\nimport type { OverlayLayer, OverlayPlacement } from \"./iframe-overlay\";\nimport type { SlashCommand } from \"../editor/inline-edit\";\nimport type { Tab } from \"../tabs/tab\";\nimport type { JxExpressionNode, JxMutableNode } from \"@jxsuite/schema/types\";\n\n/** A rect in PARENT coordinates (overlay-local from {@link canvasRectToParent}, same field shape). */\ntype ParentRect = OverlayPlacement;\n\ninterface HostState {\n iframe: HTMLIFrameElement;\n /** The `.canvas-panel-canvas` element hosting the iframe + overlay (the WeakMap key). */\n canvasEl: HTMLElement;\n channel: IframeChannel<ParentToIframe, IframeToParent>;\n /**\n * The resolved canvasUrl this iframe was built with — so a host built early with the default URL\n * is rebuilt once the platform's loopback canvasUrl becomes available (electrobun resolves it\n * async).\n */\n canvasUrl: string;\n ready: boolean;\n pending: ParentToIframe | null;\n overlay: OverlayLayer;\n /** Document path of the current selection (mirrors `session.selection`), for hover de-dupe. */\n selectionPath: (string | number)[] | null;\n /** Id of the most recent selection `measure` request, so stale `geometry` replies are dropped. */\n selReqId: number;\n /** Id of the most recent presence `measure` request (allocated from the selReqId counter). */\n presenceReqId: number;\n /** Serialized peer path → presence box meta for the in-flight presence measure. */\n presenceMeta: Map<string, { color: string; label: string }>;\n /** Whether an inline-edit session is live in this host's iframe (drives the format toolbar). */\n editing: boolean;\n /** The prop a live plain session edits (prop-bound text) — null for rich sessions/none. */\n editingProp: string | null;\n /** The latest selection snapshot from this host's iframe (active tags + caret rect + link). */\n snapshot: SelectionSnapshot | null;\n /** Highest snapshot `seq` seen, so stale (re-ordered) snapshots are dropped. */\n lastSnapshotSeq: number;\n /** The last non-null selection rect drawn (parent/overlay coords) — toolbar position fallback. */\n lastSelectionRect: ParentRect | null;\n /**\n * The gen of the render/patch this iframe's DOM currently reflects (set from `renderComplete`/\n * `patchComplete`). Cross-frame drag replies (`dragOver`/`dropResult`) are dropped unless their\n * `gen` matches, so a drop computed against a superseded render is never applied (Phase 4c).\n */\n lastRenderedGen: number;\n /**\n * The insertion \"+\" zone the overlay button currently anchors to (the iframe posts it on hover);\n * captured here so the button's click handler runs the slash-menu → mutateInsertNode flow against\n * the same parentPath/index. Null when no \"+\" is shown.\n */\n insertZone: InsertZone | null;\n /**\n * Grace timer (SALVAGED HIDE_DELAY) so a `null` zone post (cursor crossed mid-element on its way\n * to the button) doesn't yank the \"+\" before the author reaches it; cancelled on re-show / button\n * mouseenter. Null when not pending.\n */\n insertHideTimer: ReturnType<typeof setTimeout> | null;\n /**\n * Whether the cursor is currently ON the \"+\" (button mouseenter → true, mouseleave → false).\n *\n * The parent MUST hold this itself: the iframe cannot see the cursor once it lands on the button\n * (a parent-realm element overlaying the iframe), so it reports a full pointer-leave and posts\n * `insertZones: null` — which crosses the bridge ASYNCHRONOUSLY and therefore lands just AFTER\n * the button's own synchronous `mouseenter` cancelled the grace timer. Re-arming would then hide\n * the \"+\" ~300ms into the author's click, which is the whole flighty-affordance bug. The hide\n * checks this at FIRE time, so the ordering of the two signals no longer matters.\n */\n insertHover: boolean;\n /**\n * Id of the tab whose document this host's iframe DOM currently reflects. Adopted from\n * {@link HostState.pendingTabIds} ONLY when the render acks (`renderComplete`), so on the FIFO\n * channel any edit-session commit the iframe posts ahead of that ack still routes to the tab the\n * session belonged to. Doc-mutating bridge messages (editCommit/editSplit/editInsert/dropResult)\n * resolve their target tab from THIS — never from `activeTab` at message time, which may have\n * changed while the message was in flight (the cross-document bleed).\n */\n tabId: string | null;\n /** Tab id keyed by render gen for posted-but-unacked renders; adopted on `renderComplete`. */\n pendingTabIds: Map<number, string | null>;\n /**\n * A split/insert re-entry deferred until this host's DOM contains the new element: a surgical\n * patch acks (`patchComplete`) at the SAME gen the host already reflects, an escalated full\n * render acks (`renderComplete`) at a bumped one — both satisfy `gen >= minGen`. An immediate\n * `enterEdit` would race the escalated ASYNC render and silently fail to find the element.\n */\n pendingEnterEdit: { path: (string | number)[]; minGen: number; offset?: number } | null;\n /**\n * Stylebook capability (set by {@link mountStylebookCanvas}, cleared by page mounts). The specimen\n * doc's paths decode to TAGS, not tab-document paths: hits route to the injected stylebook\n * handler instead of `session.selection`, the selection watcher measures the selected tag's card,\n * and the document-editing affordances (insert \"+\", context menu, grab-drags) are ignored for\n * this host.\n */\n stylebook: {\n pathToTag: ReadonlyMap<string, string>;\n tagToCardPath: ReadonlyMap<string, (string | number)[]>;\n } | null;\n /** Measure-request id of an in-flight pan-to-card (stylebook); -1 when none. */\n panReqId: number;\n}\n\n/**\n * Opaque drag-target host handle for the coordinator bridge. The bridge passes it back to the\n * session API ({@link beginDragSession}/{@link hostDragGeometry}/{@link postDragMessage}) without\n * reading its fields.\n */\nexport type DragHost = HostState;\n\nconst hosts = new WeakMap<HTMLElement, HostState>();\n\n/** Every live host, so the selection watcher can re-measure each one when selection changes. */\nconst liveHosts = new Set<HostState>();\n\n// ─── Cross-frame drag session (Phase 4c) ────────────────────────────────────────\n// The parent owns the drag session id and the source data (which never crosses the wire). The\n// Coordinator bridge drives the session through the exported API below; the host's dragOver/dropResult\n// Handlers stale-gate replies by `currentDragSeq` and the target host's `lastRenderedGen`.\n\n/** Monotonic session id, bumped on each {@link beginDragSession}. Stale replies carry an older seq. */\nlet currentDragSeq = 0;\n\n/** Parent-retained source data keyed by `dragSeq` (the block fragment never crosses the boundary). */\nconst retainedSrcData = new Map<number, Record<string, unknown>>();\n\n/**\n * The last session whose cursor-carrying `dragOver` arrived FROM an iframe, and when. While a\n * parent-originated drag is over the canvas, the native dragover/drop stream is delivered to the\n * IFRAME (not the parent), so the iframe drives the session's dragOvers and its native drop posts\n * the dropResult. The coordinator checks {@link sawIframeDragOver} in its `onDrop` to know the\n * parent's own drop location is frame-local garbage and the in-flight dropResult is authoritative.\n */\nlet lastIframeDragOverSeq = -1;\nlet lastIframeDragOverAt = 0;\n\n/**\n * How recently (ms) an iframe-driven dragOver still marks the iframe as owning the stream. Native\n * dragover re-fires ~350ms even with a stationary cursor, so an iframe the cursor is still over\n * stays fresh; once the cursor moves back to parent chrome (e.g. drops on the block-action-bar,\n * which overlays the iframe) the iframe stream stops and the parent's drop coords are trusted\n * again.\n */\nconst IFRAME_DRAGOVER_FRESH_MS = 600;\n\n/** Whether the iframe recently drove a `dragOver` for session `seq` (see above). */\nexport function sawIframeDragOver(seq: number): boolean {\n return (\n lastIframeDragOverSeq === seq && Date.now() - lastIframeDragOverAt <= IFRAME_DRAGOVER_FRESH_MS\n );\n}\n\n// ─── Live expression preview (M6) ───────────────────────────────────────────────\n// The parent asks a live iframe to evaluate expression nodes against its LIVE resolved scope and\n// Correlates the `evalResult` reply by reqId (the measure/geometry precedent), gen-gating it so a\n// Reply computed against a superseded render never paints badges.\n\n/** Monotonic eval request id (shared across hosts; stale replies carry an older/unknown id). */\nlet evalReqId = 0;\n\n/**\n * One-shot: let automatic `$prototype: \"Request\"` entries fetch on the NEXT page render even in\n * edit/design mode.\n *\n * Those fetches are suppressed outside preview because a full render re-resolves every state entry,\n * so an escalating authoring action would issue a request per render. But the Data activity's\n * Refresh exists to re-fire them on demand — its documented purpose — so it arms this flag and the\n * next render consumes it. Deliberately one-shot: a subsequent escalation must not inherit it.\n */\nlet _allowAutoRequestsOnce = false;\n\n/**\n * Open a preview link's target for real.\n *\n * Resolved against the CANVAS's origin, not the editor's: the canvas iframe is served from the\n * project's own origin so relative `src`/`href` resolve the way they will in production, and the\n * editor shell may sit on a different origin entirely (a deep `/edit/:owner/:repo` path in the\n * cloud). Resolving against `location` would send a root-relative `/about` to the wrong host.\n */\nfunction openPreviewHref(href: string, state: HostState): void {\n let resolved: URL;\n try {\n resolved = new URL(href, state.iframe.src || canvasBaseOrigin());\n } catch {\n return; // Unparseable even against a base — nothing sensible to open.\n }\n /*\n * Scheme allowlist. A page can carry any href, and handing `javascript:` or `data:` to\n * `window.open` would execute it — in the EDITOR's origin, since the shell is the opener. Web pages\n * and the contact affordances real sites use are all that Preview needs to follow.\n */\n if (![\"http:\", \"https:\", \"mailto:\", \"tel:\"].includes(resolved.protocol)) {\n return;\n }\n const url = resolved.href;\n const override = getPreviewNavigateHandler();\n if (override) {\n override(url);\n return;\n }\n window.open(url, \"_blank\", \"noopener,noreferrer\");\n}\n\n/** Arm the next page render to allow automatic request fetches (Data activity Refresh). */\nexport function allowAutoRequestsOnNextRender(): void {\n _allowAutoRequestsOnce = true;\n}\n\nfunction consumeAllowAutoRequests(): boolean {\n const armed = _allowAutoRequestsOnce;\n _allowAutoRequestsOnce = false;\n return armed;\n}\n\n/** Pending eval resolvers keyed by reqId; a timeout or stale reply resolves null. */\nconst pendingEvals = new Map<number, (results: EvalExprResult[] | null) => void>();\n\n/** How long (ms) the parent waits for an `evalResult` before falling back to the snapshot. */\nexport const EVAL_TIMEOUT_MS = 300;\n\n/**\n * Post an `evalExpr` request to the live, ready iframe host rendering `tabId`'s document and\n * resolve with its results. Resolves `null` when no such host exists (caller falls back to the\n * snapshot evaluator immediately), when no reply lands within `timeoutMs`, or when the reply's gen\n * shows it was computed against a superseded render.\n */\nexport function requestCanvasEval(\n tabId: string | null,\n exprs: { id: string; node: unknown }[],\n contextPath: (string | number)[] | null,\n timeoutMs: number = EVAL_TIMEOUT_MS,\n): Promise<EvalExprResult[] | null> {\n let target: HostState | null = null;\n for (const host of liveHosts) {\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n continue;\n }\n // Only a document host can answer (never a stylebook specimen catalog or a null-tab override\n // Doc like git-diff), and only the one whose iframe DOM reflects this tab's document.\n if (host.ready && !host.stylebook && tabId !== null && host.tabId === tabId) {\n target = host;\n break;\n }\n }\n if (!target) {\n return Promise.resolve(null);\n }\n evalReqId += 1;\n const reqId = evalReqId;\n // Expression nodes come off the reactive document — only plain values may cross postMessage.\n // oxlint-disable-next-line unicorn/prefer-structured-clone\n const wireExprs = JSON.parse(JSON.stringify(exprs)) as { id: string; node: JxExpressionNode }[];\n target.channel.post({\n contextPath: contextPath ? [...contextPath] : null,\n exprs: wireExprs,\n gen: target.lastRenderedGen,\n kind: \"evalExpr\",\n reqId,\n });\n return new Promise((resolve) => {\n const timer = setTimeout(() => {\n pendingEvals.delete(reqId);\n resolve(null);\n }, timeoutMs);\n pendingEvals.set(reqId, (results) => {\n clearTimeout(timer);\n resolve(results);\n });\n });\n}\n\n// ─── Pending-edit flush ─────────────────────────────────────────────────────────\n// Text reaches the document on an idle tick, so anything that reads the document as authoritative\n// Must first ask every live frame to commit what the caret has typed since. Without this, saving\n// Mid-sentence writes the file WITHOUT the words still sitting in the caret's block.\n\n/** Monotonic flush request id. */\nlet flushReqId = 0;\n\n/** Pending flush resolvers keyed by reqId; a timeout resolves anyway rather than blocking a save. */\nconst pendingFlushes = new Map<number, () => void>();\n\n/** How long (ms) the parent waits for a frame to acknowledge a flush before saving regardless. */\nexport const FLUSH_TIMEOUT_MS = 250;\n\n/**\n * Ask every live frame rendering `tabId` to commit its pending text, and resolve once they have all\n * acknowledged (or the timeout elapses — a save must never hang on an unresponsive frame).\n */\nexport function flushCanvasEdits(\n tabId: string | null,\n timeoutMs: number = FLUSH_TIMEOUT_MS,\n): Promise<void> {\n const targets: HostState[] = [];\n for (const host of liveHosts) {\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n continue;\n }\n if (host.ready && !host.stylebook && tabId !== null && host.tabId === tabId) {\n targets.push(host);\n }\n }\n if (targets.length === 0) {\n return Promise.resolve();\n }\n return new Promise((resolve) => {\n let outstanding = targets.length;\n const timer = setTimeout(() => {\n for (const id of ids) {\n pendingFlushes.delete(id);\n }\n resolve();\n }, timeoutMs);\n const settle = () => {\n outstanding -= 1;\n if (outstanding === 0) {\n clearTimeout(timer);\n resolve();\n }\n };\n const ids: number[] = [];\n for (const host of targets) {\n flushReqId += 1;\n const reqId = flushReqId;\n ids.push(reqId);\n pendingFlushes.set(reqId, settle);\n host.channel.post({ kind: \"flushEdits\", reqId });\n }\n });\n}\n\n/** The host backing a given canvas element (or null), for the coordinator's host resolution. */\nexport function hostForCanvas(canvasEl: HTMLElement): HostState | null {\n return hosts.get(canvasEl) ?? null;\n}\n\n/**\n * Resolve the live host whose iframe's parent-viewport rect ({@link rectOf}) contains `cursor`.\n * Used by the coordinator to pick the drop target by pointer position (NOT the active panel), so a\n * drag over any panel's canvas targets that panel. Returns null when the cursor is over no live\n * iframe.\n */\nexport function liveDragHostAt(cursor: { x: number; y: number }): HostState | null {\n for (const host of liveHosts) {\n if (!host.iframe.isConnected) {\n continue;\n }\n const r = rectOf(host.iframe);\n if (cursor.x >= r.left && cursor.x <= r.right && cursor.y >= r.top && cursor.y <= r.bottom) {\n return host;\n }\n }\n return null;\n}\n\n/**\n * Begin a drag session against `host`: bump the session id, retain `srcData` (keyed by the new\n * seq), and post `dragStart` with the source kind and the host's current rendered gen. Returns the\n * seq so the coordinator can tag subsequent move/drop posts.\n */\nexport function beginDragSession(\n host: HostState,\n src: DragSrcKind,\n srcData: Record<string, unknown>,\n): number {\n currentDragSeq += 1;\n retainedSrcData.set(currentDragSeq, srcData);\n // The src crosses postMessage: plain-copy the path so a reactive-proxy array (e.g. a live\n // Selection fed through a drag source) can't DataCloneError the structured clone. Test fake\n // Channels pass messages by reference and never exercise the clone, so guard at the boundary.\n const wireSrc: DragSrcKind =\n src.type === \"tree-node\" ? { path: [...src.path], type: \"tree-node\" } : { type: src.type };\n host.channel.post({\n dragSeq: currentDragSeq,\n gen: host.lastRenderedGen,\n kind: \"dragStart\",\n src: wireSrc,\n });\n return currentDragSeq;\n}\n\n/**\n * Adopt an IFRAME-DRIVEN (flow 3) drag session: the iframe already owns the pointer it started and\n * drives the whole gesture, so the parent does NOT post a `dragStart` — it only sets the\n * authoritative `currentDragSeq` to the iframe's seq and retains the (path-only) source data keyed\n * by it, so the iframe's `dragOver`/`dropResult` (which carry that same seq) pass the parent's seq\n * gate and the drop applies with the retained source. Returns the adopted seq.\n */\nexport function adoptDragSession(\n _host: HostState,\n _src: DragSrcKind,\n srcData: Record<string, unknown>,\n seq: number,\n): number {\n currentDragSeq = seq;\n retainedSrcData.set(seq, srcData);\n return seq;\n}\n\n/** The current drag session id, for the coordinator to tag its move/drop posts. */\nexport function currentDragSession(): number {\n return currentDragSeq;\n}\n\n/**\n * The EMPIRICAL zoom scale for `host`'s iframe — `rectOf(iframe).width / iframe.clientWidth` (D-2),\n * read FRESH so a pan/zoom mid-drag is reflected. NOT `effectiveZoom()` (a separate path that can\n * desync). The matching iframe parent-viewport rect is returned so the cursor map cancels the pan.\n */\nexport function hostDragGeometry(host: HostState): {\n scale: number;\n rect: { left: number; top: number };\n} {\n const rect = rectOf(host.iframe);\n const scale = host.iframe.clientWidth > 0 ? rect.width / host.iframe.clientWidth : 1;\n return { rect, scale };\n}\n\n/**\n * Pin the `.canvas-panel-viewport` (the white \"page\" surface, the canvas element's parent) to the\n * SCALED content height when edit-mode content zoom is active. A `transform: scale()` on the canvas\n * element rescales its painted box but never its ancestor's auto-height, so without this write the\n * viewport background would stay sized to the UN-zoomed iframe height. The scale is read from the\n * canvas element's own inline transform (written only by `applyEditZoom`) — NOT from\n * {@link hostDragGeometry}, whose empirical ratio also reflects design mode's panzoom-wrap\n * transform, where the viewport must keep its unscaled auto height.\n */\nfunction syncEditZoomViewportHeight(state: HostState): void {\n const viewport = state.canvasEl.parentElement;\n if (!viewport) {\n return;\n }\n const match = /scale\\(([\\d.]+)\\)/.exec(state.canvasEl.style.transform);\n const scale = match ? Number(match[1]!) : 1;\n viewport.style.height = scale === 1 ? \"\" : `${state.iframe.offsetHeight * scale}px`;\n}\n\n/** Post a parent→iframe drag message to `host`'s channel (the coordinator builds it purely). */\nexport function postDragMessage(host: HostState, msg: ParentToIframe): void {\n if (!host.iframe.isConnected) {\n return;\n }\n host.channel.post(msg);\n}\n\n/** Abandon the current session's retained source data (e.g. a drop landed off-canvas). */\nexport function endDragSession(dragSeq: number): void {\n retainedSrcData.delete(dragSeq);\n}\n\n/** Hide `host`'s drop indicator (the coordinator's timeout fallback when no dropResult arrives). */\nexport function clearDropIndicator(host: HostState): void {\n host.overlay.setDropIndicator(null);\n}\n\n/**\n * The coordinator's handler for a NATIVE drag stream entering an iframe with no session bound there\n * (the `nativeDragEnter` message) — the bridge binds/migrates its live pragmatic session to that\n * host. Installed by the bridge to avoid a host→bridge import cycle.\n */\nlet nativeDragEnterHandler: ((host: HostState) => void) | null = null;\n\n/** Register the coordinator's native-drag-enter handler (see {@link nativeDragEnterHandler}). */\nexport function setNativeDragEnterHandler(fn: (host: HostState) => void): void {\n nativeDragEnterHandler = fn;\n}\n\n/** Delay (ms) before hiding the insertion \"+\" so the cursor can reach it (SALVAGED HIDE_DELAY). */\nexport const INSERT_HIDE_DELAY = 300;\n\n/**\n * The parent-realm insertion handler: open the slash menu anchored at the \"+\" `btn` and, on select,\n * run `transactDoc → mutateInsertNode` for the captured `zone`. Injected from studio.ts (which owns\n * the slash-menu / transact / defaultDef wiring) so this host module — and its tests — stay free of\n * the lit/Spectrum slash-menu and the mutation pipeline, mirroring the native-drag handler.\n */\nlet insertZoneClickHandler: ((btn: HTMLElement, zone: InsertZone) => void) | null = null;\n\n/** Register the slash-menu → mutateInsertNode handler the insertion \"+\" runs on click. */\nexport function setInsertZoneClickHandler(fn: (btn: HTMLElement, zone: InsertZone) => void): void {\n insertZoneClickHandler = fn;\n}\n\n/**\n * The parent-realm handler for an external file drop on a canvas (flow 5): upload the files and\n * either replace an existing image's source or insert new elements. Injected from studio.ts for the\n * same reason as {@link insertZoneClickHandler} — it reaches the platform and the mutation pipeline,\n * which this module and its tests stay free of.\n */\nlet fileDropHandler:\n | ((\n tab: Tab | null,\n files: File[],\n hit: FileDropHit | null,\n preview: DropPreview | null,\n ) => void | Promise<void>)\n | null = null;\n\n/** Register the upload → replace-or-insert handler for external file drops (see flow 5). */\nexport function setFileDropHandler(\n fn: (\n tab: Tab | null,\n files: File[],\n hit: FileDropHit | null,\n preview: DropPreview | null,\n ) => void | Promise<void>,\n): void {\n fileDropHandler = fn;\n}\n\n/**\n * Draw the affordance for a file drag hovering `state`'s canvas: a solid highlight over the image\n * the drop would REPLACE, or the usual insert indicator. Exactly one shows at a time — they answer\n * different questions, and both at once would be ambiguous.\n */\nfunction showFileDropAffordance(\n state: HostState,\n hit: FileDropHit | null,\n preview: DropPreview | null,\n): void {\n const replacing = hit ? isReplaceableTag(hit.tagName) : false;\n if (replacing && hit) {\n state.overlay.setDropIndicator(null);\n state.overlay.setReplaceTarget(canvasRectToParent(hit.rect));\n return;\n }\n state.overlay.setReplaceTarget(null);\n state.overlay.setDropIndicator(\n preview ? canvasRectToParent(preview.referenceRect) : null,\n preview?.edge,\n );\n}\n\n/** Hide both file-drop affordances on `state`. */\nfunction clearFileDropAffordance(state: HostState): void {\n state.overlay.setReplaceTarget(null);\n state.overlay.setDropIndicator(null);\n}\n\n/**\n * Whether a drop on this tag would replace a picture rather than insert beside it. Kept in sync\n * with `REPLACE_ATTRS` in editor/file-drop-action.ts, which owns the authoritative decision — this\n * is the display-only preview, so a custom element (whose verdict needs the component registry) is\n * shown as an insert and may still resolve to a replace on drop.\n */\nfunction isReplaceableTag(tagName: string): boolean {\n return tagName === \"img\" || tagName === \"video\" || tagName === \"source\";\n}\n\n/**\n * Accept file drops on the canvas element itself — the margin around the iframe box. The iframe\n * swallows everything over the rendered page (Chromium routes native drags to the frame under the\n * cursor), so this only ever sees a drop on the surrounding gutter, which appends to the document\n * root. Attached once per canvas element; the guard makes a re-mount idempotent.\n */\nfunction registerCanvasGutterDrop(canvasEl: HTMLElement, host: () => HostState | null): void {\n if (canvasEl.dataset.jxGutterDrop === \"1\") {\n return;\n }\n canvasEl.dataset.jxGutterDrop = \"1\";\n canvasEl.addEventListener(\"dragover\", (e: DragEvent) => {\n if (![...(e.dataTransfer?.types ?? [])].includes(\"Files\")) {\n return;\n }\n e.preventDefault();\n if (e.dataTransfer) {\n e.dataTransfer.dropEffect = \"copy\";\n }\n });\n canvasEl.addEventListener(\"drop\", (e: DragEvent) => {\n const files = e.dataTransfer?.files;\n const state = host();\n if (!files?.length || !state || state.stylebook) {\n return;\n }\n e.preventDefault();\n void fileDropHandler?.(hostTab(state), [...files], null, null);\n });\n}\n\n/** A canvas-originated slash-menu request, converted to PARENT-VIEWPORT coords by the host. */\nexport interface CanvasSlashRequest {\n rect: { left: number; top: number; bottom: number; width: number; height: number };\n filter: string;\n onSelect: (cmd: SlashCommand) => void;\n onDismiss: () => void;\n}\n\n/**\n * The parent-realm slash-menu surface the canvas iframe drives (show at a rect, navigate by key,\n * dismiss). Injected from studio.ts (which owns the lit/Spectrum menu) so this host module — and\n * its tests — stay free of it, mirroring {@link insertZoneClickHandler}.\n */\nexport interface CanvasSlashHandler {\n show: (req: CanvasSlashRequest) => void;\n nav: (key: string) => void;\n dismiss: () => void;\n}\n\nlet canvasSlashHandler: CanvasSlashHandler | null = null;\n\n/** Register the parent-realm slash-menu surface the canvas iframe drives. */\nexport function setCanvasSlashHandler(handler: CanvasSlashHandler): void {\n canvasSlashHandler = handler;\n}\n\n/**\n * The parent-realm context-menu surface for canvas right-clicks (show at parent-viewport coords,\n * dismiss on a canvas left-click). Injected from studio.ts, same DI pattern as the slash handler.\n */\nexport interface CanvasContextMenuHandler {\n show: (args: { path: (string | number)[] | null; clientX: number; clientY: number }) => void;\n dismiss: () => void;\n}\n\nlet canvasContextMenuHandler: CanvasContextMenuHandler | null = null;\n\n/** Register the parent-realm context-menu surface the canvas iframe drives. */\nexport function setCanvasContextMenuHandler(handler: CanvasContextMenuHandler): void {\n canvasContextMenuHandler = handler;\n}\n\n/**\n * The parent-realm stylebook selection handler: a hit in a stylebook host decodes to a TAG (or null\n * for chrome/empty space) plus the clicked panel's media, and routes here — never to\n * `session.selection`. Injected from studio.ts (which owns selectStylebookTag), same DI pattern as\n * the slash/context handlers.\n */\nlet stylebookHitHandler: ((tag: string | null, media: string | null) => void) | null = null;\n\n/** Register the stylebook tag-selection handler stylebook hosts route hits to. */\nexport function setStylebookHitHandler(\n fn: (tag: string | null, media: string | null) => void,\n): void {\n stylebookHitHandler = fn;\n}\n\n/**\n * Decode a stylebook hit path to its tag/compound: exact `pathToTag` lookup, then trim trailing\n * path segments pairwise (\"children\", i) so a hit on an unmapped descendant resolves to its nearest\n * mapped ancestor. Null = chrome/empty space (deselect).\n */\nfunction resolveStylebookTag(\n pathToTag: ReadonlyMap<string, string>,\n path: (string | number)[],\n): string | null {\n let p = [...path];\n for (;;) {\n const tag = pathToTag.get(serializeJxPath(p));\n if (tag) {\n return tag;\n }\n if (p.length < 2) {\n return null;\n }\n p = p.slice(0, -2);\n }\n}\n\n/**\n * The single host whose iframe currently owns the inline-edit session. Only one editable can be\n * active across all panels, so the parent format toolbar reads/writes through this (fixes the\n * multi-panel bug where two hosts' editing state could fight).\n */\nlet activeEditHost: HostState | null = null;\n\n/** Injected toolbar re-render (set by studio.ts → renderBlockActionBar); avoids a panel→host cycle. */\nlet toolbarRefresh: (() => void) | null = null;\n\n/** Register the parent toolbar's refresh fn (mirrors {@link setIframePatchEscalation}). */\nexport function setToolbarRefresh(fn: () => void): void {\n toolbarRefresh = fn;\n}\n\nlet selectionWatch: { stop: () => void } | null = null;\n\n/** Full-render escalation, injected by studio init (a patchError can't apply surgically). */\nlet patchEscalation: (() => void) | null = null;\n\n/** Register the full-render fallback the host invokes when the iframe reports a `patchError`. */\nexport function setIframePatchEscalation(fn: () => void): void {\n patchEscalation = fn;\n}\n\n/**\n * Post a surgical patch (value-carrying forward ops) to every ready live iframe host rendering\n * `tabId`'s document — a still-connected host showing another tab's doc must never fold a foreign\n * edit into its shadow doc. Returns how many hosts received it; the caller escalates to a full\n * render when that's zero (no host could apply the edit in place, so the suppressed full render\n * must run after all).\n */\nexport function postPatchToHosts(\n forwardOps: WireDocOp[],\n gen: number,\n tabId: string | null,\n): number {\n let posted = 0;\n for (const host of liveHosts) {\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n continue;\n }\n if (host.ready && host.tabId === tabId) {\n // Only the host that originated this edit already has the DOM the patch describes. A\n // Split-view panel on the same document did NOT type it and must render normally.\n const echoPaths = echoOrigin?.host === host ? echoOrigin.paths : undefined;\n host.channel.post(\n echoPaths\n ? { echoPaths, forwardOps, gen, kind: \"patch\" }\n : { forwardOps, gen, kind: \"patch\" },\n );\n posted += 1;\n }\n }\n return posted;\n}\n\n/**\n * The host whose own in-place commit is currently being applied, and the paths whose DOM it already\n * has right.\n *\n * Set for the duration of the `transactDoc` call inside the `editCommit` case and read by\n * {@link postPatchToHosts}, which runs synchronously inside it — the same begin/end shape\n * `transact.ts` uses for op recording. Never spans an await, so it cannot leak across messages.\n */\nlet echoOrigin: { host: HostState; paths: (string | number)[][] } | null = null;\n\n/**\n * Identifies the current visit to a block. Text commits sharing a run fold into ONE history entry —\n * typing commits on every pause, and without this a minute of writing would evict every structural\n * edit from the 100-entry ring and make ⌘Z walk back through the prose one pause at a time.\n */\nlet editRunSeq = 0;\n\n/**\n * Apply `fn` with `host`'s echo suppression armed for `paths`.\n *\n * This is what lets the caret survive its own edits: committing a block re-enters the patcher,\n * which would otherwise re-render the very subtree the user is typing in.\n */\nfunction withEchoSuppressed(host: HostState, paths: (string | number)[][], fn: () => void): void {\n echoOrigin = { host, paths };\n try {\n fn();\n } finally {\n echoOrigin = null;\n }\n}\n\n/** The tab whose document `state`'s iframe currently renders (null when unknown or closed). */\nfunction hostTab(state: HostState): Tab | null {\n return state.tabId ? (workspace.tabs.get(state.tabId) ?? null) : null;\n}\n\n/** Lazily start one reactive watcher that re-measures the selection in every live iframe host. */\nfunction ensureSelectionWatch(): void {\n if (selectionWatch) {\n return;\n }\n const scope = effectScope(true);\n scope.run(() => {\n effect(() => {\n const sel = activeTab.value?.session.selection ?? null;\n // Track the stylebook selection too: stylebook hosts measure the selected TAG's card\n // (session.selection is deliberately [] in stylebook mode).\n void activeTab.value?.session.ui.stylebookSelection;\n for (const host of liveHosts) {\n requestSelection(host, sel);\n }\n });\n });\n selectionWatch = { stop: () => scope.stop() };\n}\n\n/** Lazily start one reactive watcher that re-measures remote peers' selections in every host. */\nlet presenceWatchStarted = false;\nlet presenceTimer: ReturnType<typeof setTimeout> | null = null;\n\nfunction ensurePresenceWatch(): void {\n if (presenceWatchStarted) {\n return;\n }\n presenceWatchStarted = true;\n const scope = effectScope(true);\n scope.run(() => {\n effect(() => {\n const tab = activeTab.value;\n if (tab) {\n // Track the roster deeply enough that selection moves re-trigger.\n const { peers } = collabState(tab);\n void peers.map((peer) => JSON.stringify(peer.state.structuralSelection ?? null)).join(\"|\");\n }\n if (presenceTimer) {\n clearTimeout(presenceTimer);\n }\n // Debounced: awareness updates arrive per cursor move.\n presenceTimer = setTimeout(() => {\n presenceTimer = null;\n for (const host of liveHosts) {\n requestPresence(host);\n }\n }, 100);\n });\n });\n}\n\n/** Measure remote peers' selections in this host's iframe and draw colored boxes from the reply. */\nfunction requestPresence(host: HostState): void {\n if (host.stylebook || !host.ready || !host.iframe.isConnected) {\n return;\n }\n const tab = activeTab.value;\n const peers = tab ? collabState(tab).peers : [];\n host.presenceMeta.clear();\n const paths: (string | number)[][] = [];\n for (const peer of peers) {\n const { structuralSelection } = peer.state;\n if (!structuralSelection || peer.state.focusedPath !== tab?.documentPath) {\n continue;\n }\n const path = [...structuralSelection];\n paths.push(path);\n host.presenceMeta.set(JSON.stringify(path), {\n color: peer.state.user.color,\n label: peer.state.user.name ?? peer.state.user.login,\n });\n }\n if (paths.length === 0) {\n host.presenceReqId = -1;\n host.overlay.setPresence([]);\n return;\n }\n host.selReqId += 1;\n host.presenceReqId = host.selReqId;\n host.channel.post({ kind: \"measure\", paths, reqId: host.presenceReqId });\n}\n\n/** Track the selection on a host and ask its iframe to measure it (or clear the box when null). */\nfunction requestSelection(host: HostState, sel: (string | number)[] | null): void {\n if (host.stylebook) {\n requestStylebookSelection(host);\n return;\n }\n host.selectionPath = sel;\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n return;\n }\n if (!sel) {\n host.overlay.setSelection(null);\n return;\n }\n if (!host.ready) {\n return;\n }\n host.selReqId += 1;\n // Post a plain copy: `session.selection` is a reactive proxy, and only serializable values may\n // Cross the postMessage boundary.\n host.channel.post({ kind: \"measure\", paths: [[...sel]], reqId: host.selReqId });\n}\n\n/**\n * Stylebook variant of {@link requestSelection}: measure the SELECTED TAG's card (the specimen doc\n * addresses selection by tag, not by tab-document path). Cleared when no tag is selected or the tag\n * has no card in this host's generated doc.\n */\nfunction requestStylebookSelection(host: HostState): void {\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n return;\n }\n const tag = activeTab.value?.session.ui.stylebookSelection ?? null;\n const cardPath = tag ? host.stylebook?.tagToCardPath.get(tag) : undefined;\n if (!tag || !cardPath) {\n host.overlay.setSelection(null);\n return;\n }\n if (!host.ready) {\n return;\n }\n host.selReqId += 1;\n host.channel.post({ kind: \"measure\", paths: [[...cardPath]], reqId: host.selReqId });\n}\n\n/**\n * The default iframe document URL (a static shell that boots the slim canvas bundle). Used when the\n * platform does not provide its own canvasUrl — i.e. the dev server and electrobun keep this path.\n */\nconst DEFAULT_CANVAS_URL = \"/packages/studio/canvas.html\";\n\nfunction ensureHost(canvasEl: HTMLElement): HostState {\n // Read the platform's canvasUrl when one is registered; otherwise fall back to the default. The\n // Dev server leaves it unset, and some tests mount without a platform registered.\n const canvasUrl = (hasPlatform() ? getPlatform().canvasUrl : undefined) ?? DEFAULT_CANVAS_URL;\n const existing = hosts.get(canvasEl);\n if (existing) {\n if (existing.canvasUrl === canvasUrl) {\n return existing;\n }\n // The platform's loopback canvasUrl arrived after this host was built with the default URL\n // (electrobun resolves it async over RPC) — tear the early iframe down and rebuild against the\n // Right cross-origin origin.\n existing.channel.dispose();\n liveHosts.delete(existing);\n hosts.delete(canvasEl);\n }\n // ParentOrigin is the parent's real origin, passed into the iframe URL so the cross-origin iframe\n // Can target a postMessage back at it.\n const parentOrigin = location.origin;\n const token = crypto.randomUUID();\n // IframeOrigin is the iframe's own origin. For a RELATIVE canvasUrl (dev / chromium) it resolves to\n // The parent's location.origin (same-origin). For an absolute loopback canvasUrl (electrobun) it is\n // The loopback origin, so the channel accepts/targets the right cross-origin peer.\n const iframeOrigin = new URL(canvasUrl, location.href).origin;\n const iframe = document.createElement(\"iframe\");\n iframe.className = \"jx-canvas-iframe\";\n iframe.style.cssText =\n \"width:100%;min-height:480px;height:100%;border:0;display:block;background:#fff\";\n // Preserve any query already on canvasUrl (e.g. electrobun's ?win=7) and append the token (always)\n // Plus parentOrigin (conditionally — see below).\n const srcUrl = new URL(canvasUrl, location.href);\n srcUrl.searchParams.set(\"token\", token);\n // Pass parentOrigin into the iframe src ONLY when the PARENT is served over http(s) (dev / chromium\n // — same-origin, so the origin round-trips and the iframe can keep its acceptOrigin STRICT). For a\n // Non-http(s) parent (electrobun views://) OMIT it: a custom scheme may not surface as a postMessage\n // Origin (event.origin), so the iframe falls back to acceptOrigin '*' + the shared token (it logs\n // The warn) rather than silently stalling. The PARENT side here stays STRICT — acceptOrigin /\n // TargetOrigin are the real (loopback) iframeOrigin below, a gateable origin.\n if (location.protocol === \"http:\" || location.protocol === \"https:\") {\n srcUrl.searchParams.set(\"parentOrigin\", parentOrigin);\n }\n // Keep a relative canvasUrl relative in the src attribute (emit only path+query, not the resolved\n // Absolute URL) so the same-origin path stays byte-identical.\n iframe.src = iframeOrigin === parentOrigin ? `${srcUrl.pathname}${srcUrl.search}` : srcUrl.href;\n // Overlay boxes are positioned within the canvas element, so it must be a positioned ancestor.\n if (!canvasEl.style.position) {\n canvasEl.style.position = \"relative\";\n }\n const overlay = createOverlayLayer(document);\n canvasEl.replaceChildren(iframe, overlay.root);\n registerCanvasGutterDrop(canvasEl, () => hosts.get(canvasEl) ?? null);\n const channel = postMessageChannel<ParentToIframe, IframeToParent>({\n acceptOrigin: iframeOrigin,\n source: window,\n // Read contentWindow lazily: a freshly-navigated iframe swaps its window, so never capture it.\n target: {\n postMessage: (message, targetOrigin) =>\n iframe.contentWindow?.postMessage(message, targetOrigin),\n },\n targetOrigin: iframeOrigin,\n token,\n });\n\n const state: HostState = {\n canvasEl,\n canvasUrl,\n channel,\n editing: false,\n editingProp: null,\n iframe,\n insertHideTimer: null,\n insertHover: false,\n insertZone: null,\n lastRenderedGen: -1,\n lastSelectionRect: null,\n lastSnapshotSeq: 0,\n overlay,\n panReqId: -1,\n pending: null,\n pendingEnterEdit: null,\n pendingTabIds: new Map(),\n presenceMeta: new Map(),\n presenceReqId: -1,\n ready: false,\n selectionPath: null,\n selReqId: 0,\n snapshot: null,\n stylebook: null,\n tabId: null,\n };\n // The insertion \"+\" lives on the overlay (the one pointer-events:auto element there). Clicking it\n // Opens the slash menu → mutateInsertNode for the captured zone; mouseenter/leave record whether\n // The cursor is ON it, which both drives the grace timer and VETOES a hide the iframe's (async,\n // Later-arriving) leave post armed underneath the author — see {@link HostState.insertHover}.\n overlay.insertButton.addEventListener(\"click\", (e) => onInsertButtonClick(state, e));\n overlay.insertButton.addEventListener(\"mouseenter\", () => {\n state.insertHover = true;\n cancelInsertHide(state);\n });\n overlay.insertButton.addEventListener(\"mouseleave\", () => {\n state.insertHover = false;\n scheduleInsertHide(state);\n });\n channel.onMessage((msg) => handleMessage(state, msg));\n hosts.set(canvasEl, state);\n liveHosts.add(state);\n ensureSelectionWatch();\n ensurePresenceWatch();\n return state;\n}\n\n// ─── Insertion \"+\" affordance (cross-origin) ────────────────────────────────────\n\n/** Show the \"+\" for `zone`, capturing it on the host for the click handler; cancels any hide. */\nfunction showInsertZone(state: HostState, zone: InsertZone): void {\n cancelInsertHide(state);\n state.insertZone = zone;\n state.overlay.setInsertZone(canvasRectToParent(zone.rect), zone.edge);\n}\n\n/** Hide the \"+\" immediately and forget the captured zone. */\nfunction hideInsertZoneNow(state: HostState): void {\n cancelInsertHide(state);\n state.insertZone = null;\n state.insertHover = false;\n state.overlay.setInsertZone(null);\n}\n\n/**\n * Whether the cursor is on the \"+\" right now. {@link HostState.insertHover} is the primary signal;\n * the live `:hover` match is a belt-and-braces second one for a button that materialised UNDER an\n * already-stationary cursor (the browser updates `:hover` on that layout change, but a `mouseenter`\n * is not guaranteed).\n */\nfunction insertButtonHovered(state: HostState): boolean {\n const btn = state.overlay.insertButton;\n return state.insertHover || (typeof btn.matches === \"function\" && btn.matches(\":hover\"));\n}\n\n/**\n * Arm the grace timer to hide the \"+\" (SALVAGED HIDE_DELAY), replacing any pending one. The hide is\n * SKIPPED when the cursor turns out to be on the button by the time it fires — see\n * {@link HostState.insertHover} for why a cancel-on-mouseenter alone loses that race.\n */\nfunction scheduleInsertHide(state: HostState): void {\n cancelInsertHide(state);\n state.insertHideTimer = setTimeout(() => {\n state.insertHideTimer = null;\n if (insertButtonHovered(state)) {\n return;\n }\n hideInsertZoneNow(state);\n }, INSERT_HIDE_DELAY);\n}\n\n/** Cancel a pending grace-timer hide of the \"+\". */\nfunction cancelInsertHide(state: HostState): void {\n if (state.insertHideTimer !== null) {\n clearTimeout(state.insertHideTimer);\n state.insertHideTimer = null;\n }\n}\n\n/**\n * Click the \"+\": defer to the injected slash-menu → mutateInsertNode handler with the captured\n * zone.\n */\nfunction onInsertButtonClick(state: HostState, e: MouseEvent): void {\n e.stopPropagation();\n e.preventDefault();\n const zone = state.insertZone;\n if (!zone) {\n return;\n }\n insertZoneClickHandler?.(state.overlay.insertButton, zone);\n}\n\n/** Handle a message the iframe posted back: ready handshake, pointer hit/hover, measured geometry. */\nfunction handleMessage(state: HostState, msg: IframeToParent): void {\n switch (msg.kind) {\n case \"ready\": {\n state.ready = true;\n if (state.pending) {\n state.channel.post(state.pending);\n state.pending = null;\n }\n // Re-measure the current selection now that the iframe can answer.\n requestSelection(state, state.selectionPath);\n return;\n }\n case \"hit\": {\n // The clicked panel becomes the ACTIVE panel (same as clicking its header): getActivePanel(),\n // Header highlighting, and the style panel's breakpoint context all follow the click — and the\n // Block action bar anchors to the panel the selection was actually made in, not panel 0.\n let panelMedia: string | null = null;\n for (const p of canvasPanels) {\n if (hosts.get(p.canvas as HTMLElement) === state) {\n if (!p.mediaName?.startsWith(\"git-diff\")) {\n panelMedia = panelMediaToActiveMedia(p.mediaName);\n updateUi(\"activeMedia\", panelMedia);\n }\n break;\n }\n }\n // A canvas left-click closes an open context menu — its parent-realm outside-click listener\n // Can't see clicks inside the cross-origin iframe.\n canvasContextMenuHandler?.dismiss();\n // Stylebook host: the path decodes to a TAG (or null = deselect) and routes to the injected\n // Handler — specimen paths are NOT tab-document paths, so session.selection stays untouched.\n if (state.stylebook) {\n const tag = resolveStylebookTag(state.stylebook.pathToTag, msg.hit.path);\n stylebookHitHandler?.(tag, panelMedia);\n if (tag) {\n // Draw immediately from the posted rect; the selection watcher re-measures the CARD.\n const rect = canvasRectToParent(msg.hit.rect);\n state.overlay.setSelection(rect, `<${tag}>`);\n state.lastSelectionRect = rect;\n } else {\n state.overlay.setSelection(null);\n }\n return;\n }\n // A click in the canvas selects the node; the selection watcher redraws the box via `measure`.\n state.selectionPath = msg.hit.path;\n const tab = activeTab.value;\n if (tab) {\n tab.session.selection = msg.hit.path;\n }\n // Draw immediately from the posted rect for snappiness (the measure round-trip confirms it).\n {\n const rect = canvasRectToParent(msg.hit.rect);\n state.overlay.setSelection(rect);\n state.lastSelectionRect = rect;\n }\n return;\n }\n case \"hover\": {\n if (state.stylebook) {\n // Decode to a tag; suppress the box when hovering the selected tag (legacy parity).\n const tag = msg.hit ? resolveStylebookTag(state.stylebook.pathToTag, msg.hit.path) : null;\n const selected = activeTab.value?.session.ui.stylebookSelection ?? null;\n if (msg.hit && tag && tag !== selected) {\n state.overlay.setHover(canvasRectToParent(msg.hit.rect));\n } else {\n state.overlay.setHover(null);\n }\n return;\n }\n drawHover(state, msg.hit);\n return;\n }\n case \"insertZones\": {\n // Document-editing affordance — never for specimen catalogs (belt-and-braces with the\n // Iframe-side mode gate).\n if (state.stylebook) {\n return;\n }\n // The iframe recomputed the insertion \"+\" zones for the hovered node. Draw the \"+\" from the\n // First zone's rect (scale=1, D-2 — the overlay is inside the scaled panzoom-wrap); a null/empty\n // Set arms the grace timer rather than hiding immediately, so the cursor can reach the button.\n const zone = msg.zones?.[0] ?? null;\n if (zone) {\n showInsertZone(state, zone);\n } else {\n scheduleInsertHide(state);\n }\n return;\n }\n case \"geometry\": {\n // Remote-presence reply: draw one colored box per measured peer selection.\n if (msg.reqId === state.presenceReqId) {\n state.presenceReqId = -1;\n const items: { placement: OverlayPlacement; color: string; label: string }[] = [];\n for (const hit of msg.hits) {\n const meta = state.presenceMeta.get(JSON.stringify(hit.path));\n if (meta) {\n items.push({ ...meta, placement: canvasRectToParent(hit.rect) });\n }\n }\n state.overlay.setPresence(items);\n return;\n }\n // Pan-to-card reply (stylebook): convert the card's iframe rect to parent-viewport space by\n // The empirical zoom + iframe offset and center it.\n if (msg.reqId === state.panReqId) {\n state.panReqId = -1;\n const [hit] = msg.hits;\n if (hit) {\n const { rect: ifr, scale } = hostDragGeometry(state);\n panToParentRect({ height: hit.rect.height * scale, top: hit.rect.y * scale + ifr.top });\n }\n return;\n }\n if (msg.reqId === state.selReqId) {\n const [hit] = msg.hits;\n const rect = hit ? canvasRectToParent(hit.rect) : null;\n const sbTag = state.stylebook\n ? (activeTab.value?.session.ui.stylebookSelection ?? null)\n : null;\n state.overlay.setSelection(rect, sbTag ? `<${sbTag}>` : null);\n if (rect) {\n state.lastSelectionRect = rect;\n }\n }\n return;\n }\n case \"evalResult\": {\n // A live expression-preview reply (M6). Resolve the pending request by reqId (unknown ids —\n // Already timed out or from a torn-down request — are dropped), gen-gating it so values\n // Computed against a superseded render resolve null (the caller keeps the snapshot preview).\n const resolve = pendingEvals.get(msg.reqId);\n if (!resolve) {\n return;\n }\n pendingEvals.delete(msg.reqId);\n resolve(msg.gen === state.lastRenderedGen ? msg.results : null);\n return;\n }\n case \"renderComplete\": {\n // Adopt the tab identity this render was mounted with. host.tabId flips ONLY here — after any\n // Edit-session commit the iframe posted ahead of this ack on the FIFO channel — so a commit\n // Racing a tab switch still routes to the tab its session belonged to.\n if (state.pendingTabIds.has(msg.gen)) {\n state.tabId = state.pendingTabIds.get(msg.gen) ?? null;\n }\n for (const gen of state.pendingTabIds.keys()) {\n if (gen <= msg.gen) {\n state.pendingTabIds.delete(gen);\n }\n }\n onDomUpdated(state, msg.gen);\n return;\n }\n case \"patchComplete\": {\n // A patch never re-targets the host (tabId untouched) — only the DOM/geometry changed.\n onDomUpdated(state, msg.gen);\n return;\n }\n case \"renderError\": {\n // The render never landed — its pending identity must not be adopted by a later ack.\n state.pendingTabIds.delete(msg.gen);\n return;\n }\n case \"dataScope\": {\n // The iframe posted its resolved $defs snapshot right after renderComplete. Adopt it into the\n // Parent's canvas state so the data-explorer panel shows live data (buildScope moved into the\n // Iframe realm; the parent hard-codes scope:null at ready). Gate on the last-rendered gen so a\n // Snapshot from a superseded render can't clobber the current one, then re-render the left\n // Panel (which hosts the data-explorer) to reflect the new scope.\n if (msg.gen !== state.lastRenderedGen) {\n return;\n }\n updateCanvas({ scope: msg.scope });\n renderOnly(\"leftPanel\");\n return;\n }\n case \"contentHeight\": {\n // Size the iframe element to its document so the canvas never scrolls internally — the parent\n // Canvas pans/scrolls instead, every node stays inside the iframe box (hit-testable), and the\n // Overlay (drawn in canvas space) tracks it. The cssText's 480px `min-height` is a\n // Pre-measurement floor so an empty/short PAGE stays a usable canvas; a component DEFINITION\n // (fragment) instead hugs its content, so drop the floor for it once measured (else a short\n // Component leaves dead space below — pages keep the floor and stay tall via #jx-canvas-root).\n state.iframe.style.height = `${msg.height}px`;\n state.iframe.style.minHeight = msg.fragment ? \"0px\" : \"480px\";\n syncEditZoomViewportHeight(state);\n return;\n }\n case \"dragOver\": {\n // Display-only drop indicator (Phase 4c). Drop stale replies: a different drag session\n // (dragSeq) or a superseded render (gen). The indicator draw side uses scale=1 (D-2) — the\n // Overlay is inside the scaled panzoom-wrap, so the browser already applies the zoom.\n if (msg.dragSeq !== currentDragSeq) {\n return;\n }\n // A cursor-carrying dragOver means the IFRAME is driving the over-stream from its own events\n // (native routing or flow 3) — not merely replying to a parent-forwarded dragMove. Record it\n // BEFORE the gen gate: it's a fact about event routing, not render freshness.\n if (msg.cursor) {\n lastIframeDragOverSeq = msg.dragSeq;\n lastIframeDragOverAt = Date.now();\n }\n if (msg.gen !== state.lastRenderedGen) {\n return;\n }\n if (msg.preview) {\n state.overlay.setDropIndicator(\n canvasRectToParent(msg.preview.referenceRect),\n msg.preview.edge,\n );\n } else {\n state.overlay.setDropIndicator(null);\n }\n // Flow 3 (iframe-driven) posts a `cursor` in iframe-viewport coords: the parent has no pointer\n // Of its own during an iframe-originated drag, so position the ghost by FORWARD-converting the\n // Cursor to parent-viewport space (the inverse of parentCursorToIframe). Parent-driven flows\n // (1/2/4) omit `cursor` — the bridge moves their ghost from the raw parent pointer.\n if (msg.cursor) {\n const g = hostDragGeometry(state);\n moveDragGhost(msg.cursor.x * g.scale + g.rect.left, msg.cursor.y * g.scale + g.rect.top);\n }\n return;\n }\n case \"nativeDragEnter\": {\n if (state.stylebook) {\n return; // A specimen catalog is never a drop target.\n }\n // A parent-originated NATIVE drag crossed onto this iframe before any session bound it (the\n // Parent never sees a cursor inside the iframe rect) — let the bridge bind/migrate here.\n nativeDragEnterHandler?.(state);\n return;\n }\n case \"dragEnd\": {\n // The iframe cancelled a flow-3 drag locally (Escape). Tear down the indicator/ghost and\n // Release the retained source data so no drop is applied.\n state.overlay.setDropIndicator(null);\n clearDragGhost();\n retainedSrcData.delete(msg.dragSeq);\n return;\n }\n case \"dropResult\": {\n // The authoritative, freshly-computed drop (Phase 4c). Apply through the realm-agnostic\n // Mutation helper with the PARENT-retained source data, unless stale or empty.\n if (msg.dragSeq !== currentDragSeq || msg.gen !== state.lastRenderedGen) {\n return;\n }\n if (msg.instruction && msg.targetPath) {\n const srcData = retainedSrcData.get(msg.dragSeq);\n if (srcData) {\n applyDropInstruction(hostTab(state), { type: msg.instruction }, srcData, msg.targetPath);\n }\n }\n retainedSrcData.delete(msg.dragSeq);\n // The drop resolved (or was empty) — tear down the display affordances on this host.\n state.overlay.setDropIndicator(null);\n clearDragGhost();\n return;\n }\n case \"fileDragOver\": {\n if (state.stylebook) {\n return; // A specimen catalog is never a drop target.\n }\n showFileDropAffordance(state, msg.hit, msg.preview);\n return;\n }\n case \"fileDragLeave\": {\n clearFileDropAffordance(state);\n return;\n }\n case \"fileDrop\": {\n clearFileDropAffordance(state);\n if (state.stylebook) {\n return;\n }\n void fileDropHandler?.(hostTab(state), msg.files, msg.hit, msg.preview);\n return;\n }\n case \"patchError\": {\n // The iframe couldn't apply the edit surgically — fall back to a full render of the live doc.\n patchEscalation?.();\n return;\n }\n case \"forwardKey\": {\n // A global shortcut pressed while the iframe had focus — replay it for the editor's handler.\n redispatchKey(msg.event);\n return;\n }\n case \"forwardWheel\": {\n // A wheel over the iframe — replay it on canvasWrap so the editor's zoom/pan handler fires (the\n // Cursor is mapped from iframe-viewport coords to parent-viewport via this host's scale + offset).\n redispatchWheel(state, msg);\n return;\n }\n case \"editStart\": {\n // Inline editing began in this host's iframe. Only one editable is active across all panels —\n // Tear down any other host's editing state and make this the single active edit host.\n if (activeEditHost && activeEditHost !== state) {\n activeEditHost.editing = false;\n activeEditHost.editingProp = null;\n activeEditHost.snapshot = null;\n }\n activeEditHost = state;\n // Each visit to a block is one undoable edit. Bumping the run id here breaks the history\n // Coalescing run, so returning to the same paragraph later is a separate ⌘Z step.\n editRunSeq += 1;\n state.editing = true;\n state.editingProp = msg.prop ?? null;\n state.snapshot = null;\n state.lastSnapshotSeq = 0;\n toolbarRefresh?.();\n return;\n }\n case \"selectionChanged\": {\n // Drop stale (re-ordered) snapshots; otherwise store the latest and refresh the toolbar.\n if (msg.seq <= state.lastSnapshotSeq) {\n return;\n }\n state.lastSnapshotSeq = msg.seq;\n state.snapshot = msg;\n toolbarRefresh?.();\n return;\n }\n case \"flushComplete\": {\n const done = pendingFlushes.get(msg.reqId);\n if (done) {\n pendingFlushes.delete(msg.reqId);\n done();\n }\n return;\n }\n case \"editCommit\": {\n // Route to the tab this host's iframe renders — NOT activeTab, which may have changed while\n // The message was in flight (the cross-document bleed).\n const apply = () =>\n applyInlineCommit(hostTab(state), msg.path, msg.children, msg.textContent);\n // An in-place commit (the idle tick) leaves the caret in the block, so the echoed patch must\n // Not re-render it. A commit on release renders normally — the caret has already left.\n if (msg.inPlace) {\n withEchoSuppressed(state, [msg.path], apply);\n } else {\n apply();\n }\n return;\n }\n case \"editCommitProp\": {\n // A prop-bound plain session committed: persist into the instance's $props (same host-tab\n // Routing as editCommit; the unchanged-value no-op lives in the apply).\n //\n // A $props change re-renders the WHOLE component instance, which would tear out the nested\n // Editing host the caret is typing in — so an in-place commit is echo-suppressed exactly as a\n // Page block's is. The instance re-renders for real on release.\n const applyProp = () => applyInlinePropCommit(hostTab(state), msg.path, msg.prop, msg.value);\n if (msg.inPlace) {\n withEchoSuppressed(state, [msg.path], applyProp);\n } else {\n applyProp();\n }\n return;\n }\n case \"editMerge\": {\n // Joining two blocks removes one of them, so the caret has to be re-placed — at the SEAM,\n // Where the two blocks met, which is where the author's cursor visually was.\n const seam = applyBlockMerge(hostTab(state), msg.fromPath, msg.intoPath);\n if (seam) {\n deferEnterEdit(state, seam.path, seam.offset);\n }\n return;\n }\n case \"editRangeReplace\": {\n const caret = applyRangeReplace(hostTab(state), msg.from, msg.to, msg.between, msg.text);\n if (caret) {\n deferEnterEdit(state, caret.path, caret.offset);\n }\n return;\n }\n case \"editSplit\": {\n // The mutation lands now (surgical patch or escalated render); re-entry on the new paragraph\n // Is deferred until this host acks the DOM that contains it (see deferEnterEdit).\n deferEnterEdit(state, applyInlineSplit(hostTab(state), msg.path, msg.before, msg.after));\n return;\n }\n case \"editInsert\": {\n deferEnterEdit(state, applyInlineInsert(hostTab(state), msg.path, msg.cmd, msg.commitData));\n return;\n }\n case \"slashShow\": {\n // The iframe engine wants the slash menu at its edited element's rect (iframe-viewport) —\n // Convert to parent-viewport by the empirical zoom + iframe offset and show the real menu.\n // The select/dismiss callbacks post back over THIS host's channel, closing the loop.\n const { rect: ifr, scale } = hostDragGeometry(state);\n const left = msg.rect.x * scale + ifr.left;\n const top = msg.rect.y * scale + ifr.top;\n canvasSlashHandler?.show({\n filter: msg.filter,\n onDismiss: () => state.channel.post({ kind: \"slashDismissed\" }),\n onSelect: (cmd) => state.channel.post({ cmd: { ...cmd }, kind: \"slashSelect\" }),\n rect: {\n bottom: top + msg.rect.height * scale,\n height: msg.rect.height * scale,\n left,\n top,\n width: msg.rect.width * scale,\n },\n });\n return;\n }\n case \"slashNav\": {\n canvasSlashHandler?.nav(msg.key);\n return;\n }\n case \"slashDismiss\": {\n canvasSlashHandler?.dismiss();\n return;\n }\n case \"previewNavigate\": {\n openPreviewHref(msg.href, state);\n return;\n }\n case \"contextMenu\": {\n if (state.stylebook) {\n return; // The doc context menu's actions are meaningless for specimen paths.\n }\n // A canvas right-click — convert to parent-viewport coords and show the Jx element menu.\n const { rect: ifr, scale } = hostDragGeometry(state);\n canvasContextMenuHandler?.show({\n clientX: msg.x * scale + ifr.left,\n clientY: msg.y * scale + ifr.top,\n path: msg.path ? [...msg.path] : null,\n });\n return;\n }\n case \"editEnd\": {\n // Ignore a superseded late editEnd (a re-enter's stop→start can deliver a stale one): only act\n // When this host is still the one editing.\n if (!state.editing) {\n return;\n }\n state.editing = false;\n state.editingProp = null;\n state.snapshot = null;\n if (activeEditHost === state) {\n activeEditHost = null;\n }\n toolbarRefresh?.();\n break;\n }\n default: {\n break;\n }\n }\n}\n\n/**\n * Shared renderComplete/patchComplete bookkeeping: the DOM (and so all geometry) just changed —\n * re-measure the selection box, record the gen the DOM now reflects (cross-frame drag replies are\n * stale-gated against it, Phase 4c), drop the \"+\" (anchored to a now-stale rect), and flush a\n * deferred split/insert re-entry once the DOM containing the new element is live.\n */\nfunction onDomUpdated(state: HostState, gen: number): void {\n state.lastRenderedGen = gen;\n requestSelection(state, state.selectionPath);\n requestPresence(state);\n hideInsertZoneNow(state);\n if (state.pendingEnterEdit && gen >= state.pendingEnterEdit.minGen) {\n const { offset, path } = state.pendingEnterEdit;\n state.pendingEnterEdit = null;\n // Re-enter only when this host still shows the ACTIVE tab — a background tab's iframe renders a\n // Different doc, so re-entering there would grab the wrong element (the commit itself already\n // Landed in the right tab via hostTab routing).\n if (state.tabId !== null && state.tabId === workspace.activeTabId) {\n reenterEdit(state, path, offset);\n }\n }\n}\n\n/**\n * Defer re-entering inline editing on `path` until this host's DOM reflects the split/insert (see\n * {@link onDomUpdated}). `minGen` is the gen the host currently reflects: the surgical patch acks at\n * that same gen; an escalated full render acks at a bumped one — both satisfy `gen >= minGen`,\n * while a stale ack cannot. Latest-wins on overwrite.\n */\nfunction deferEnterEdit(state: HostState, path: (string | number)[], offset?: number): void {\n state.pendingEnterEdit = {\n minGen: state.lastRenderedGen,\n path: [...path],\n ...(offset === undefined ? {} : { offset }),\n };\n}\n\n/** Ask the host's iframe to (re-)enter inline editing on `path` (a plain copy crosses the bridge). */\nfunction reenterEdit(state: HostState, path: (string | number)[], offset?: number): void {\n state.channel.post({\n kind: \"enterEdit\",\n path: [...path],\n ...(offset === undefined ? {} : { offset }),\n });\n}\n\n/**\n * Replay a forwarded wheel on `canvasWrap` so the editor's zoom/pan handler fires. The forwarded\n * cursor is in iframe-viewport CSS px; map it to parent-viewport space by the host's empirical zoom\n * scale ({@link hostDragGeometry}) plus the iframe's on-screen offset, so ctrl+wheel zooms toward\n * the real cursor. A synthetic event triggers no native scroll, which is fine — the handler does\n * the work.\n */\nfunction redispatchWheel(\n state: HostState,\n msg: Extract<IframeToParent, { kind: \"forwardWheel\" }>,\n): void {\n const { rect, scale } = hostDragGeometry(state);\n canvasWrap.dispatchEvent(\n new WheelEvent(\"wheel\", {\n bubbles: true,\n cancelable: true,\n clientX: rect.left + msg.x * scale,\n clientY: rect.top + msg.y * scale,\n ctrlKey: msg.ctrlKey,\n deltaX: msg.deltaX,\n deltaY: msg.deltaY,\n metaKey: msg.metaKey,\n shiftKey: msg.shiftKey,\n }),\n );\n}\n\n/** Rebuild and dispatch a synthetic `keydown` on the editor document from a forwarded keystroke. */\nfunction redispatchKey(event: SerializedKey): void {\n document.dispatchEvent(\n new KeyboardEvent(\"keydown\", {\n altKey: event.altKey,\n bubbles: true,\n cancelable: true,\n code: event.code,\n ctrlKey: event.ctrlKey,\n key: event.key,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n }),\n );\n}\n\n/** Draw the hover box, hidden when there's no hover or it coincides with the current selection. */\nfunction drawHover(state: HostState, hit: NodeHit | null): void {\n if (!hit || pathsEqual(hit.path, state.selectionPath)) {\n state.overlay.setHover(null);\n return;\n }\n state.overlay.setHover(canvasRectToParent(hit.rect));\n}\n\n/**\n * Render `doc` into the iframe canvas mounted in `canvasEl`: resolve the document parent-side and\n * post it (queued until the iframe is `ready`).\n *\n * `widthPx` makes the panel's breakpoint width an EXPLICIT lever on the iframe element itself (only\n * `style.width` is touched — the rest of cssText, incl. `min-height:480px; height:100%`, is kept).\n * The iframe is a real viewport, so its CSS width is the layout viewport `@media` evaluates\n * against; setting it here survives iframe reuse and any future container-styling change. Null\n * (edit-mode / git-diff / full-width panels) falls back to `100%`. The iframe stays FIXED-HEIGHT —\n * content scrolls inside it like a real device viewport; narrowing the width does not auto-grow\n * it.\n *\n * `tabId` is the identity of the tab whose document this render shows (null for override docs like\n * git-diff, whose iframes must never route doc mutations anywhere). It is recorded against `gen`\n * and adopted into `host.tabId` only when the iframe acks the render — see\n * {@link HostState.tabId}.\n */\nexport async function mountIframeCanvas(\n gen: number,\n doc: JxMutableNode,\n canvasEl: HTMLElement,\n widthPx?: number | null,\n tabId: string | null = null,\n): Promise<void> {\n const state = ensureHost(canvasEl);\n state.pendingTabIds.set(gen, tabId);\n // A page mount clears any stylebook capability from a previous mode's reuse of this host.\n state.stylebook = null;\n state.iframe.style.width = widthPx ? `${widthPx}px` : \"100%\";\n // Always resolve and post the latest render. The iframe drops stale generations itself (via its\n // Own `latestGen`), so the parent must NOT gate on `view.renderGeneration`: during boot many\n // Renders fire and the generation is usually stale by the time resolution finishes, which would\n // Otherwise drop every post.\n const resolved = await resolveCanvasDocument(doc);\n // The doc must be structured-cloneable to cross postMessage. A Jx document is JSON by contract, so\n // A JSON round-trip (NOT structuredClone, which would throw) drops residual functions / reactive\n // Proxy artifacts that would otherwise raise DataCloneError and silently drop the entire message.\n // oxlint-disable-next-line unicorn/prefer-structured-clone\n const cloneableDoc = JSON.parse(JSON.stringify(resolved.renderDoc)) as unknown;\n // The RAW page doc (forward-op + data-jx-path coordinate space) crosses as the iframe's shadow doc.\n // oxlint-disable-next-line unicorn/prefer-structured-clone\n const cloneableShadow = JSON.parse(JSON.stringify(doc)) as unknown;\n // Which tags can hold a caret depends on the document's vocabulary, so the format's verdicts ride\n // With the render rather than being baked into the frame. Absent for a native document, where the\n // Studio's own element metadata answers on its own.\n // Resolve from THIS render's tab, not `state.tabId` — that is only adopted when the render is\n // Acknowledged, so at post time it still names the previous render's document (null on first\n // Mount, which is exactly the render that matters).\n const renderTab = tabId ? (workspace.tabs.get(tabId) ?? null) : null;\n const formatElements = formatByName(renderTab?.doc.sourceFormat)?.studio?.elements;\n const editableTags = formatElements ? formatEditableVerdicts(formatElements) : undefined;\n const message: ParentToIframe = {\n colorScheme: activeSchemeWire(),\n doc: cloneableDoc,\n docBase: resolved.docBase ?? `${canvasBaseOrigin()}/`,\n gen,\n kind: \"render\",\n mapperCtx: resolved.mapperCtx,\n mode: resolved.mapperCtx.canvasMode as CanvasMode,\n shadowDoc: cloneableShadow,\n siteStyle: resolved.siteStyle,\n ...(editableTags ? { editableTags } : {}),\n ...(consumeAllowAutoRequests() ? { allowAutoRequests: true } : {}),\n };\n // A mode switch to preview mid-split must not start an edit session in the preview render.\n if (message.mode === \"preview\") {\n state.pendingEnterEdit = null;\n }\n if (state.ready) {\n state.channel.post(message);\n } else {\n state.pending = message;\n }\n}\n\n/**\n * Mount a STYLEBOOK canvas: post the pre-generated specimen document (no `resolveCanvasDocument` —\n * the generator already merged the effective style/media and there is no layout/page mapping) and\n * arm the host's stylebook capability (tag-addressed hits/selection). Mounted with a NULL tab\n * identity: specimen paths are not tab-document paths, so any doc-mutating bridge message from this\n * host must drop — the existing null-tabId routing does exactly that.\n */\nexport function mountStylebookCanvas(\n gen: number,\n generated: {\n doc: JxMutableNode;\n pathToTag: ReadonlyMap<string, string>;\n tagToCardPath: ReadonlyMap<string, (string | number)[]>;\n },\n canvasEl: HTMLElement,\n widthPx: number | null,\n): void {\n const state = ensureHost(canvasEl);\n state.pendingTabIds.set(gen, null);\n state.stylebook = { pathToTag: generated.pathToTag, tagToCardPath: generated.tagToCardPath };\n state.pendingEnterEdit = null;\n state.iframe.style.width = widthPx ? `${widthPx}px` : \"100%\";\n // Two independent plain clones: the iframe renders `doc` and folds styleUpdates into `shadowDoc`\n // (and fake test channels pass messages by reference, so sharing one object would alias them).\n // oxlint-disable-next-line unicorn/prefer-structured-clone\n const cloneableDoc = JSON.parse(JSON.stringify(generated.doc)) as unknown;\n // oxlint-disable-next-line unicorn/prefer-structured-clone\n const cloneableShadow = JSON.parse(JSON.stringify(generated.doc)) as unknown;\n const message: ParentToIframe = {\n colorScheme: activeSchemeWire(),\n doc: cloneableDoc,\n docBase: `${canvasBaseOrigin()}/`,\n gen,\n kind: \"render\",\n mapperCtx: {\n arrayPaths: [],\n canvasMode: \"stylebook\",\n layoutWrapped: false,\n pageContentOffset: null,\n pageContentPrefix: null,\n },\n mode: \"stylebook\",\n shadowDoc: cloneableShadow,\n // The generator already merged projectConfig.style into the doc's own style block — passing\n // SiteStyle too would double-apply it.\n siteStyle: null,\n };\n if (state.ready) {\n state.channel.post(message);\n } else {\n state.pending = message;\n }\n}\n\n/** The active tab's forced preview scheme as wire data (auto → null). */\nfunction activeSchemeWire(): \"light\" | \"dark\" | null {\n const s = activeTab.value?.session.ui.previewColorScheme;\n return s === \"light\" || s === \"dark\" ? s : null;\n}\n\n/**\n * Flip the color-scheme preview on every ready host (page and stylebook alike — both render\n * scheme-aware CSS). A pure attribute write iframe-side: no render, no patch, no gen.\n */\nexport function postColorSchemeToLiveHosts(scheme: \"light\" | \"dark\" | null): void {\n for (const host of liveHosts) {\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n continue;\n }\n if (host.ready) {\n host.channel.post({ kind: \"setColorScheme\", scheme });\n }\n }\n}\n\n/**\n * Push the project's current site style to every ready PAGE host as an in-place sheet replace (live\n * design-token editing — stylebook hosts pre-merge site style into the specimen doc and are\n * skipped). Render-free; the next full render carries the same style via its own siteStyle.\n */\nexport function postSiteStyleToLiveHosts(): void {\n const config = projectState?.projectConfig;\n if (!config) {\n return;\n }\n // Site config comes off a reactive store — only plain values may cross postMessage.\n // oxlint-disable-next-line unicorn/prefer-structured-clone\n const siteStyle = JSON.parse(JSON.stringify(config.style ?? null)) as Record<\n string,\n unknown\n > | null;\n // oxlint-disable-next-line unicorn/prefer-structured-clone\n const media = JSON.parse(JSON.stringify(config.$media ?? {})) as Record<string, string>;\n for (const host of liveHosts) {\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n continue;\n }\n if (host.ready && !host.stylebook) {\n host.channel.post({ kind: \"siteStyleUpdate\", media, siteStyle });\n }\n }\n}\n\n/**\n * Post a live style update to every ready stylebook host (gen-tagged per host so a stale update is\n * dropped iframe-side; the superseding render carries the same style). Returns how many hosts\n * received it — zero means no stylebook iframe is live yet and the caller should fall through to a\n * full render. Each post is followed by a selection re-measure so the box tracks the reflow.\n */\nexport function postStyleUpdateToStylebookHosts(style: Record<string, unknown>): number {\n let posted = 0;\n // Style objects come off the reactive doc — only plain values may cross postMessage.\n // oxlint-disable-next-line unicorn/prefer-structured-clone\n const cloneable = JSON.parse(JSON.stringify(style)) as Record<string, unknown>;\n for (const host of liveHosts) {\n if (!host.iframe.isConnected) {\n liveHosts.delete(host);\n continue;\n }\n if (host.ready && host.stylebook) {\n host.channel.post({ gen: host.lastRenderedGen, kind: \"styleUpdate\", style: cloneable });\n posted += 1;\n requestSelection(host, host.selectionPath);\n }\n }\n return posted;\n}\n\n/**\n * Pan the canvas so the selected tag's card is centered (layers-panel \"locate\" affordance). The\n * card lives inside the iframe, so it is measured over the bridge and the reply pans by the\n * converted parent-viewport rect (see the `geometry` handler's panReqId branch).\n */\nexport function panToStylebookTag(tag: string): void {\n const panel = getActivePanel();\n const host = panel ? (hosts.get(panel.canvas as HTMLElement) ?? null) : null;\n if (!host?.stylebook || !host.ready) {\n return;\n }\n const cardPath = host.stylebook.tagToCardPath.get(tag);\n if (!cardPath) {\n return;\n }\n host.selReqId += 1;\n host.panReqId = host.selReqId;\n host.channel.post({ kind: \"measure\", paths: [[...cardPath]], reqId: host.selReqId });\n}\n\n// ─── Format-toolbar bridge (Phase 4b-2) ─────────────────────────────────────────\n\n/** The host whose iframe currently owns the inline-edit session (or null). */\nexport function getActiveEditHost(): HostState | null {\n return activeEditHost;\n}\n\n/** The current edit session's editing flag + latest selection snapshot, for the parent toolbar. */\nexport function getEditSnapshot(): {\n editing: boolean;\n editingProp: string | null;\n snapshot: SelectionSnapshot | null;\n} {\n if (!activeEditHost) {\n return { editing: false, editingProp: null, snapshot: null };\n }\n return {\n editing: activeEditHost.editing,\n editingProp: activeEditHost.editingProp,\n snapshot: activeEditHost.snapshot,\n };\n}\n\n/** Post an `applyFormat` intent to the active edit host's iframe (no-op when none/not ready). */\nexport function postApplyFormat(intent: ApplyFormatIntent): void {\n const host = activeEditHost;\n if (!host || !host.ready) {\n return;\n }\n host.channel.post({ intent, kind: \"applyFormat\" });\n}\n\n/**\n * Ask the active edit host's iframe to commit-and-end its inline-edit session (no-op when none).\n * The parent calls this when intent leaves the edit surface in the PARENT realm — a tab switch, a\n * chrome click outside the edit toolbars — which the iframe cannot observe itself. The resulting\n * `editCommit` routes by the host's tabId, so a commit racing a tab switch still lands in the\n * document its session belonged to.\n */\nexport function commitActiveEditSession(): void {\n const host = activeEditHost;\n if (host?.editing && host.ready) {\n host.channel.post({ kind: \"endEdit\" });\n }\n}\n\n/** The live host backing the active panel's canvas (for non-edit selection-bar positioning). */\nfunction hostForActivePanel(): HostState | null {\n const panel = getActivePanel();\n return panel ? (hosts.get(panel.canvas as HTMLElement) ?? null) : null;\n}\n\n/**\n * The format toolbar's anchor rect, in PARENT-VIEWPORT space (the bar is `position:fixed`). Both\n * source rects — the edit session's caret snapshot and the `lastSelectionRect` fallback — are in\n * UNSCALED iframe-viewport px (D-2: the overlay draws them inside the scaled panzoom-wrap, so the\n * browser applies the zoom there); the fixed bar gets no such free ride, so scale by the live\n * empirical zoom ({@link hostDragGeometry}) and add the iframe's on-screen offset, whose GBCR\n * already bakes in pan + zoom + ancestor scroll. The empirical ratio covers BOTH scale sources:\n * design mode's panzoom-wrap transform and edit mode's content-zoom counter-scale (where it\n * evaluates to exactly `editZoom` — the iframe's layout width is `renderWidth / editZoom` while its\n * rendered width is `renderWidth`).\n */\nexport function getEditBarAnchorRect(): ParentRect | null {\n // The format toolbar follows the live caret/selection snapshot of the active edit session; the\n // Structural bar (tag badge / parent selector / move / convert / drag handle) must still position\n // On a plain selection with no inline-edit session, so fall back to the active panel's host and\n // Its last measured selection rect.\n const editHost = activeEditHost;\n const host = editHost ?? hostForActivePanel();\n if (!host) {\n return null;\n }\n const { rect: ifr, scale } = hostDragGeometry(host);\n const snapRect = host === editHost ? host.snapshot?.rect : null;\n if (snapRect) {\n return {\n height: snapRect.height * scale,\n left: snapRect.x * scale + ifr.left,\n top: snapRect.y * scale + ifr.top,\n width: snapRect.width * scale,\n };\n }\n if (host.lastSelectionRect) {\n // The fallback rect is overlay-local (same top-left + coordinate space as the iframe viewport).\n return {\n height: host.lastSelectionRect.height * scale,\n left: host.lastSelectionRect.left * scale + ifr.left,\n top: host.lastSelectionRect.top * scale + ifr.top,\n width: host.lastSelectionRect.width * scale,\n };\n }\n return null;\n}\n",
|
|
39
|
-
"/// <reference lib=\"dom\" />\n/**\n * Media upload core — the single path every upload surface goes through.\n *\n * Four surfaces feed it: the image field's Upload button (ui/media-picker), a file dropped on the\n * canvas (editor/file-drop-action), a file dropped on the Files tree (files/files), and the Manage\n * view's drop zone / Upload button (browse/browse). They differ only in how the destination\n * directory is chosen; naming, collision handling, the platform call, and cache invalidation are\n * shared here.\n *\n * Destination (specs/site-architecture.md §9.1/§9.3): a document inside a content collection keeps\n * its media co-located in `content/<collection>/images/` — the entry references it file-relatively\n * and the collection loader rewrites it to the asset mount. Everything else goes to `public/`,\n * which is served from the site root.\n *\n * @docs studio/projects/media\n */\n\nimport { errorMessage } from \"@jxsuite/schema/parse\";\nimport { getPlatform } from \"../platform\";\nimport { statusMessage } from \"../panels/statusbar\";\nimport { activeTab } from \"../workspace/workspace\";\n\n// ─── File classification ─────────────────────────────────────────────────────\n\n/** Extensions rendered as a thumbnail (media picker, Manage cards, file-tree icons). */\nexport const IMAGE_EXTENSIONS = new Set([\n \".jpg\",\n \".jpeg\",\n \".png\",\n \".gif\",\n \".svg\",\n \".webp\",\n \".avif\",\n \".ico\",\n]);\n\n/** Every extension Studio treats as project media. Superset of {@link IMAGE_EXTENSIONS}. */\nexport const MEDIA_EXTENSIONS = new Set([\n ...IMAGE_EXTENSIONS,\n \".mp4\",\n \".webm\",\n \".mp3\",\n \".wav\",\n \".ogg\",\n \".pdf\",\n \".woff\",\n \".woff2\",\n \".ttf\",\n \".otf\",\n]);\n\n/** The `accept` attribute for every upload file input. */\nexport const UPLOAD_ACCEPT = [\n \"image/*\",\n \"video/*\",\n \"audio/*\",\n \".pdf\",\n \".svg\",\n \".woff\",\n \".woff2\",\n \".ttf\",\n \".otf\",\n].join(\",\");\n\n/** What kind of element an uploaded asset wants to become. */\nexport type AssetKind = \"image\" | \"video\" | \"audio\" | \"file\";\n\n/** One successfully uploaded file. */\nexport interface UploadedAsset {\n /** Project-relative path written, e.g. `public/hero.jpg`. */\n path: string;\n /** The filename actually used (may carry a collision suffix). */\n name: string;\n /** The reference to write into a document `src`/prop, e.g. `/hero.jpg`. */\n ref: string;\n kind: AssetKind;\n}\n\n/** Lowercased extension including the dot, or `\"\"` when the name carries none. */\nexport function extensionOf(name: string): string {\n const dot = name.lastIndexOf(\".\");\n return dot > 0 ? name.slice(dot).toLowerCase() : \"\";\n}\n\n/** Whether a file extension (with or without the leading dot) is a previewable image. */\nexport function isImage(ext: string): boolean {\n return IMAGE_EXTENSIONS.has(ext.startsWith(\".\") ? ext.toLowerCase() : `.${ext.toLowerCase()}`);\n}\n\n/** Whether a filename is project media. */\nexport function isMediaFile(name: string): boolean {\n return MEDIA_EXTENSIONS.has(extensionOf(name));\n}\n\nconst VIDEO_EXTENSIONS = new Set([\".mp4\", \".webm\", \".mov\", \".m4v\"]);\nconst AUDIO_EXTENSIONS = new Set([\".mp3\", \".wav\", \".ogg\", \".m4a\", \".flac\"]);\n\n/**\n * Classify a file by MIME type, falling back to its extension. A drop from the OS usually carries a\n * `type`, but it is empty for unrecognized extensions and for some Linux file managers.\n */\nexport function mediaKind(file: { name: string; type?: string }): AssetKind {\n const mime = file.type ?? \"\";\n if (mime.startsWith(\"image/\")) {\n return \"image\";\n }\n if (mime.startsWith(\"video/\")) {\n return \"video\";\n }\n if (mime.startsWith(\"audio/\")) {\n return \"audio\";\n }\n const ext = extensionOf(file.name);\n if (IMAGE_EXTENSIONS.has(ext)) {\n return \"image\";\n }\n if (VIDEO_EXTENSIONS.has(ext)) {\n return \"video\";\n }\n if (AUDIO_EXTENSIONS.has(ext)) {\n return \"audio\";\n }\n return \"file\";\n}\n\n// ─── Destination resolution ──────────────────────────────────────────────────\n\n/** Matches a path inside a content collection: `content/<collection>/…`. */\nconst CONTENT_ENTRY = /^content\\/([^/]+)\\//;\n\n/**\n * The directory an upload lands in when the caller doesn't name one. A document inside a content\n * collection gets `content/<collection>/images`; everything else gets `public`.\n */\nexport function uploadDirFor(documentPath: string | null): string {\n const match = documentPath ? CONTENT_ENTRY.exec(documentPath.replaceAll(\"\\\\\", \"/\")) : null;\n return match ? `content/${match[1]}/images` : \"public\";\n}\n\n/**\n * The reference to write into a document for a file at `destPath`.\n *\n * `public/` is served from the site root, so its contents get a root-relative `/name`. A content\n * asset is referenced relative to the entry that owns it (`./images/name`) so the collection loader\n * rewrites it to the asset mount. Anything else is project-root relative (`./dir/name`), which is\n * how the compiler resolves a non-`/` path.\n */\nexport function assetRef(destPath: string): string {\n const path = destPath.replaceAll(\"\\\\\", \"/\");\n if (path.startsWith(\"public/\")) {\n return path.slice(\"public\".length);\n }\n const content = /^content\\/[^/]+\\/(.+)$/.exec(path);\n if (content) {\n return `./${content[1]}`;\n }\n return `./${path}`;\n}\n\n/**\n * A filename that doesn't collide with `taken`, suffixing `-1`, `-2`, … before the extension. Never\n * overwrites existing media (the previous behaviour clobbered silently).\n */\nexport function uniqueName(name: string, taken: ReadonlySet<string>): string {\n if (!taken.has(name)) {\n return name;\n }\n const ext = extensionOf(name);\n const base = ext ? name.slice(0, -ext.length) : name;\n for (let i = 1; ; i++) {\n const candidate = `${base}-${i}${ext}`;\n if (!taken.has(candidate)) {\n return candidate;\n }\n }\n}\n\n/** Join a directory and a filename, treating `.` (project root) as no prefix. */\nexport function joinDir(dir: string, name: string): string {\n const normalized = dir.replaceAll(\"\\\\\", \"/\").replace(/\\/+$/, \"\");\n return normalized === \".\" || normalized === \"\" ? name : `${normalized}/${name}`;\n}\n\n// ─── Cache invalidation (injected) ───────────────────────────────────────────\n\n/**\n * Called after a batch of uploads with the directory they landed in. Injected from studio.ts so\n * this module doesn't import the media-picker / Manage / file-tree caches it needs to invalidate\n * (they all import from here) — the same injection pattern as the canvas host's drop handlers.\n */\nlet mediaChangedHandler: ((dir: string) => void | Promise<void>) | null = null;\n\n/** Register the post-upload cache invalidator (see {@link mediaChangedHandler}). */\nexport function setMediaChangedHandler(fn: ((dir: string) => void | Promise<void>) | null): void {\n mediaChangedHandler = fn;\n}\n\n// ─── Upload ──────────────────────────────────────────────────────────────────\n\n/**\n * Upload files into the project and report what landed.\n *\n * `opts.dir` names the destination explicitly (the file tree's target folder, the Manage view's\n * active category); without it the destination follows the active document via {@link uploadDirFor}.\n * Names are made collision-free against a single listing of the destination. A file that fails to\n * upload is reported and skipped — the rest of the batch still lands.\n */\nexport async function uploadAssets(\n files: Iterable<File>,\n opts: { dir?: string } = {},\n): Promise<UploadedAsset[]> {\n const list = [...files];\n if (list.length === 0) {\n return [];\n }\n const platform = getPlatform();\n const dir = opts.dir ?? uploadDirFor(activeTab.value?.documentPath ?? null);\n\n let taken: Set<string>;\n try {\n const existing = await platform.listDirectory(dir);\n taken = new Set(existing.map((entry) => entry.name));\n } catch {\n taken = new Set(); // Directory doesn't exist yet — the backend mkdir -p's on write.\n }\n\n const uploaded: UploadedAsset[] = [];\n for (const file of list) {\n const name = uniqueName(file.name, taken);\n taken.add(name);\n const path = joinDir(dir, name);\n try {\n await platform.uploadFile(path, file);\n uploaded.push({ kind: mediaKind(file), name, path, ref: assetRef(path) });\n } catch (error) {\n statusMessage(`Upload failed: ${file.name} — ${errorMessage(error)}`);\n }\n }\n\n if (uploaded.length > 0) {\n statusMessage(\n uploaded.length === 1\n ? `Uploaded ${uploaded[0]!.name} to ${dir}/`\n : `Uploaded ${uploaded.length} files to ${dir}/`,\n );\n await mediaChangedHandler?.(dir);\n }\n return uploaded;\n}\n",
|
|
40
|
-
"/** OXC code services (server-backed) */\n\nimport { getPlatform } from \"../platform\";\nimport { isJsonObject, paramNames } from \"@jxsuite/schema/guards\";\nimport { projectState } from \"../state\";\nimport { getNodeAtPath } from \"../store\";\nimport { loadedMonaco } from \"./monaco-lazy\";\nimport type { JxPath } from \"../state\";\nimport type { JxFunctionDef, JxMutableNode } from \"@jxsuite/schema/types\";\nimport type { editor } from \"monaco-editor\";\n\nexport interface OxLintDiagnostic {\n severity: string;\n message: string;\n help?: string;\n code?: string;\n url?: string;\n labels?: { span: { line: number; column: number; length?: number } }[];\n}\n\n/**\n * @param {string} action\n * @param {unknown} payload\n */\nexport async function codeService(action: string, payload: unknown) {\n const platform = getPlatform();\n if (!platform.codeService) {\n return null;\n }\n return platform.codeService(action, payload);\n}\n\n/**\n * Ask the server to locate a document by filename within the project root.\n *\n * @param {string} name\n */\nexport async function locateDocument(name: string) {\n const platform = getPlatform();\n if (!platform.locateFile) {\n return null;\n }\n return platform.locateFile(name);\n}\n\n/** Schema returned by a plugin's `$prototype` module (loose superset used across panels). */\nexport interface PluginSchema {\n type?: string;\n description?: string;\n properties?: Record<string, unknown>;\n required?: string[];\n returns?: { type?: string };\n [key: string]: unknown;\n}\n\n/** Cache of plugin schemas keyed by \"$src::$prototype\". */\nexport const pluginSchemaCache = new Map<string, PluginSchema | null>();\n\n/**\n * Fetch and cache the schema for a $prototype module via the server. Works for both external\n * prototypes (with $src) and prototypes resolved from project.json imports.\n *\n * @param {{ $src?: string; $prototype?: string }} def\n * @param {{ documentPath?: string }} state\n */\nexport async function fetchPluginSchema(\n def: { $src?: string; $prototype?: string },\n state: { documentPath?: string },\n) {\n const importedPath = def.$prototype\n ? projectState?.projectConfig?.imports?.[def.$prototype]\n : null;\n const src = def.$src || importedPath;\n if (!src || !def.$prototype) {\n return null;\n }\n const cacheKey = `${src}::${def.$prototype}`;\n if (pluginSchemaCache.has(cacheKey)) {\n return pluginSchemaCache.get(cacheKey);\n }\n\n try {\n const platform = getPlatform();\n if (!platform.fetchPluginSchema) {\n pluginSchemaCache.set(cacheKey, null);\n return null;\n }\n const base =\n !importedPath && state.documentPath ? `${location.origin}/${state.documentPath}` : undefined;\n const schema = (await platform.fetchPluginSchema(\n src,\n def.$prototype,\n base,\n )) as PluginSchema | null;\n pluginSchemaCache.set(cacheKey, schema);\n return schema;\n } catch {\n pluginSchemaCache.set(cacheKey, null);\n return null;\n }\n}\n\n/**\n * @param {import(\"monaco-editor\").editor.IStandaloneCodeEditor} editor\n * @param {OxLintDiagnostic[]} diagnostics\n */\nexport function setLintMarkers(\n editor: editor.IStandaloneCodeEditor,\n diagnostics: OxLintDiagnostic[],\n) {\n const model = editor.getModel();\n if (!model) {\n return;\n }\n // Reachable only with a live editor in hand, so Monaco is already loaded.\n const monaco = loadedMonaco();\n if (!monaco) {\n return;\n }\n const markers = diagnostics\n .map((d) => {\n const label = d.labels?.[0];\n if (!label) {\n return null;\n }\n const { line, column, length } = label.span;\n return {\n code: d.url ? { target: monaco.Uri.parse(d.url), value: d.code } : d.code,\n endColumn: column + (length || 1),\n endLineNumber: line,\n message: d.message + (d.help ? `\\n${d.help}` : \"\"),\n severity:\n d.severity === \"error\" ? monaco.MarkerSeverity.Error : monaco.MarkerSeverity.Warning,\n source: \"oxlint\",\n startColumn: column,\n startLineNumber: line,\n };\n })\n .filter(Boolean);\n monaco.editor.setModelMarkers(model, \"oxlint\", markers as editor.IMarkerData[]);\n}\n\n/**\n * @param {{ type: string; defName?: string; path?: JxPath; eventKey?: string }} editing\n * @param {JxMutableNode | null | undefined} document\n */\nexport function getFunctionArgs(\n editing: { type: string; defName?: string; path?: JxPath; eventKey?: string },\n document: JxMutableNode | null | undefined,\n): string[] {\n // Read parameters off any object-shaped def (covers legacy entries without $prototype).\n const fromDef = (def: unknown): string[] | null => {\n if (!isJsonObject(def)) {\n return null;\n }\n const params = def.parameters;\n if (!Array.isArray(params) || params.length === 0) {\n return null;\n }\n return paramNames(params as JxFunctionDef[\"parameters\"]);\n };\n if (editing.type === \"def\") {\n const args = editing.defName ? fromDef(document?.state?.[editing.defName]) : null;\n if (args) {\n return args;\n }\n } else if (editing.type === \"event\") {\n if (!document || !editing.path) {\n return [\"state\", \"event\"];\n }\n const node = getNodeAtPath(document, editing.path);\n const args = node && editing.eventKey ? fromDef(node[editing.eventKey]) : null;\n if (args) {\n return args;\n }\n }\n return [\"state\", \"event\"];\n}\n",
|
|
41
|
-
"/// <reference lib=\"dom\" />\nimport type { CemParameter, JxMutableNode, JxStateObject } from \"@jxsuite/schema/types\";\nimport { isFunctionDef, isJsonObject } from \"@jxsuite/schema/guards\";\n\n/** Collect slot elements from the document tree. Whitespace-only names count as unnamed. */\nexport function collectSlots(node?: JxMutableNode | null, slots: string[] = []) {\n if (node?.tagName === \"slot\") {\n const name = node.attributes?.name;\n slots.push(typeof name === \"string\" ? name.trim() : \"\");\n }\n if (Array.isArray(node?.children)) {\n for (const c of node.children) {\n collectSlots(typeof c === \"string\" ? undefined : c, slots);\n }\n }\n return slots;\n}\n\n/**\n * Validate slot usage in a component definition. Returns a warning message or null when valid. Only\n * static children are walked — slots inside $switch cases are mutually exclusive branches and are\n * not counted (v1 limitation).\n */\nexport function validateComponentSlots(doc: JxMutableNode): string | null {\n const names = collectSlots(doc);\n const unnamed = names.filter((n) => n === \"\").length;\n if (unnamed > 1) {\n return `Component has ${unnamed} unnamed <slot> elements — only one default slot is allowed. Give extra slots a name attribute.`;\n }\n const seen = new Set<string>();\n for (const n of names) {\n if (n && seen.has(n)) {\n return `Duplicate slot name \"${n}\" — slot names must be unique within a component.`;\n }\n seen.add(n);\n }\n return null;\n}\n\n/**\n * Generate and download a CEM 2.1.0 manifest for the current document.\n *\n * @param {{ document: JxMutableNode }} S - Studio state\n * @param {{\n * defCategory: (d: unknown) => string;\n * normParam: (p: string | CemParameter) => CemParameter;\n * collectCssParts: (node: JxMutableNode) => { name: string }[];\n * }} helpers\n */\nexport function exportCemManifest(\n S: { document: JxMutableNode },\n helpers: {\n defCategory: (d: unknown) => string;\n normParam: (p: string | CemParameter) => CemParameter;\n collectCssParts: (node: JxMutableNode) => { name: string }[];\n },\n) {\n const { defCategory, normParam, collectCssParts } = helpers;\n const doc = S.document;\n const { tagName } = doc;\n if (!tagName || !tagName.includes(\"-\")) {\n return;\n }\n\n const state = doc.state || {};\n const members: Record<string, unknown>[] = [];\n const attributes: Record<string, unknown>[] = [];\n const events: Record<string, unknown>[] = [];\n const seenEvents = new Set<string>();\n\n for (const [key, d] of Object.entries(state)) {\n if (key.startsWith(\"#\")) {\n continue;\n } // Private\n\n const cat = defCategory(d);\n\n if (cat === \"function\") {\n if (isFunctionDef(d)) {\n members.push({\n kind: \"method\",\n name: key,\n ...(d.description ? { description: d.description } : {}),\n ...(d.parameters ? { parameters: d.parameters.map(normParam) } : {}),\n ...(d.deprecated\n ? { deprecated: typeof d.deprecated === \"string\" ? d.deprecated : true }\n : {}),\n });\n // Collect emits\n for (const ev of d.emits ?? []) {\n if (ev.name && !seenEvents.has(ev.name)) {\n seenEvents.add(ev.name);\n events.push({\n name: ev.name,\n ...(ev.type !== undefined ? { type: ev.type } : {}),\n ...(ev.description ? { description: ev.description } : {}),\n });\n }\n }\n } else if (isJsonObject(d)) {\n // Legacy $handler entry — emit a bare method member\n const { description } = d;\n members.push({\n kind: \"method\",\n name: key,\n ...(typeof description === \"string\" ? { description } : {}),\n });\n }\n } else if (cat === \"state\") {\n // Naked primitive values carry no metadata; object defs are signals/type defs.\n const def: JxStateObject | null = isJsonObject(d) ? (d as JxStateObject) : null;\n members.push({\n kind: \"field\",\n name: key,\n ...(def?.type ? { type: { text: def.type } } : {}),\n ...(def && def.default !== undefined ? { default: String(def.default) } : {}),\n ...(def?.description ? { description: def.description } : {}),\n ...(def?.attribute ? { attribute: def.attribute } : {}),\n ...(def?.reflects ? { reflects: true } : {}),\n ...(def?.deprecated\n ? { deprecated: typeof def.deprecated === \"string\" ? def.deprecated : true }\n : {}),\n });\n if (def?.attribute) {\n attributes.push({\n name: def.attribute,\n ...(def.type ? { type: { text: def.type } } : {}),\n fieldName: key,\n });\n }\n }\n }\n\n // Slots\n const slotNames = collectSlots(doc);\n const slots = slotNames.map((name: string) => {\n const slot: { name: string; description?: string } = { name: name || \"\" };\n if (!name) {\n slot.description = \"Default slot\";\n }\n return slot;\n });\n\n // CSS custom properties\n const style = doc.style || {};\n const cssProperties = Object.entries(style)\n .filter(([k]) => k.startsWith(\"--\"))\n .map(([name, val]) => ({ default: String(val), name }));\n\n // CSS parts\n const cssParts = collectCssParts(doc).map((p) => ({ name: p.name }));\n\n const manifest = {\n modules: [\n {\n declarations: [\n {\n kind: \"class\",\n members,\n name: tagName,\n tagName,\n ...(attributes.length > 0 ? { attributes } : {}),\n ...(events.length > 0 ? { events } : {}),\n ...(slots.length > 0 ? { slots } : {}),\n ...(cssProperties.length > 0 ? { cssProperties } : {}),\n ...(cssParts.length > 0 ? { cssParts } : {}),\n },\n ],\n kind: \"javascript-module\",\n path: \"\",\n },\n ],\n schemaVersion: \"2.1.0\",\n };\n\n const blob = new Blob([JSON.stringify(manifest, null, 2)], {\n type: \"application/json\",\n });\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = `${tagName}.cem.json`;\n a.click();\n URL.revokeObjectURL(url);\n}\n"
|
|
42
|
-
],
|
|
43
|
-
"mappings": "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",
|
|
44
|
-
"debugId": "252AAA4F9D8BC86364756E2164756E21",
|
|
45
|
-
"names": []
|
|
46
|
-
}
|