@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
|
@@ -22,8 +22,12 @@
|
|
|
22
22
|
import {
|
|
23
23
|
commitActiveBlock,
|
|
24
24
|
getActiveElement,
|
|
25
|
+
handleSlashTrigger,
|
|
25
26
|
isEditableBlock,
|
|
26
27
|
isEditing,
|
|
28
|
+
isSlashActive,
|
|
29
|
+
openSlashMenu,
|
|
30
|
+
refreshSlashMenu,
|
|
27
31
|
splitActiveBlock,
|
|
28
32
|
startEditing,
|
|
29
33
|
stopEditing,
|
|
@@ -452,6 +456,23 @@ export function startIframeInlineEdit(
|
|
|
452
456
|
onSplit: () => splitActiveBlock(),
|
|
453
457
|
});
|
|
454
458
|
|
|
459
|
+
/* The slash gesture, at the EDITING HOST.
|
|
460
|
+
`editor/inline-edit.ts` recognised "/" in a `keydown` listener it attached to the BLOCK, and
|
|
461
|
+
for an ordinary block the editing host is this container — so the focused element, and every
|
|
462
|
+
keydown's target, is the container and that listener never fired. Typing "/" in the canvas
|
|
463
|
+
simply inserted a slash: the menu the docs describe, and the shot the manifest quarantined,
|
|
464
|
+
had no trigger at all. It is recognised here, where the keystrokes are, and the engine still
|
|
465
|
+
owns what a slash MEANS (start of a block or after a space; anywhere else it is punctuation).
|
|
466
|
+
The matching `input` half re-filters the open menu, for the same reason: a contenteditable's
|
|
467
|
+
`input` targets its host, not the block the caret happens to be in. */
|
|
468
|
+
const onSlashKey = (e: Event) => handleSlashTrigger(e as KeyboardEvent);
|
|
469
|
+
const onSlashInput = () => {
|
|
470
|
+
if (isSlashActive()) {
|
|
471
|
+
refreshSlashMenu();
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
container.addEventListener("keydown", onSlashKey);
|
|
475
|
+
container.addEventListener("input", onSlashInput);
|
|
455
476
|
doc.addEventListener("mouseup", onMouseUp, true);
|
|
456
477
|
doc.addEventListener("keyup", onKeyUp, true);
|
|
457
478
|
doc.addEventListener("blur", onBlurCapture, true);
|
|
@@ -461,6 +482,14 @@ export function startIframeInlineEdit(
|
|
|
461
482
|
applyFormatIntent(msg.intent);
|
|
462
483
|
return;
|
|
463
484
|
}
|
|
485
|
+
if (msg.kind === "openSlash") {
|
|
486
|
+
/* Opened BY NAME, so there is no "/" in the document to anchor it — the engine gives this
|
|
487
|
+
menu its own filter field and deletes nothing when a block is chosen. `openSlashMenu`
|
|
488
|
+
refuses when no caret session is live, which is the same refusal the record's `requires`
|
|
489
|
+
sentence states. */
|
|
490
|
+
openSlashMenu({ anchored: false });
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
464
493
|
if (msg.kind === "flushEdits") {
|
|
465
494
|
// Commit anything the idle tick has not yet written, THEN acknowledge. The commit is posted
|
|
466
495
|
// First, so a parent that has seen the acknowledgement has already applied the text.
|
|
@@ -492,6 +521,8 @@ export function startIframeInlineEdit(
|
|
|
492
521
|
});
|
|
493
522
|
|
|
494
523
|
return () => {
|
|
524
|
+
container.removeEventListener("keydown", onSlashKey);
|
|
525
|
+
container.removeEventListener("input", onSlashInput);
|
|
495
526
|
doc.removeEventListener("mouseup", onMouseUp, true);
|
|
496
527
|
doc.removeEventListener("keyup", onKeyUp, true);
|
|
497
528
|
doc.removeEventListener("blur", onBlurCapture, true);
|
|
@@ -95,8 +95,10 @@ export interface InteractionDeps {
|
|
|
95
95
|
*/
|
|
96
96
|
getShadowDoc: () => JxMutableNode | null;
|
|
97
97
|
/**
|
|
98
|
-
* The live render's canvas mode.
|
|
99
|
-
*
|
|
98
|
+
* The live render's canvas mode. Editing affordances are suppressed per mode: insertion "+" zones
|
|
99
|
+
* are meaningless for stylebook renders (specimens aren't insert targets), and preview reports
|
|
100
|
+
* nothing at all beyond link intent — no hit, no hover, no zones, no Jx context menu — because a
|
|
101
|
+
* preview is the shipped page, not a document you can point at. Absent = permissive.
|
|
100
102
|
*/
|
|
101
103
|
getMode?: () => string;
|
|
102
104
|
/**
|
|
@@ -129,6 +131,31 @@ export function startInteraction(
|
|
|
129
131
|
let lastZonesKey: string | null = null;
|
|
130
132
|
let lastGen = deps?.getGen?.() ?? 0;
|
|
131
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Whether this render is a preview. Preview is the fidelity view: it has no selection, no hover
|
|
136
|
+
* box, no insertion "+" and no Jx element menu, so the frame reports none of them. (The host
|
|
137
|
+
* refuses the same messages independently — the iframe bundle ships prebuilt, so neither side may
|
|
138
|
+
* rely on the other's build being current.)
|
|
139
|
+
*/
|
|
140
|
+
const isPreview = () => deps?.getMode?.() === "preview";
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Report that the person is now working in this frame's pane — every mode, every button, every
|
|
144
|
+
* target.
|
|
145
|
+
*
|
|
146
|
+
* `pointerdown` rather than `click`, and unconditional rather than mode-gated, because both of
|
|
147
|
+
* `hit`'s holes are holes in what a CLICK means here. In preview there is no `hit` by design (a
|
|
148
|
+
* click in preview is a click on the page), and in edit/design `hit` is posted only when the
|
|
149
|
+
* click lands on a `[data-jx-path]` node — so an artboard's empty margin, a right-click, and
|
|
150
|
+
* every single interaction with a Preview pane all left the keyboard in the other pane.
|
|
151
|
+
*
|
|
152
|
+
* It carries nothing, which is what makes it safe to send from preview: the parent moves pane
|
|
153
|
+
* focus and does not touch the document, so the page underneath is still just a page.
|
|
154
|
+
*/
|
|
155
|
+
const onPointerDown = () => {
|
|
156
|
+
channel.post({ kind: "paneFocus" });
|
|
157
|
+
};
|
|
158
|
+
|
|
132
159
|
const onClick = (e: Event) => {
|
|
133
160
|
/*
|
|
134
161
|
* Preview keeps anchors live, so a click would navigate this iframe and destroy the render (and
|
|
@@ -139,18 +166,29 @@ export function startInteraction(
|
|
|
139
166
|
* Design/edit never reach this: the runtime de-links anchors onto `data-jx-href` there, so there
|
|
140
167
|
* is no navigation to intercept and a click means "select this element".
|
|
141
168
|
*/
|
|
142
|
-
if (
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
169
|
+
if (isPreview()) {
|
|
170
|
+
if (e.target instanceof Element) {
|
|
171
|
+
const anchor = e.target.closest("a[href]");
|
|
172
|
+
const href = anchor?.getAttribute("href");
|
|
173
|
+
if (href && !href.startsWith("#")) {
|
|
174
|
+
e.preventDefault();
|
|
175
|
+
channel.post({ href, kind: "previewNavigate" });
|
|
176
|
+
}
|
|
149
177
|
}
|
|
178
|
+
// No hit post: a click in preview is a click on the page, never a selection.
|
|
179
|
+
return;
|
|
150
180
|
}
|
|
151
181
|
const hit = nearestHit(e.target);
|
|
152
182
|
if (hit) {
|
|
153
|
-
|
|
183
|
+
// Ctrl/Cmd is the accumulate gesture (§6.5). The iframe reports the modifier and nothing
|
|
184
|
+
// Else — it holds no selection state, so what a modified click MEANS is the parent's to
|
|
185
|
+
// Decide, exactly as the unmodified click already was.
|
|
186
|
+
const mouse = e as MouseEvent;
|
|
187
|
+
channel.post({
|
|
188
|
+
additive: mouse.ctrlKey === true || mouse.metaKey === true,
|
|
189
|
+
hit,
|
|
190
|
+
kind: "hit",
|
|
191
|
+
});
|
|
154
192
|
}
|
|
155
193
|
};
|
|
156
194
|
|
|
@@ -163,6 +201,9 @@ export function startInteraction(
|
|
|
163
201
|
* the key was ever compared — a forced layout per mouse move, thrown away almost every time.
|
|
164
202
|
*/
|
|
165
203
|
const reportHover = (el: HTMLElement | null) => {
|
|
204
|
+
if (isPreview()) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
166
207
|
const key = el?.dataset.jxPath ?? null;
|
|
167
208
|
if (key === lastHoverKey) {
|
|
168
209
|
return;
|
|
@@ -186,7 +227,7 @@ export function startInteraction(
|
|
|
186
227
|
|
|
187
228
|
/** Resolve + post the insertion "+" zones for an iframe-viewport cursor, deduped by key. */
|
|
188
229
|
const reportInsertZones = (target: EventTarget | null, cursor: { x: number; y: number }) => {
|
|
189
|
-
if (!deps || deps.getMode?.() === "stylebook") {
|
|
230
|
+
if (!deps || deps.getMode?.() === "stylebook" || isPreview()) {
|
|
190
231
|
return;
|
|
191
232
|
}
|
|
192
233
|
syncZoneGen();
|
|
@@ -242,7 +283,7 @@ export function startInteraction(
|
|
|
242
283
|
return;
|
|
243
284
|
}
|
|
244
285
|
reportHover(null);
|
|
245
|
-
if (deps && lastZonesKey !== "none") {
|
|
286
|
+
if (deps && !isPreview() && lastZonesKey !== "none") {
|
|
246
287
|
lastZonesKey = "none";
|
|
247
288
|
channel.post({ kind: "insertZones", zones: null });
|
|
248
289
|
}
|
|
@@ -250,23 +291,41 @@ export function startInteraction(
|
|
|
250
291
|
|
|
251
292
|
const onContextMenu = (e: Event) => {
|
|
252
293
|
const me = e as MouseEvent;
|
|
294
|
+
// Preview keeps the NATIVE menu: the Jx element menu's verbs (duplicate, delete, paste, wrap)
|
|
295
|
+
// Are document edits, and preview does not edit. Copy Link Address does what it says instead.
|
|
296
|
+
if (isPreview()) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
253
299
|
// Inside the ACTIVE editable keep the NATIVE menu (spellcheck / paste) — the session owns it.
|
|
254
300
|
const active = isEditing() ? getActiveElement() : null;
|
|
255
301
|
if (active && e.target instanceof Node && active.contains(e.target)) {
|
|
256
302
|
return;
|
|
257
303
|
}
|
|
258
|
-
// Suppress the browser menu everywhere else (legacy parity — the deleted panel-events handler
|
|
259
|
-
// PreventDefaulted even with no element hit) and let the parent show the Jx element menu.
|
|
260
|
-
e.preventDefault();
|
|
261
304
|
const hit = nearestHit(e.target);
|
|
305
|
+
/*
|
|
306
|
+
* NO ELEMENT UNDER THE POINTER — keep the browser's menu.
|
|
307
|
+
*
|
|
308
|
+
* This called `preventDefault()` before looking, "legacy parity" with a handler that did the
|
|
309
|
+
* same. The parent then posts `path: null`, `showContextMenu` returns early on it, and the
|
|
310
|
+
* result is a right-click that suppresses the browser menu and shows nothing in its place:
|
|
311
|
+
* plan §10's dead zone, named there as the thing to fix. The margin around the artboard is
|
|
312
|
+
* exactly where a reader reaches for View Source or Inspect.
|
|
313
|
+
*/
|
|
314
|
+
if (!hit) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
// An element IS under the pointer, so the Jx element menu is the right answer and the browser's
|
|
318
|
+
// Would be a worse one.
|
|
319
|
+
e.preventDefault();
|
|
262
320
|
channel.post({
|
|
263
321
|
kind: "contextMenu",
|
|
264
|
-
path: hit
|
|
322
|
+
path: hit.path,
|
|
265
323
|
x: me.clientX,
|
|
266
324
|
y: me.clientY,
|
|
267
325
|
});
|
|
268
326
|
};
|
|
269
327
|
|
|
328
|
+
doc.addEventListener("pointerdown", onPointerDown, true);
|
|
270
329
|
doc.addEventListener("click", onClick, true);
|
|
271
330
|
doc.addEventListener("pointermove", onMove, true);
|
|
272
331
|
doc.addEventListener("pointerleave", onLeave, true);
|
|
@@ -277,6 +336,7 @@ export function startInteraction(
|
|
|
277
336
|
cancelRaf(movePending);
|
|
278
337
|
movePending = 0;
|
|
279
338
|
}
|
|
339
|
+
doc.removeEventListener("pointerdown", onPointerDown, true);
|
|
280
340
|
doc.removeEventListener("click", onClick, true);
|
|
281
341
|
doc.removeEventListener("pointermove", onMove, true);
|
|
282
342
|
doc.removeEventListener("pointerleave", onLeave, true);
|
|
@@ -1,66 +1,121 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
/**
|
|
3
|
-
* In-iframe keyboard forwarding
|
|
4
|
-
* moves into the canvas iframe (a click selects a node there) undo/redo/save/delete/duplicate/arrow
|
|
5
|
-
* navigation stop firing. This captures the global-shortcut subset inside the iframe, prevents the
|
|
6
|
-
* browser default, and posts a flattened event the parent re-dispatches to its shortcut handler.
|
|
3
|
+
* In-iframe keyboard forwarding — one authority, synced from the host's keymap.
|
|
7
4
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* Studio's chords are dispatched against the EDITOR document, so once focus moves into the canvas
|
|
6
|
+
* iframe (a click selects a node there) nothing the parent binds fires. This captures the
|
|
7
|
+
* keystrokes the parent actually wants, prevents their default, and posts a flattened event the
|
|
8
|
+
* host re-dispatches into its own registry.
|
|
9
|
+
*
|
|
10
|
+
* **Which keystrokes those are is no longer written down here.** It used to be, in three
|
|
11
|
+
* hand-maintained lists — eight bare keys, four "the editor owns these" chords, three "the browser
|
|
12
|
+
* owns these" chords — kept beside a registry that already knew the answer, and they disagreed with
|
|
13
|
+
* it in both directions:
|
|
14
|
+
*
|
|
15
|
+
* - **⌘A was forwarded AND prevented.** No record binds it, so the host claimed nothing and select-
|
|
16
|
+
* all did nothing — while the `preventDefault` had already suppressed the browser's own, so a
|
|
17
|
+
* writer mid-sentence could not select their paragraph either. Two ways of doing nothing.
|
|
18
|
+
* - **⌘B was withheld**, on the list's stated assumption that "the editing engine implements it
|
|
19
|
+
* itself". It does not: `editor/inline-edit.ts`'s keydown listener is attached to the BLOCK while
|
|
20
|
+
* the editing host is the canvas container, so it never fires, and `canvas/editable-actions.ts`
|
|
21
|
+
* rejects the browser's native `formatBold` because Jx owns its own markup. Bold in the canvas
|
|
22
|
+
* did nothing at all, under a toolbar advertising ⌘B.
|
|
23
|
+
*
|
|
24
|
+
* So the frame is told the table instead ({@link ParentToIframe} `keymap`), and answers the
|
|
25
|
+
* question by RESOLVING: pick the scope stack the host would pick, and forward iff some scope in it
|
|
26
|
+
* claims the chord. Everything the three lists encoded falls out of that, without being encoded:
|
|
27
|
+
*
|
|
28
|
+
* - The clipboard trio is bound at `canvas` scope only (`editor/context-menu.ts`), so with a caret
|
|
29
|
+
* session live the stack is `["caret", "global"]`, nothing claims ⌘C/⌘X/⌘V, and the browser's own
|
|
30
|
+
* copy of the selected TEXT happens — the old `CLIPBOARD_CHORDS` contract, derived rather than
|
|
31
|
+
* listed.
|
|
32
|
+
* - The bare editing keys (Backspace, Enter, the arrows) are `canvas`-scoped for the same reason and
|
|
33
|
+
* behave the same way.
|
|
34
|
+
* - `format.*` is `caret`-scoped, so ⌘B forwards exactly while a caret exists and the host posts
|
|
35
|
+
* `applyFormat` back — the path the toolbar's own buttons have always taken.
|
|
36
|
+
*
|
|
37
|
+
* The remaining local rule is a real one: a genuine `INPUT` / `TEXTAREA` / `SELECT` inside the
|
|
38
|
+
* rendered page (an author's own form) keeps every keystroke, because Backspace and Enter are
|
|
39
|
+
* canvas-bound and a resolved table would happily prevent them mid-field.
|
|
11
40
|
*/
|
|
12
41
|
|
|
13
|
-
import
|
|
14
|
-
import type { IframeToParent, ParentToIframe, SerializedKey } from "./iframe-protocol";
|
|
42
|
+
import { chordFromEvent } from "../commands/keymap";
|
|
15
43
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"Escape",
|
|
21
|
-
"Enter",
|
|
22
|
-
"ArrowUp",
|
|
23
|
-
"ArrowDown",
|
|
24
|
-
"ArrowLeft",
|
|
25
|
-
"ArrowRight",
|
|
26
|
-
]);
|
|
44
|
+
import type { KeyScope } from "../commands/levels";
|
|
45
|
+
|
|
46
|
+
import type { IframeChannel } from "./iframe-channel";
|
|
47
|
+
import type { IframeToParent, ParentToIframe, SerializedKey, SyncedChord } from "./iframe-protocol";
|
|
27
48
|
|
|
28
49
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
50
|
+
* The three scopes a canvas frame can ever be dispatching under.
|
|
51
|
+
*
|
|
52
|
+
* The host projects exactly these out of the keymap ({@link import("../commands/keymap").
|
|
53
|
+
* chordsInScopes}) — narrower than "every scope", because the grid and code engines, the focused
|
|
54
|
+
* dock and the palette are other surfaces entirely and their chords must not make a canvas swallow
|
|
55
|
+
* a keystroke.
|
|
31
56
|
*/
|
|
32
|
-
const
|
|
57
|
+
export const FRAME_KEY_SCOPES = ["caret", "canvas", "global"] as const;
|
|
58
|
+
|
|
59
|
+
/** The scope stack a caret session is in — app chords still fire, element-level ones do not. */
|
|
60
|
+
const CARET_STACK = ["caret", "global"] as const;
|
|
61
|
+
/** The stack with a selection but no caret: structural verbs are live. */
|
|
62
|
+
const CANVAS_STACK = ["canvas", "global"] as const;
|
|
63
|
+
/** Preview draws no overlays and posts no hits, so element-level chords have nothing to aim at. */
|
|
64
|
+
const GLOBAL_STACK = ["global"] as const;
|
|
65
|
+
|
|
66
|
+
/** The synced table, plus the platform the chords were computed for. */
|
|
67
|
+
export interface ForwardTable {
|
|
68
|
+
mac: boolean;
|
|
69
|
+
chords: readonly SyncedChord[];
|
|
70
|
+
}
|
|
33
71
|
|
|
34
|
-
/**
|
|
35
|
-
|
|
72
|
+
/** An empty table — what the frame knows before the host's first `keymap` message arrives. */
|
|
73
|
+
export const NO_TABLE: ForwardTable = { chords: [], mac: false };
|
|
74
|
+
|
|
75
|
+
/** Whether `el` is a text-entry control in the RENDERED PAGE whose keystrokes are its own. */
|
|
76
|
+
function isPageTextEntry(el: EventTarget | null): boolean {
|
|
36
77
|
if (!(el instanceof HTMLElement)) {
|
|
37
78
|
return false;
|
|
38
79
|
}
|
|
39
|
-
if (el.isContentEditable) {
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
80
|
return el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.tagName === "SELECT";
|
|
43
81
|
}
|
|
44
82
|
|
|
45
83
|
/**
|
|
46
|
-
*
|
|
84
|
+
* The scope stack this keystroke would be dispatched under, host-side.
|
|
47
85
|
*
|
|
48
|
-
* The
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
86
|
+
* The same ladder as `commands/context.ts`'s `keyScopeStack`, minus the branches the frame cannot
|
|
87
|
+
* be in: there is no modal and no focused dock inside the canvas, and the grid and code engines are
|
|
88
|
+
* other editors entirely. Keeping the two in step is what makes the forwarding decision and the
|
|
89
|
+
* dispatch decision the same decision.
|
|
90
|
+
*/
|
|
91
|
+
export function frameScopeStack(sessionLive: boolean, mode: string): readonly KeyScope[] {
|
|
92
|
+
if (sessionLive) {
|
|
93
|
+
return CARET_STACK;
|
|
94
|
+
}
|
|
95
|
+
return mode === "preview" ? GLOBAL_STACK : CANVAS_STACK;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Whether the parent's registry claims this keystroke.
|
|
52
100
|
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* - Modifier chords are app commands and always forward, EXCEPT the inline-formatting ones the
|
|
56
|
-
* editing engine implements itself.
|
|
101
|
+
* `""` from {@link chordFromEvent} means a bare modifier — the start of every chord — and is never
|
|
102
|
+
* forwarded.
|
|
57
103
|
*/
|
|
58
|
-
export function shouldForwardKey(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
104
|
+
export function shouldForwardKey(
|
|
105
|
+
e: KeyboardEvent,
|
|
106
|
+
table: ForwardTable = NO_TABLE,
|
|
107
|
+
sessionLive = false,
|
|
108
|
+
mode = "design",
|
|
109
|
+
): boolean {
|
|
110
|
+
if (isPageTextEntry(e.target)) {
|
|
111
|
+
return false;
|
|
62
112
|
}
|
|
63
|
-
|
|
113
|
+
const chord = chordFromEvent(e, table.mac);
|
|
114
|
+
if (!chord) {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
const stack = frameScopeStack(sessionLive, mode);
|
|
118
|
+
return table.chords.some((entry) => entry.chord === chord && stack.includes(entry.scope));
|
|
64
119
|
}
|
|
65
120
|
|
|
66
121
|
/** Flatten a KeyboardEvent to the structured-cloneable subset the bridge carries. */
|
|
@@ -76,15 +131,22 @@ export function serializeKey(e: KeyboardEvent): SerializedKey {
|
|
|
76
131
|
}
|
|
77
132
|
|
|
78
133
|
/**
|
|
79
|
-
* Listen for
|
|
80
|
-
*
|
|
134
|
+
* Listen for the parent's chords on the iframe document, prevent their default, and forward them.
|
|
135
|
+
* Returns a teardown function.
|
|
136
|
+
*
|
|
137
|
+
* All three accessors are read PER KEYSTROKE, never captured: the table is replaced whenever the
|
|
138
|
+
* author rebinds a key, the session comes and goes under the same listener, and the mode changes
|
|
139
|
+
* without one.
|
|
81
140
|
*/
|
|
82
141
|
export function startKeyForwarding(
|
|
83
142
|
channel: IframeChannel<IframeToParent, ParentToIframe>,
|
|
84
143
|
doc: Document = document,
|
|
144
|
+
isSessionLive: () => boolean = () => false,
|
|
145
|
+
getTable: () => ForwardTable = () => NO_TABLE,
|
|
146
|
+
getMode: () => string = () => "design",
|
|
85
147
|
): () => void {
|
|
86
148
|
const onKey = (e: KeyboardEvent) => {
|
|
87
|
-
if (!shouldForwardKey(e)) {
|
|
149
|
+
if (!shouldForwardKey(e, getTable(), isSessionLive(), getMode())) {
|
|
88
150
|
return;
|
|
89
151
|
}
|
|
90
152
|
e.preventDefault();
|
|
@@ -70,6 +70,12 @@ export interface OverlayLayer {
|
|
|
70
70
|
* each call; pass [] to clear. Placements are overlay-local coords like setSelection's.
|
|
71
71
|
*/
|
|
72
72
|
setPresence: (items: { placement: OverlayPlacement; color: string; label: string }[]) => void;
|
|
73
|
+
/**
|
|
74
|
+
* Draw the NON-primary members of a multi-selection (§6.5). Replaces the whole set each call;
|
|
75
|
+
* pass [] to clear, which is what a selection of one always does — one selected node draws the
|
|
76
|
+
* selection box and nothing else, exactly as it did before the selection became a list.
|
|
77
|
+
*/
|
|
78
|
+
setCoSelection: (placements: OverlayPlacement[]) => void;
|
|
73
79
|
/** Position the hover box (or hide it when `placement` is null). */
|
|
74
80
|
setHover: (placement: OverlayPlacement | null) => void;
|
|
75
81
|
/**
|
|
@@ -97,6 +103,13 @@ export interface OverlayLayer {
|
|
|
97
103
|
* shows exactly one of them. `placement` is overlay-local like the others; null hides it.
|
|
98
104
|
*/
|
|
99
105
|
setReplaceTarget: (placement: OverlayPlacement | null) => void;
|
|
106
|
+
/**
|
|
107
|
+
* Hide (or restore) the whole layer. Preview renders get it suppressed: the editing affordances
|
|
108
|
+
* are gated message-by-message in the host, and this is the single switch that guarantees none of
|
|
109
|
+
* them can be PAINTED over a page that is supposed to look shipped — including any box a
|
|
110
|
+
* still-in-flight reply from a pre-preview render would otherwise land.
|
|
111
|
+
*/
|
|
112
|
+
setSuppressed: (suppressed: boolean) => void;
|
|
100
113
|
/** The clickable "+" button, so the caller can attach click + hover (grace-timer) listeners. */
|
|
101
114
|
readonly insertButton: HTMLButtonElement;
|
|
102
115
|
/** The layer root element (caller appends it over the iframe). */
|
|
@@ -164,7 +177,19 @@ export function createOverlayLayer(doc: Document = document): OverlayLayer {
|
|
|
164
177
|
const presenceGroup = doc.createElement("div");
|
|
165
178
|
presenceGroup.className = "overlay-presence-group";
|
|
166
179
|
|
|
167
|
-
|
|
180
|
+
// The other members of a multi-selection, same container discipline as presence.
|
|
181
|
+
const coSelectionGroup = doc.createElement("div");
|
|
182
|
+
coSelectionGroup.className = "overlay-coselection-group";
|
|
183
|
+
|
|
184
|
+
root.append(
|
|
185
|
+
hoverBox,
|
|
186
|
+
selectionBox,
|
|
187
|
+
coSelectionGroup,
|
|
188
|
+
dropBox,
|
|
189
|
+
replaceBox,
|
|
190
|
+
insertButton,
|
|
191
|
+
presenceGroup,
|
|
192
|
+
);
|
|
168
193
|
|
|
169
194
|
return {
|
|
170
195
|
dispose: () => root.remove(),
|
|
@@ -174,6 +199,18 @@ export function createOverlayLayer(doc: Document = document): OverlayLayer {
|
|
|
174
199
|
setHover: (placement) => place(hoverBox, placement),
|
|
175
200
|
setInsertZone: (placement, edge = "center") => placeInsertButton(insertButton, placement, edge),
|
|
176
201
|
setReplaceTarget: (placement) => place(replaceBox, placement),
|
|
202
|
+
setSuppressed: (suppressed) => {
|
|
203
|
+
root.style.display = suppressed ? "none" : "";
|
|
204
|
+
},
|
|
205
|
+
setCoSelection: (placements) => {
|
|
206
|
+
coSelectionGroup.replaceChildren();
|
|
207
|
+
for (const placement of placements) {
|
|
208
|
+
const box = doc.createElement("div");
|
|
209
|
+
box.className = "overlay-box overlay-selection overlay-coselection";
|
|
210
|
+
place(box, placement);
|
|
211
|
+
coSelectionGroup.append(box);
|
|
212
|
+
}
|
|
213
|
+
},
|
|
177
214
|
setPresence: (items) => {
|
|
178
215
|
presenceGroup.replaceChildren();
|
|
179
216
|
for (const item of items) {
|