@jxsuite/studio 2.0.0 → 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-0hzentwq.js → components-2bpqp4mq.js} +5 -7
- package/dist/chunks/{components-0hzentwq.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-2c188n41.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-97qcgvdn.js → studio-adn0z1k3.js} +14 -8
- package/dist/chunks/{studio-97qcgvdn.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-hhj92gcr.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-ygzav7z5.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-n9zmpxjg.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 +23711 -35185
- 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 +34 -9
- package/src/new-project/location-fields.ts +9 -1
- package/src/new-project/new-project-modal.ts +270 -262
- 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 -120
- 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 +75 -2
- 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 +113 -0
- 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-qct0gt8f.js +0 -531
- package/dist/chunks/extension-sections-qct0gt8f.js.map +0 -12
- package/dist/chunks/files-02zn5y24.js +0 -50
- package/dist/chunks/files-02zn5y24.js.map +0 -9
- package/dist/chunks/git-panel-mbb0y0hz.js +0 -28
- package/dist/chunks/git-panel-mbb0y0hz.js.map +0 -9
- package/dist/chunks/layers-panel-9qekmqk1.js +0 -26
- package/dist/chunks/layers-panel-9qekmqk1.js.map +0 -9
- package/dist/chunks/settings-modal-gj0hrah4.js +0 -29
- package/dist/chunks/settings-modal-gj0hrah4.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-4k0m4fmp.js.map +0 -13
- package/dist/chunks/studio-568nx4t5.js +0 -469
- package/dist/chunks/studio-568nx4t5.js.map +0 -14
- package/dist/chunks/studio-9smfzqhc.js +0 -19
- package/dist/chunks/studio-9smfzqhc.js.map +0 -10
- package/dist/chunks/studio-asvf0j9e.js +0 -429
- package/dist/chunks/studio-asvf0j9e.js.map +0 -13
- package/dist/chunks/studio-d77qm3pk.js +0 -3427
- package/dist/chunks/studio-d77qm3pk.js.map +0 -26
- package/dist/chunks/studio-j6gqyjf4.js +0 -1854
- package/dist/chunks/studio-j6gqyjf4.js.map +0 -18
- package/dist/chunks/studio-n9zmpxjg.js.map +0 -115
- package/dist/chunks/studio-qkvt37c0.js.map +0 -9
- package/dist/chunks/studio-rq0vxb19.js +0 -3744
- package/dist/chunks/studio-rq0vxb19.js.map +0 -22
- package/dist/chunks/studio-wd6ewdvd.js +0 -853
- package/dist/chunks/studio-wd6ewdvd.js.map +0 -12
- 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-ygzav7z5.js.map +0 -46
- package/dist/chunks/studio-zmy7241e.js +0 -399
- package/dist/chunks/studio-zmy7241e.js.map +0 -12
- 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-2c188n41.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-hhj92gcr.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
|
@@ -46,6 +46,22 @@ export interface WireMapperCtx {
|
|
|
46
46
|
arrayPaths: string[];
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* One live binding, as the frame needs to know it: the chord and the scope that holds it.
|
|
51
|
+
*
|
|
52
|
+
* Scopes are carried rather than flattened because the frame picks its own stack per keystroke —
|
|
53
|
+
* `caret` when an inline-edit session is live, `canvas` when the artboard has a selection, `global`
|
|
54
|
+
* under both — which is the same ladder `commands/context.ts`'s `keyScopeStack` walks host-side.
|
|
55
|
+
* Flattening to "chords the parent wants" would lose exactly the distinction that lets ⌘C reach the
|
|
56
|
+
* browser mid-sentence and the structural copy verb at every other moment.
|
|
57
|
+
*
|
|
58
|
+
* The command ID is deliberately absent: the frame decides whether to FORWARD, never what runs.
|
|
59
|
+
*/
|
|
60
|
+
export interface SyncedChord {
|
|
61
|
+
chord: string;
|
|
62
|
+
scope: "caret" | "canvas" | "global";
|
|
63
|
+
}
|
|
64
|
+
|
|
49
65
|
/** Messages the editor (parent) sends into the canvas iframe. */
|
|
50
66
|
export type ParentToIframe =
|
|
51
67
|
| { kind: "init"; gen: number }
|
|
@@ -82,6 +98,53 @@ export type ParentToIframe =
|
|
|
82
98
|
// Flip the forced color-scheme preview on the iframe root without re-rendering — a document-level
|
|
83
99
|
// Idempotent attribute write, deliberately gen-less (like endEdit).
|
|
84
100
|
| { kind: "setColorScheme"; scheme: "light" | "dark" | null }
|
|
101
|
+
/**
|
|
102
|
+
* Set the language the artboard is drawn in — `lang` and `dir` on the frame's document element.
|
|
103
|
+
*
|
|
104
|
+
* Render-free and gen-less, like `setColorScheme` above, because it changes no content: Jx has no
|
|
105
|
+
* message catalogue, so the TEXT is whatever file is open and only the direction, the font stack
|
|
106
|
+
* and CSS's own `:lang()` selectors move. `dir` travels with the tag rather than being derived in
|
|
107
|
+
* the frame — `localeDirection` is CLDR's answer via `Intl.Locale`, and the frame has no reason
|
|
108
|
+
* to hold a second copy of the RTL script list.
|
|
109
|
+
*
|
|
110
|
+
* `null` is "the document's own language": both attributes come off, and the frame falls back to
|
|
111
|
+
* whatever the rendered document declares.
|
|
112
|
+
*/
|
|
113
|
+
| { kind: "setLocale"; locale: string | null; dir: "ltr" | "rtl" }
|
|
114
|
+
/**
|
|
115
|
+
* Open the slash menu at the caret, by name rather than by typing "/".
|
|
116
|
+
*
|
|
117
|
+
* The gesture is recognised inside the frame (`canvas/iframe-inline-edit.ts`), because that is
|
|
118
|
+
* where the keystroke is; this is the door for `insert.openSlashMenu` — the palette, a rebound
|
|
119
|
+
* chord, the automation runner and the assistant. The frame opens it UNANCHORED: there is no "/"
|
|
120
|
+
* in the document, so the menu carries its own filter field and selecting a block deletes
|
|
121
|
+
* nothing.
|
|
122
|
+
*
|
|
123
|
+
* Gen-less and render-free, like `setColorScheme` above. A frame with no caret session ignores
|
|
124
|
+
* it, which is the same refusal the record's `requires` sentence states.
|
|
125
|
+
*/
|
|
126
|
+
| { kind: "openSlash" }
|
|
127
|
+
/**
|
|
128
|
+
* The chord table, so the frame forwards exactly what the host's registry binds.
|
|
129
|
+
*
|
|
130
|
+
* The frame used to answer "does the parent want this keystroke?" from three hand-written lists —
|
|
131
|
+
* eight bare keys, four "the editor owns these" chords, three "the browser owns these" chords —
|
|
132
|
+
* maintained beside a registry that already knew the answer. They disagreed in both directions:
|
|
133
|
+
* ⌘A was forwarded and `preventDefault`ed by a frame that assumed the host would claim it (no
|
|
134
|
+
* record binds it, so select-all did nothing AND the native one was suppressed), while ⌘B was
|
|
135
|
+
* withheld on the assumption the editing engine handled it (it does not — the parent's
|
|
136
|
+
* block-level keydown listener never fires against a container-level editing host, and
|
|
137
|
+
* `canvas/editable-actions.ts` rejects the browser's own `formatBold`), so Bold in the canvas did
|
|
138
|
+
* nothing at all.
|
|
139
|
+
*
|
|
140
|
+
* Idempotent and render-free, like `setColorScheme` above, and deliberately gen-less: it
|
|
141
|
+
* describes the APP, not a document. The host reposts it whenever the keymap changes, which is
|
|
142
|
+
* what makes a rebinding in Preferences take effect inside the canvas.
|
|
143
|
+
*
|
|
144
|
+
* A frame built before this message existed ignores it and keeps its own lists — which is the
|
|
145
|
+
* compatibility story `dist/iframe-entry.js` shipping prebuilt requires.
|
|
146
|
+
*/
|
|
147
|
+
| { kind: "keymap"; mac: boolean; chords: readonly SyncedChord[] }
|
|
85
148
|
// Replace the injected site-style sheet in place (live design-token editing) — idempotent and
|
|
86
149
|
// Render-free; the superseding render carries the same style via its own siteStyle.
|
|
87
150
|
| {
|
|
@@ -240,6 +303,29 @@ export interface DropPreview {
|
|
|
240
303
|
edge: "top" | "bottom" | "inside";
|
|
241
304
|
}
|
|
242
305
|
|
|
306
|
+
/**
|
|
307
|
+
* A click that landed on LAYOUT chrome — a header, a footer, anything the layout file contributes
|
|
308
|
+
* that is not the page's own content. Such a node has no page-document path, so it can never be a
|
|
309
|
+
* {@link NodeHit}; it is addressed by the layout FILE it came from plus its path inside that file.
|
|
310
|
+
*
|
|
311
|
+
* This is the message that makes the first click a new author makes do something. On a default
|
|
312
|
+
* project the two most conspicuous strings on the page ("My Site", "Built with Jx") both come from
|
|
313
|
+
* `layouts/base.json`, and before this existed clicking either one selected nothing, hovered
|
|
314
|
+
* nothing and posted nothing.
|
|
315
|
+
*/
|
|
316
|
+
export interface LayoutHit {
|
|
317
|
+
/** Project-relative path of the layout document, e.g. `layouts/base.json`. */
|
|
318
|
+
layoutFile: string;
|
|
319
|
+
/** The clicked node's path WITHIN that layout document (what to select once it is open). */
|
|
320
|
+
layoutPath: (string | number)[];
|
|
321
|
+
/** The rendered tag, for the panel's `<header>` label. */
|
|
322
|
+
tagName: string;
|
|
323
|
+
/** The rendered class list, shown read-only in the panel. */
|
|
324
|
+
className: string;
|
|
325
|
+
/** The node's box, in iframe-viewport coords (same convention as {@link NodeHit}). */
|
|
326
|
+
rect: SerializableRect;
|
|
327
|
+
}
|
|
328
|
+
|
|
243
329
|
/** A document path plus the iframe-space rect of the node it resolves to. */
|
|
244
330
|
export interface NodeHit {
|
|
245
331
|
path: (string | number)[];
|
|
@@ -308,7 +394,31 @@ export type IframeToParent =
|
|
|
308
394
|
// Not the parent, now resolves the scope). `gen` lets the parent drop a snapshot from a superseded
|
|
309
395
|
// Render. Posted right after `renderComplete`; values are JSON-safe deep clones (see serialize-scope).
|
|
310
396
|
| { kind: "dataScope"; gen: number; scope: Record<string, unknown> }
|
|
311
|
-
|
|
397
|
+
// The frame's own quiescence, ANSWERED rather than polled (spec §13.5, plan §13.4 condition 5).
|
|
398
|
+
// Nothing in the parent realm can see inside a cross-origin frame, so a parent that wanted to
|
|
399
|
+
// Know whether the canvas had settled could only sleep. The frame samples itself at its own rAF
|
|
400
|
+
// And posts whenever the tuple changes, ending with the quiet one; the host holds the latest.
|
|
401
|
+
//
|
|
402
|
+
// `fonts` is `document.fonts.status === "loaded"` and is NOT sufficient alone — in a blank canvas
|
|
403
|
+
// Frame it reports "loaded" against an EMPTY font set (measured in S0: `hero` drifted 0.150 RMSE
|
|
404
|
+
// Because the first capture measured fallback metrics while Plus Jakarta Sans was still in
|
|
405
|
+
// Flight). It is honest only together with `gen` (a frame that has not acked a render has not
|
|
406
|
+
// Loaded its fonts either) and the runner's per-frame network count.
|
|
407
|
+
//
|
|
408
|
+
// `images` counts images whose load FAILED and whose retry (`installCanvasImageRetry`, re-firing
|
|
409
|
+
// At 150/300/450 ms) has not resolved. Deliberately NOT "images not yet complete": blocking on
|
|
410
|
+
// `img.complete` failed 8 of 61 shots — the design canvas renders unresolved bindings as literal
|
|
411
|
+
// Srcs, several starters ship a 404 favicon, and lazy images below the fold never complete. A
|
|
412
|
+
// Pending retry is the one image fact only the app knows.
|
|
413
|
+
| { kind: "idle"; gen: number; fonts: boolean; animations: number; images: number }
|
|
414
|
+
// `additive` is Ctrl/Cmd being held at the moment of the click — the ACCUMULATE gesture, which
|
|
415
|
+
// The parent turns into a toggle against `session.selection` (studio §6.5). Absent/false is a
|
|
416
|
+
// Plain replace, which is what every canvas click was before the selection became a set.
|
|
417
|
+
| { kind: "hit"; hit: NodeHit; additive?: boolean }
|
|
418
|
+
// A click on layout chrome (see {@link LayoutHit}). Distinct from `hit` because the target is not
|
|
419
|
+
// In the page document at all: the parent adopts it as `view.layoutSelection` (which shows the
|
|
420
|
+
// Read-only layout panel with its "Open Layout →" action) rather than as a document selection.
|
|
421
|
+
| { kind: "layoutHit"; hit: LayoutHit }
|
|
312
422
|
| { kind: "hover"; hit: NodeHit | null }
|
|
313
423
|
// Candidate insertion "+" zones for the hovered node, recomputed on pointermove (cross-origin
|
|
314
424
|
// Cousin of the legacy insertion-helper). `null` clears the "+" (cursor mid-element / left the
|
|
@@ -417,7 +527,17 @@ export type IframeToParent =
|
|
|
417
527
|
// The engine (in the iframe) detected "/" in a live edit session; the parent shows the real
|
|
418
528
|
// Lit/Spectrum menu. Re-posted with a new `filter` as the author keeps typing (the engine's
|
|
419
529
|
// UpdateSlashMenu drives it). `rect` is the edited element's bbox in IFRAME-VIEWPORT coords.
|
|
420
|
-
|
|
530
|
+
/**
|
|
531
|
+
* Show the parent's slash menu at this rect.
|
|
532
|
+
*
|
|
533
|
+
* `showFilter` is what an UNANCHORED menu needs — one opened by `insert.openSlashMenu` rather
|
|
534
|
+
* than by typing "/". There is no "/…" run in the document to narrow the list with, so the menu
|
|
535
|
+
* has to carry its own field or the only way past fifteen blocks is scrolling. It existed as a
|
|
536
|
+
* callback option INSIDE the frame and was dropped at this boundary, which is the argument for a
|
|
537
|
+
* message carrying every fact its receiver needs rather than most of them: the loss was
|
|
538
|
+
* invisible, because the menu still appeared.
|
|
539
|
+
*/
|
|
540
|
+
| { kind: "slashShow"; rect: SerializableRect; filter: string; showFilter?: boolean }
|
|
421
541
|
// A menu-navigation key pressed in the iframe while the parent menu is open. The iframe
|
|
422
542
|
// Intercepts these four keys capture-phase (restoring the "menu captures Enter" contract) and the
|
|
423
543
|
// Host drives the parent menu's key handler directly — no synthetic keydown redispatch.
|
|
@@ -430,6 +550,21 @@ export type IframeToParent =
|
|
|
430
550
|
// Browser menu is still suppressed, legacy parity); x/y are IFRAME-VIEWPORT coords for the host
|
|
431
551
|
// To convert via its empirical geometry.
|
|
432
552
|
| { kind: "contextMenu"; path: (string | number)[] | null; x: number; y: number }
|
|
553
|
+
// ─── Pane focus ─────────────────────────────────────────────────────────────
|
|
554
|
+
// A pointer went down somewhere in this frame. Nothing else — no path, no coordinates, no
|
|
555
|
+
// Selection: it says only "the person is working in this pane now", which the parent realm cannot
|
|
556
|
+
// Observe for itself because a pointer event inside a cross-origin iframe is delivered in the
|
|
557
|
+
// Frame's own realm and never surfaces above it.
|
|
558
|
+
//
|
|
559
|
+
// `hit` used to be the whole seam, and it has two holes. It is not posted in PREVIEW at all — a
|
|
560
|
+
// Click there is a click on the page, never a selection — so a pane showing Preview could not be
|
|
561
|
+
// Focused by clicking the thing it is showing; and in edit/design it is only posted when the
|
|
562
|
+
// Click lands ON a `[data-jx-path]` node, so clicking an artboard's empty margin focused nothing
|
|
563
|
+
// Either. Both left the keyboard in the other pane while the person was plainly in this one.
|
|
564
|
+
//
|
|
565
|
+
// Deliberately NOT in the host's preview block-list: focusing a pane is not an edit, and it is
|
|
566
|
+
// The one thing preview must still report.
|
|
567
|
+
| { kind: "paneFocus" }
|
|
433
568
|
// ─── Preview navigation ─────────────────────────────────────────────────────
|
|
434
569
|
// A link was clicked in PREVIEW mode. Preview keeps anchors live (design/edit de-link them onto
|
|
435
570
|
// `data-jx-href`), so the click would navigate the canvas iframe away and destroy the render —
|
|
@@ -165,6 +165,36 @@ export const EDIT_PLACEHOLDER_CSS = `
|
|
|
165
165
|
font-size: 13px;
|
|
166
166
|
pointer-events: none;
|
|
167
167
|
}
|
|
168
|
+
[data-jx-layout-region] {
|
|
169
|
+
position: relative;
|
|
170
|
+
opacity: 0.5;
|
|
171
|
+
transition: opacity 120ms ease;
|
|
172
|
+
}
|
|
173
|
+
[data-jx-layout-region]:hover {
|
|
174
|
+
opacity: 0.85;
|
|
175
|
+
outline: 1px dashed color-mix(in srgb, #808080 55%, transparent);
|
|
176
|
+
outline-offset: -1px;
|
|
177
|
+
}
|
|
178
|
+
[data-jx-layout-region] [data-jx-layout-region] {
|
|
179
|
+
opacity: 1;
|
|
180
|
+
}
|
|
181
|
+
[data-jx-layout-region]::before {
|
|
182
|
+
content: "LAYOUT \\00B7 " attr(data-jx-layout-file);
|
|
183
|
+
position: absolute;
|
|
184
|
+
top: 0;
|
|
185
|
+
left: 0;
|
|
186
|
+
z-index: 2;
|
|
187
|
+
padding: 1px 5px;
|
|
188
|
+
border-radius: 0 0 3px 0;
|
|
189
|
+
background: color-mix(in srgb, #808080 78%, transparent);
|
|
190
|
+
color: #fff;
|
|
191
|
+
font: 700 9px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
192
|
+
letter-spacing: 0.08em;
|
|
193
|
+
pointer-events: none;
|
|
194
|
+
}
|
|
195
|
+
[data-jx-layout-region] [data-jx-layout-region]::before {
|
|
196
|
+
content: none;
|
|
197
|
+
}
|
|
168
198
|
`;
|
|
169
199
|
|
|
170
200
|
/**
|
|
@@ -187,6 +217,22 @@ export function syncEditModeCss(doc: Document, mode: CanvasMode): void {
|
|
|
187
217
|
doc.head.append(style);
|
|
188
218
|
}
|
|
189
219
|
|
|
220
|
+
/**
|
|
221
|
+
* Flag the canvas document as a preview shell, so `canvas.html`'s preview rules apply.
|
|
222
|
+
*
|
|
223
|
+
* The document's default box is built for EDITING: `html, body { overflow: hidden }`, because the
|
|
224
|
+
* host grows the iframe to its content height there and the parent canvas is what pans. Preview
|
|
225
|
+
* inverts that — the frame stays at the pane's height and the document scrolls itself — and until
|
|
226
|
+
* this existed nothing turned the clipping off, so preview showed the first screenful of every page
|
|
227
|
+
* and no more. An attribute rather than an injected stylesheet: the rules it switches live beside
|
|
228
|
+
* the ones they override, which is where a reader looks for them.
|
|
229
|
+
*
|
|
230
|
+
* Called on every render because one iframe is reused across modes.
|
|
231
|
+
*/
|
|
232
|
+
export function syncPreviewShell(doc: Document, mode: CanvasMode): void {
|
|
233
|
+
doc.documentElement.toggleAttribute("data-jx-preview", mode === "preview");
|
|
234
|
+
}
|
|
235
|
+
|
|
190
236
|
/**
|
|
191
237
|
* Whether a canvas mode gets a live caret. Design and edit are the interactive modes; preview must
|
|
192
238
|
* look and behave like the shipped page, and stylebook specimens are not documents.
|
|
@@ -429,7 +475,10 @@ export function injectHead(doc: JxDocument): void {
|
|
|
429
475
|
}
|
|
430
476
|
}
|
|
431
477
|
|
|
432
|
-
/**
|
|
478
|
+
/**
|
|
479
|
+
* Build the `onNodeCreated` hook that stamps `data-jx-path` (page content) or `data-jx-layout-path`
|
|
480
|
+
* + `data-jx-layout-file` (layout-originated nodes) on rendered nodes.
|
|
481
|
+
*/
|
|
433
482
|
export function makeStamper(ctx: PathMapCtx) {
|
|
434
483
|
return (created: Node, path: (string | number)[], def: unknown) => {
|
|
435
484
|
if (!(created instanceof HTMLElement)) {
|
|
@@ -459,7 +508,25 @@ export function makeStamper(ctx: PathMapCtx) {
|
|
|
459
508
|
}
|
|
460
509
|
const classified = classifyRenderNode(path, def, ctx);
|
|
461
510
|
if (classified.kind === "layout") {
|
|
462
|
-
|
|
511
|
+
// A layout node has no page-document path, but it is NOT anonymous: stamp where it came from
|
|
512
|
+
// So a click on it can select it and offer to open the layout at that node. Without this the
|
|
513
|
+
// Two most clickable strings on a brand-new project ("My Site", "Built with Jx") answered a
|
|
514
|
+
// Click with nothing at all.
|
|
515
|
+
created.dataset.jxLayoutPath = serializeJxPath(classified.layoutPath);
|
|
516
|
+
if (classified.layoutFile) {
|
|
517
|
+
created.dataset.jxLayoutFile = classified.layoutFile;
|
|
518
|
+
}
|
|
519
|
+
if (classified.chrome) {
|
|
520
|
+
// Chrome — a region of the layout that does NOT wrap the page content. Marked so the canvas
|
|
521
|
+
// Can dim and label it, and frozen so no caret can land there. The container is permanently
|
|
522
|
+
// `contenteditable`, so without this the browser happily put a caret in the site header and
|
|
523
|
+
// Then dropped every keystroke on the floor at the `beforeinput` chokepoint: the one place a
|
|
524
|
+
// New author is most likely to click looked editable and silently was not.
|
|
525
|
+
created.dataset.jxLayoutRegion = "";
|
|
526
|
+
if (isEditableMode(ctx.canvasMode)) {
|
|
527
|
+
created.contentEditable = "false";
|
|
528
|
+
}
|
|
529
|
+
}
|
|
463
530
|
return;
|
|
464
531
|
}
|
|
465
532
|
created.dataset.jxPath = serializeJxPath(classified.path);
|
|
@@ -542,6 +609,7 @@ export async function renderResolvedDocument(opts: {
|
|
|
542
609
|
applySiteStyle(opts.siteStyle, (opts.doc as { $media?: Record<string, string> }).$media ?? {});
|
|
543
610
|
injectHead(opts.doc);
|
|
544
611
|
syncEditModeCss(opts.container.ownerDocument, opts.mode);
|
|
612
|
+
syncPreviewShell(opts.container.ownerDocument, opts.mode);
|
|
545
613
|
syncStylebookCss(opts.container.ownerDocument, opts.mode);
|
|
546
614
|
// Seed the runtime's root $media before buildScope so a COMPONENT with its own `@--name` blocks
|
|
547
615
|
// But no own `$media` resolves the breakpoint to its real query (the iframe path calls buildScope
|
|
@@ -59,6 +59,12 @@ export function startIframeSlashBridge(
|
|
|
59
59
|
filter,
|
|
60
60
|
kind: "slashShow",
|
|
61
61
|
rect: { height: r.height, width: r.width, x: r.left, y: r.top },
|
|
62
|
+
/* Carried, because the parent draws the menu and only the FRAME knows why it opened. A
|
|
63
|
+
menu opened by name has no "/…" run in the document to filter with, so it needs its own
|
|
64
|
+
field; the "/" gesture needs none, because the author types into the block. This option
|
|
65
|
+
was dropped at this boundary and the loss was invisible — the menu still appeared, just
|
|
66
|
+
with no way past fifteen items but scrolling. */
|
|
67
|
+
...(cbs.showFilter === true ? { showFilter: true } : {}),
|
|
62
68
|
});
|
|
63
69
|
},
|
|
64
70
|
};
|
|
@@ -22,17 +22,67 @@ export interface PathMapCtx {
|
|
|
22
22
|
arrayPaths: Set<string>;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
/**
|
|
26
|
-
|
|
25
|
+
/**
|
|
26
|
+
* The marker `markLayoutNodes` stamps on every node of a resolved layout document (see
|
|
27
|
+
* {@link file://./canvas-live-render.ts}). It names the layout FILE and the node's own path inside
|
|
28
|
+
* that file — enough for the editor to select the node, label it, and open the layout at it. It
|
|
29
|
+
* used to be a bare `true`, which is why clicking layout chrome on a fresh project selected nothing
|
|
30
|
+
* at all: the render had thrown away the only two facts needed to act on the click.
|
|
31
|
+
*/
|
|
32
|
+
export interface LayoutMarker {
|
|
33
|
+
/** Project-relative path of the layout document, e.g. `layouts/base.json`. */
|
|
34
|
+
file: string;
|
|
35
|
+
/** The node's path WITHIN the layout document. */
|
|
36
|
+
path: JxPath;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* A render node either belongs to the layout (carrying its origin in the layout file, since it has
|
|
41
|
+
* no page-document path) or maps to a page-document path.
|
|
42
|
+
*
|
|
43
|
+
* `chrome` distinguishes the two very different kinds of layout node. Most are chrome — a header, a
|
|
44
|
+
* footer, a `<noscript>` — regions the page cannot edit in place. But the nodes on the path down to
|
|
45
|
+
* the `<slot>` (the layout root, the `<main>` around it) WRAP the page content, so they must stay
|
|
46
|
+
* transparent: dimming or freezing them would dim and freeze the whole document. Only chrome is
|
|
47
|
+
* dimmed, labelled, and made `contenteditable="false"`.
|
|
48
|
+
*/
|
|
49
|
+
export type RenderNodeClass =
|
|
50
|
+
| { kind: "layout"; layoutFile: string; layoutPath: JxPath; chrome: boolean }
|
|
51
|
+
| { kind: "path"; path: JxPath };
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Whether `path` is the page-content container or one of its ancestors — i.e. whether this node's
|
|
55
|
+
* subtree contains the distributed page content. `prefix` is the render path of the container whose
|
|
56
|
+
* children hold that content (`PathMapCtx.pageContentPrefix`).
|
|
57
|
+
*/
|
|
58
|
+
export function wrapsPageContent(path: JxPath, prefix: JxPath | null): boolean {
|
|
59
|
+
if (!prefix) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return path.length <= prefix.length && path.every((seg, i) => prefix[i] === seg);
|
|
63
|
+
}
|
|
27
64
|
|
|
28
65
|
/**
|
|
29
66
|
* Resolve a runtime render path to a document path (or flag it as layout-originated). Pure — the
|
|
30
|
-
* caller decides whether to record the result in a WeakMap or
|
|
67
|
+
* caller decides whether to record the result in a WeakMap or `data-jx-*` attributes.
|
|
31
68
|
*/
|
|
32
69
|
export function classifyRenderNode(path: JxPath, def: unknown, ctx: PathMapCtx): RenderNodeClass {
|
|
33
|
-
// Layout-originated nodes have no page-document path; the caller
|
|
34
|
-
|
|
35
|
-
|
|
70
|
+
// Layout-originated nodes have no page-document path; the caller stamps their origin instead
|
|
71
|
+
// (data-jx-layout-path / data-jx-layout-file).
|
|
72
|
+
const marker =
|
|
73
|
+
ctx.layoutWrapped && typeof def === "object"
|
|
74
|
+
? (def as { $__layout?: unknown } | null)?.$__layout
|
|
75
|
+
: undefined;
|
|
76
|
+
if (marker) {
|
|
77
|
+
const origin = (typeof marker === "object" ? marker : {}) as Partial<LayoutMarker>;
|
|
78
|
+
return {
|
|
79
|
+
// The root is never chrome even when the layout distributed nothing: it IS the render, and a
|
|
80
|
+
// Dimmed, frozen root would be a canvas nobody can touch.
|
|
81
|
+
chrome: path.length > 0 && !wrapsPageContent(path, ctx.pageContentPrefix),
|
|
82
|
+
kind: "layout",
|
|
83
|
+
layoutFile: typeof origin.file === "string" ? origin.file : "",
|
|
84
|
+
layoutPath: Array.isArray(origin.path) ? origin.path : [],
|
|
85
|
+
};
|
|
36
86
|
}
|
|
37
87
|
|
|
38
88
|
let mappedPath = path;
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
/**
|
|
3
|
+
* The surface REGISTRY — one stage record per pane, and nothing that knows what a pane contains.
|
|
4
|
+
*
|
|
5
|
+
* A pane is the unit of split, focus and zoom (§4.1), so it is also the unit of RENDER. The panels
|
|
6
|
+
* a pass mounted, the host element they mounted into, the mode that pass was drawn in and the full
|
|
7
|
+
* render a failed patch escalates to are all facts about ONE pane; they were app-level singletons
|
|
8
|
+
* only because the shell had a single stage.
|
|
9
|
+
*
|
|
10
|
+
* They could not stay that way. `classifyOps` gated a patch on `canvasPanels.every(p => p.ready)`
|
|
11
|
+
* and on one `getCanvasMode()`, and `escalateToFullRender` scheduled the one global render — so the
|
|
12
|
+
* moment a second stage exists, an edit typed into one pane would be refused because the OTHER
|
|
13
|
+
* pane's canvas was still mounting, and every escalation would re-render both. That is a
|
|
14
|
+
* correctness bug, not a performance one, which is why this lands before the second host rather
|
|
15
|
+
* than with it.
|
|
16
|
+
*
|
|
17
|
+
* A surface is addressed by pane id and nothing else. `panels/pane-grid.ts` builds a cell per pane
|
|
18
|
+
* and registers its stage as it goes.
|
|
19
|
+
*
|
|
20
|
+
* **Split from `canvas-surface.ts` for one reason: the WORKSPACE.** The helpers that answer "which
|
|
21
|
+
* tab is this pane showing" need `workspace/workspace.ts`, and `workspace.ts` needs
|
|
22
|
+
* `services/monaco-buffer.ts` — which in turn has to enumerate every stage's source buffer, because
|
|
23
|
+
* a close gate that asked only "the" Monaco would miss whichever pane it was not holding. That is a
|
|
24
|
+
* cycle. The store of records has no opinion about tabs, so it is the half that comes out.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import type { CanvasPanel } from "../types";
|
|
28
|
+
import type { MonacoSurface } from "../view";
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The class name every pane's stage element carries.
|
|
32
|
+
*
|
|
33
|
+
* Declared here rather than in the grid because it is what the two genuinely document-level
|
|
34
|
+
* gestures test with `closest()` — "is this event over SOME stage" is a question about surfaces,
|
|
35
|
+
* not about the reconciler that happens to build them.
|
|
36
|
+
*/
|
|
37
|
+
export const STAGE_CLASS = "pane-stage";
|
|
38
|
+
|
|
39
|
+
/** One pane's stage: where it renders, what it mounted there, and what it last drew. */
|
|
40
|
+
export interface CanvasSurface {
|
|
41
|
+
/** The pane this stage belongs to. Stable for the life of the pane. */
|
|
42
|
+
readonly paneId: string;
|
|
43
|
+
/**
|
|
44
|
+
* The element the pane's stage renders into.
|
|
45
|
+
*
|
|
46
|
+
* Typed non-null and initialised null, exactly as the shell refs in `store.ts` are: a surface is
|
|
47
|
+
* addressable before its host exists in the DOM, and every renderer runs after `initShellRefs`.
|
|
48
|
+
*/
|
|
49
|
+
wrap: HTMLElement;
|
|
50
|
+
/** The panels the last pass mounted here. Mutated in place by the render, never reassigned. */
|
|
51
|
+
readonly panels: CanvasPanel[];
|
|
52
|
+
/**
|
|
53
|
+
* The effective canvas mode this stage last drew, or null before its first pass.
|
|
54
|
+
*
|
|
55
|
+
* Per-surface because it decides a TEARDOWN: a mode transition rebuilds the panel structure, and
|
|
56
|
+
* one pane switching from Design to Code must not make the other pane's next pass believe its own
|
|
57
|
+
* structure is stale.
|
|
58
|
+
*/
|
|
59
|
+
prevCanvasMode: string | null;
|
|
60
|
+
/**
|
|
61
|
+
* The transformed element the pan/zoom modes draw into, or null in the modes that render none.
|
|
62
|
+
*
|
|
63
|
+
* Per-surface because it IS the stage's content. `view.panzoomWrap` held whichever pane painted
|
|
64
|
+
* last, so a fit computed for one pane wrote a transform onto the other's artboards.
|
|
65
|
+
*/
|
|
66
|
+
panzoomWrap: HTMLElement | null;
|
|
67
|
+
/** The observer that re-centres this stage until the author pans it. One per stage. */
|
|
68
|
+
centerObserver: ResizeObserver | null;
|
|
69
|
+
/** Whether this stage still wants re-centring — cleared by the first deliberate pan. */
|
|
70
|
+
needsCenter: boolean;
|
|
71
|
+
panX: number;
|
|
72
|
+
panY: number;
|
|
73
|
+
/** The source view's Monaco, mounted into THIS stage. Two Code panes are two models. */
|
|
74
|
+
monacoEditor: MonacoSurface | null;
|
|
75
|
+
/**
|
|
76
|
+
* The Stylebook filter and Customized flag THIS stage's catalogue was last built for.
|
|
77
|
+
*
|
|
78
|
+
* A one-slot module cache, until two panes started evicting each other from it.
|
|
79
|
+
* `shell.stylebook.filter` is a render input for every pane, so both stages render in the same
|
|
80
|
+
* frame: the first stored the new filter and rebuilt, the second compared against a slot the
|
|
81
|
+
* first had already advanced, found "nothing changed", and returned through the cheap
|
|
82
|
+
* `postStyleUpdateToStylebookHosts` path with its catalogue still listing the previous filter's
|
|
83
|
+
* specimens. Which pane lost was decided by render order, and it stayed wrong until a mode
|
|
84
|
+
* change. `null` means "this stage has never drawn a catalogue", which is not the same as "drew
|
|
85
|
+
* one for the empty filter" — the first pass must always rebuild.
|
|
86
|
+
*/
|
|
87
|
+
prevStylebookFilter: string | null;
|
|
88
|
+
prevStylebookCustomizedOnly: boolean | null;
|
|
89
|
+
/** Teardown for this stage's source-mode collab binding (unbind + release the lock). */
|
|
90
|
+
sourceCollabCleanup: (() => void) | null;
|
|
91
|
+
/**
|
|
92
|
+
* The generation of the last render pass this stage opened.
|
|
93
|
+
*
|
|
94
|
+
* Per-surface because it is a STALENESS comparison within one pane: a deferred artboard asks "is
|
|
95
|
+
* the pass I belong to still the current one HERE". While it was app-wide, pane A opening a pass
|
|
96
|
+
* invalidated pane B's in-flight one, so B's artboards 1..n never reached `ready` and every edit
|
|
97
|
+
* in B escalated to a full render, permanently. The VALUES are still globally unique — see
|
|
98
|
+
* {@link nextRenderGeneration} — because the iframe host caches a pass's resolved document by
|
|
99
|
+
* generation identity.
|
|
100
|
+
*/
|
|
101
|
+
renderGeneration: number;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* The next render generation, monotonic across every surface.
|
|
106
|
+
*
|
|
107
|
+
* Unique across panes even though the comparison is per-pane: `iframe-host.ts`'s
|
|
108
|
+
* `preparePassRender` caches the resolved+serialized document on `byDoc` keyed by the generation's
|
|
109
|
+
* identity, so two surfaces reusing the number would thrash that cache — and the frame's own
|
|
110
|
+
* `latestGen` drop rule would start discarding the other pane's live renders.
|
|
111
|
+
*/
|
|
112
|
+
let _nextGen = 0;
|
|
113
|
+
|
|
114
|
+
/** Take the next globally-unique render generation. */
|
|
115
|
+
export function nextRenderGeneration(): number {
|
|
116
|
+
_nextGen += 1;
|
|
117
|
+
return _nextGen;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const _surfaces = new Map<string, CanvasSurface>();
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* The surface record for a pane, created on first mention.
|
|
124
|
+
*
|
|
125
|
+
* Created rather than looked up so every reader has an answer before the host is attached — the
|
|
126
|
+
* same contract `store.ts`'s shell refs have, and what keeps `activeCanvasSurface()` non-nullable.
|
|
127
|
+
*
|
|
128
|
+
* @param {string} paneId
|
|
129
|
+
* @returns {CanvasSurface}
|
|
130
|
+
*/
|
|
131
|
+
export function surfaceForPane(paneId: string): CanvasSurface {
|
|
132
|
+
let surface = _surfaces.get(paneId);
|
|
133
|
+
if (!surface) {
|
|
134
|
+
surface = freshSurface(paneId);
|
|
135
|
+
_surfaces.set(paneId, surface);
|
|
136
|
+
}
|
|
137
|
+
return surface;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** A surface record with nothing in it. One place the per-stage defaults are written down. */
|
|
141
|
+
function freshSurface(paneId: string): CanvasSurface {
|
|
142
|
+
return {
|
|
143
|
+
centerObserver: null,
|
|
144
|
+
monacoEditor: null,
|
|
145
|
+
needsCenter: true,
|
|
146
|
+
panX: 0,
|
|
147
|
+
panY: 0,
|
|
148
|
+
panels: [],
|
|
149
|
+
paneId,
|
|
150
|
+
panzoomWrap: null,
|
|
151
|
+
prevCanvasMode: null,
|
|
152
|
+
prevStylebookCustomizedOnly: null,
|
|
153
|
+
prevStylebookFilter: null,
|
|
154
|
+
renderGeneration: 0,
|
|
155
|
+
sourceCollabCleanup: null,
|
|
156
|
+
wrap: null as unknown as HTMLElement,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Every registered surface, in registration order. The grid's inventory, and the tests'.
|
|
162
|
+
*
|
|
163
|
+
* @returns {CanvasSurface[]}
|
|
164
|
+
*/
|
|
165
|
+
export function allCanvasSurfaces(): CanvasSurface[] {
|
|
166
|
+
return [..._surfaces.values()];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* The stage `node` sits inside, or null when it is outside every one of them.
|
|
171
|
+
*
|
|
172
|
+
* The N-stage replacement for `canvasWrap.contains(target)`. Two document-level gestures — the
|
|
173
|
+
* browser-zoom block and the wheel forwarded out of a frame — need "which stage is this in", and
|
|
174
|
+
* with one stage they were allowed to spell it as "is it in THE stage".
|
|
175
|
+
*
|
|
176
|
+
* @param {Node | null} node
|
|
177
|
+
* @returns {CanvasSurface | null}
|
|
178
|
+
*/
|
|
179
|
+
export function stageContaining(node: Node | null): CanvasSurface | null {
|
|
180
|
+
if (!node) {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
for (const surface of _surfaces.values()) {
|
|
184
|
+
if (surface.wrap?.contains(node)) {
|
|
185
|
+
return surface;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Forget everything a surface's last pass mounted.
|
|
193
|
+
*
|
|
194
|
+
* Dropping the panel records is not enough: each artboard owns a render `EffectScope` (and the
|
|
195
|
+
* surgical-subtree scopes nested inside it) that goes on reacting to the document until it is
|
|
196
|
+
* stopped. The render path has always stopped them before emptying the array; a surface whose HOST
|
|
197
|
+
* changes hands has to do exactly the same, or every handover leaks one live scope per artboard —
|
|
198
|
+
* scopes that then repaint DOM belonging to a stage this pane no longer has.
|
|
199
|
+
*/
|
|
200
|
+
export function releaseMountedPanels(surface: CanvasSurface): void {
|
|
201
|
+
for (const panel of surface.panels) {
|
|
202
|
+
panel.renderScope?.stop();
|
|
203
|
+
panel.renderScope = null;
|
|
204
|
+
}
|
|
205
|
+
surface.panels.length = 0;
|
|
206
|
+
surface.prevCanvasMode = null;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Attach a pane's stage element. Called once per host that exists in the shell.
|
|
211
|
+
*
|
|
212
|
+
* A fresh host carries nothing over: the panels named by the previous one are detached DOM and the
|
|
213
|
+
* mode it last drew describes a structure that is gone, so both are cleared here rather than by
|
|
214
|
+
* each caller remembering to.
|
|
215
|
+
*
|
|
216
|
+
* @param {string} paneId
|
|
217
|
+
* @param {HTMLElement} wrap
|
|
218
|
+
* @returns {CanvasSurface}
|
|
219
|
+
*/
|
|
220
|
+
export function registerCanvasSurface(paneId: string, wrap: HTMLElement): CanvasSurface {
|
|
221
|
+
const surface = surfaceForPane(paneId);
|
|
222
|
+
surface.wrap = wrap;
|
|
223
|
+
releaseMountedPanels(surface);
|
|
224
|
+
return surface;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/* There is no `moveCanvasStage`, and there is no handover.
|
|
228
|
+
§18.3 handed the shell's ONE stage to whichever pane had focus, because there was one stage. The
|
|
229
|
+
grid gives every pane its own, registered by `panels/pane-grid.ts` when the cell is built and
|
|
230
|
+
released when it is removed, so nothing moves and no pane is ever left describing DOM it does
|
|
231
|
+
not own. The rule that survives is {@link releaseMountedPanels}: a surface that loses its host
|
|
232
|
+
has to stop the render scope of every artboard it mounted, or each goes on repainting a stage
|
|
233
|
+
that is not there. */
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Build a pane's surface record from scratch, replacing anything a previous pane of that id left.
|
|
237
|
+
*
|
|
238
|
+
* The grid calls this as it builds a cell, BEFORE the stage element exists — a pane is complete
|
|
239
|
+
* before it is published (§18.1 rule 1), and that includes the record every renderer resolves
|
|
240
|
+
* through.
|
|
241
|
+
*
|
|
242
|
+
* @param {string} paneId
|
|
243
|
+
* @returns {CanvasSurface}
|
|
244
|
+
*/
|
|
245
|
+
export function createPaneSurface(paneId: string): CanvasSurface {
|
|
246
|
+
const existing = _surfaces.get(paneId);
|
|
247
|
+
if (existing) {
|
|
248
|
+
disposePaneSurface(paneId);
|
|
249
|
+
}
|
|
250
|
+
const surface = freshSurface(paneId);
|
|
251
|
+
_surfaces.set(paneId, surface);
|
|
252
|
+
return surface;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* How a surface releases the editors and observers its renders created.
|
|
257
|
+
*
|
|
258
|
+
* Injected, because the teardown lives in `canvas/canvas-render.ts` — which imports this module —
|
|
259
|
+
* and a surface record must stay reachable from the dependency-light half of the graph. Same idiom
|
|
260
|
+
* as `setIframePatchEscalation`.
|
|
261
|
+
*/
|
|
262
|
+
let _teardown: ((surface: CanvasSurface) => void) | null = null;
|
|
263
|
+
|
|
264
|
+
/** Register the per-surface teardown. Called once, at import time, by `canvas-render.ts`. */
|
|
265
|
+
export function setSurfaceTeardown(fn: ((surface: CanvasSurface) => void) | null): void {
|
|
266
|
+
_teardown = fn;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Release everything a pane's stage owns and forget the record.
|
|
271
|
+
*
|
|
272
|
+
* Ordered: the render-owned surfaces first (through the injected teardown — Monaco, the collab
|
|
273
|
+
* binding, the centering observer), then the artboards' render scopes, then the record. The DOM is
|
|
274
|
+
* the caller's: `pane-grid.ts` removes the cell, and `iframe-host.ts`'s `releaseCanvasHosts` tears
|
|
275
|
+
* the frames down BEFORE the removal, while they are still reachable from the stage.
|
|
276
|
+
*
|
|
277
|
+
* @param {string} paneId
|
|
278
|
+
*/
|
|
279
|
+
export function disposePaneSurface(paneId: string): void {
|
|
280
|
+
const surface = _surfaces.get(paneId);
|
|
281
|
+
if (!surface) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
_teardown?.(surface);
|
|
285
|
+
releaseMountedPanels(surface);
|
|
286
|
+
unregisterCanvasSurface(paneId);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** Forget a pane's surface record without releasing anything. Tests, and the app reset. */
|
|
290
|
+
export function unregisterCanvasSurface(paneId: string): void {
|
|
291
|
+
_surfaces.delete(paneId);
|
|
292
|
+
}
|