@jxsuite/studio 6.1.2 → 8.0.1
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/README.md +5 -5
- package/dist/chunks/2020-5wtzce5g.js +4 -0
- package/dist/chunks/adapter-5tphg7xe.js +4 -0
- package/dist/chunks/add-new-flow-psym14sn.js +4 -0
- package/dist/chunks/cf-account-picker-haqazq5r.js +4 -0
- package/dist/chunks/cf-settings-h2wrh6hq.js +4 -0
- package/dist/chunks/{color-area-0fj8a4ga.js → color-area-6rbra5dy.js} +2 -2
- package/dist/chunks/{color-field-xch8kx2g.js → color-field-gy56c94g.js} +3 -3
- package/dist/chunks/color-m7r1vk54.js +4 -0
- package/dist/chunks/{color-slider-jxd8v350.js → color-slider-sqqdyf6c.js} +2 -2
- package/dist/chunks/{combobox-p0efwjke.js → combobox-72h32ejk.js} +3 -3
- package/dist/chunks/components-r22xca09.js +4 -0
- package/dist/chunks/content-source-mmppmcyg.js +4 -0
- package/dist/chunks/convert-to-repeater-he70fc2b.js +4 -0
- package/dist/chunks/editor-ccd9jwsa.js +4 -0
- package/dist/chunks/entry-commands-6qxz9e8p.js +4 -0
- package/dist/chunks/extension-sections-0egb88dm.js +4 -0
- package/dist/chunks/file-ops-qnab36ek.js +4 -0
- package/dist/chunks/files-rcn56qvm.js +4 -0
- package/dist/chunks/format-host-yxz0kjjs.js +4 -0
- package/dist/chunks/fs-events-d1qxq4z4.js +4 -0
- package/dist/chunks/grid-open-4z1g062t.js +4 -0
- package/dist/chunks/{grid-view-d2wq9ezg.js → grid-view-qg1b5eqx.js} +25 -25
- package/dist/chunks/{icons-pnfz478q.js → icons-63bjtbs7.js} +2 -2
- package/dist/chunks/{iframe-entry-jdcktez8.js → iframe-entry-2zggzajv.js} +4 -4
- package/dist/chunks/{iframe-entry-zap785cw.js → iframe-entry-76j8vwwx.js} +4 -4
- package/dist/chunks/iframe-entry-99nr5zfb.js +5 -0
- package/dist/chunks/{iframe-entry-x0ygf2yr.js → iframe-entry-pkgmcgp0.js} +4 -4
- package/dist/chunks/iframe-host-ssv7kyj0.js +4 -0
- package/dist/chunks/{index-zpjmzqfk.js → index-32eqzv1k.js} +3 -3
- package/dist/chunks/index-f0jn7nnp.js +4 -0
- package/dist/chunks/{javascript-m54mnwp6.js → javascript-pjp734q4.js} +3 -3
- package/dist/chunks/jsonMode-njkvsa02.js +13 -0
- package/dist/chunks/jx-validate-ttasrbh7.js +4 -0
- package/dist/chunks/layers-bgyr11tr.js +4 -0
- package/dist/chunks/layers-panel-7ez66zeq.js +4 -0
- package/dist/chunks/{listbox-e74qjyq6.js → listbox-c421cf8c.js} +2 -2
- package/dist/chunks/lit-html-v9gh687x.js +4 -0
- package/dist/chunks/media-library-sq468wts.js +4 -0
- package/dist/chunks/media-picker-shfe59pt.js +4 -0
- package/dist/chunks/{menu-n6yzswmy.js → menu-bdpzbfvs.js} +2 -2
- package/dist/chunks/{monaco-binding-7gx83x3r.js → monaco-binding-vq1hgnn0.js} +3 -3
- package/dist/chunks/monaco-buffer-3afgwvbp.js +4 -0
- package/dist/chunks/monaco-setup-xrd2cbkp.js +4 -0
- package/dist/chunks/notify-kzrjr3fv.js +4 -0
- package/dist/chunks/parse-v77xtwv7.js +4 -0
- package/dist/chunks/platform-7v4rtd7m.js +4 -0
- package/dist/chunks/popover-b89sfej7.js +4 -0
- package/dist/chunks/publish-panel-2z9gw8ee.js +4 -0
- package/dist/chunks/publish-quick-qx2455cj.js +4 -0
- package/dist/chunks/publish-workspace-wrc1dgwx.js +4 -0
- package/dist/chunks/quick-search-n0t0eqxb.js +4 -0
- package/dist/chunks/references-9547rg5s.js +4 -0
- package/dist/chunks/right-panel-wsgnr9pn.js +4 -0
- package/dist/chunks/source-control-kwktr9y6.js +4 -0
- package/dist/chunks/{split-n2gfpm5m.js → split-c9zfdgxf.js} +2 -2
- package/dist/chunks/studio-03ct6yfv.js +9 -0
- package/dist/chunks/studio-07rcfje3.js +5 -0
- package/dist/chunks/studio-3e54qh39.js +7 -0
- package/dist/chunks/studio-3exxhz5g.js +5 -0
- package/dist/chunks/studio-3q40e3rj.js +5 -0
- package/dist/chunks/studio-3qeh9t0h.js +6 -0
- package/dist/chunks/studio-3qqjeep5.js +6 -0
- package/dist/chunks/studio-43sd2mam.js +4 -0
- package/dist/chunks/studio-4hp8pkyt.js +5 -0
- package/dist/chunks/studio-58xg6j2q.js +9 -0
- package/dist/chunks/studio-5g0rprdt.js +7 -0
- package/dist/chunks/{studio-2j1cb95x.js → studio-6m380wp7.js} +4 -4
- package/dist/chunks/studio-80jyh1xh.js +4 -0
- package/dist/chunks/studio-83mk4bgg.js +9 -0
- package/dist/chunks/{studio-v0jzqdjm.js → studio-881z1xrx.js} +4 -4
- package/dist/chunks/studio-8m0y2qe7.js +5 -0
- package/dist/chunks/{studio-d81xfh1g.js → studio-8tr6cfrc.js} +4 -4
- package/dist/chunks/studio-8vcvfs7r.js +6 -0
- package/dist/chunks/studio-9tmebf0s.js +5 -0
- package/dist/chunks/studio-a2bvaptz.js +5 -0
- package/dist/chunks/studio-b7y5mr30.js +5 -0
- package/dist/chunks/studio-bavb31r0.js +5 -0
- package/dist/chunks/{studio-dgz8d0c1.js → studio-bbe4c90a.js} +4 -4
- package/dist/chunks/studio-c05wdnt3.js +5 -0
- package/dist/chunks/studio-ccv2svc6.js +5 -0
- package/dist/chunks/studio-d5grtb9e.js +16 -0
- package/dist/chunks/studio-df0baea9.js +5 -0
- package/dist/chunks/studio-dgk4dqtx.js +7 -0
- package/dist/chunks/studio-e1g64q43.js +5 -0
- package/dist/chunks/studio-ed1hp6zf.js +6 -0
- package/dist/chunks/studio-ed3xx40h.js +7 -0
- package/dist/chunks/studio-f14e1zdj.js +5 -0
- package/dist/chunks/studio-fbhxxc5f.js +5 -0
- package/dist/chunks/studio-fyh0jc96.js +5 -0
- package/dist/chunks/studio-gcxk20n7.js +5 -0
- package/dist/chunks/studio-jaaz8ce9.js +5 -0
- package/dist/chunks/{studio-90pq9km1.js → studio-jcnsdaep.js} +4 -4
- package/dist/chunks/studio-jsgf2q5k.js +7 -0
- package/dist/chunks/{studio-0q988f9w.js → studio-k3xxbagr.js} +3 -3
- package/dist/chunks/{studio-5ve6bbep.js → studio-k7evxqh4.js} +4 -4
- package/dist/chunks/studio-kt3pjkwd.js +5 -0
- package/dist/chunks/studio-m8g16bgz.js +5 -0
- package/dist/chunks/studio-mn0476ag.js +5 -0
- package/dist/chunks/studio-mx1smyq0.js +5 -0
- package/dist/chunks/studio-n0c5h6mf.js +5 -0
- package/dist/chunks/{studio-485046te.js → studio-nh6d342n.js} +7 -7
- package/dist/chunks/studio-nqxqf8p2.js +4 -0
- package/dist/chunks/studio-p4nrkvqr.js +5 -0
- package/dist/chunks/{studio-1fxkaaea.js → studio-pbxa5fpc.js} +4 -4
- package/dist/chunks/studio-pgmvdv7z.js +7 -0
- package/dist/chunks/studio-ph84avkf.js +5 -0
- package/dist/chunks/{studio-tq0rtfwj.js → studio-q0mvbaq6.js} +4 -4
- package/dist/chunks/studio-q0tccd43.js +5 -0
- package/dist/chunks/studio-q7rtx6zq.js +14 -0
- package/dist/chunks/{studio-a3g98wjr.js → studio-qgh13jtz.js} +4 -4
- package/dist/chunks/studio-qmn1xc24.js +5 -0
- package/dist/chunks/studio-qwdqwkj0.js +5 -0
- package/dist/chunks/studio-r5qy30vx.js +5 -0
- package/dist/chunks/studio-rj9eamf8.js +5 -0
- package/dist/chunks/studio-rptgsk96.js +5 -0
- package/dist/chunks/studio-rthyg42z.js +928 -0
- package/dist/chunks/studio-s19tp1xr.js +5 -0
- package/dist/chunks/studio-s32578pn.js +5 -0
- package/dist/chunks/studio-svb7yyve.js +5 -0
- package/dist/chunks/studio-syreb644.js +5 -0
- package/dist/chunks/studio-tf9jryb1.js +10 -0
- package/dist/chunks/studio-tfkznv39.js +5 -0
- package/dist/chunks/studio-tft6r105.js +5 -0
- package/dist/chunks/studio-txf2kysx.js +5 -0
- package/dist/chunks/studio-v8867ddv.js +12 -0
- package/dist/chunks/studio-vxq7fcvv.js +5 -0
- package/dist/chunks/studio-w4rz9hdk.js +5 -0
- package/dist/chunks/studio-wbcjbhy1.js +9 -0
- package/dist/chunks/studio-wc649wss.js +5 -0
- package/dist/chunks/studio-wys23mxz.js +5 -0
- package/dist/chunks/studio-x1x167jh.js +5 -0
- package/dist/chunks/studio-x9hsze61.js +5 -0
- package/dist/chunks/studio-y0n7yxea.js +9 -0
- package/dist/chunks/studio-y3ahhdpx.js +5 -0
- package/dist/chunks/studio-z97c48fk.js +5 -0
- package/dist/chunks/studio-zat62m0c.js +5 -0
- package/dist/chunks/studio-zcd2e7yz.js +5 -0
- package/dist/chunks/studio-zz9qe3rw.js +64 -0
- package/dist/chunks/toast-1gv0h53h.js +4 -0
- package/dist/chunks/{toast-host-ke5z4ng7.js → toast-host-1yg5ar8d.js} +3 -3
- package/dist/chunks/{tooltip-5v8ngwj2.js → tooltip-yypz28gq.js} +3 -3
- package/dist/chunks/{tree-mdq3v5cw.js → tree-9xa4hm7n.js} +2 -2
- package/dist/chunks/tsMode-epyfz1hv.js +14 -0
- package/dist/chunks/workspace-dz7nxfhv.js +4 -0
- package/dist/chunks/workspace-home-xsd7hkjw.js +4 -0
- package/dist/chunks/{ws-client-nze0k6mv.js → ws-client-bv552sfx.js} +3 -3
- package/dist/iframe-entry.js +20 -16
- package/dist/manifest.json +77 -63
- package/dist/studio.js +103 -104
- package/dist/workers/ts.worker.js +3 -3
- package/package.json +12 -11
- package/src/browse/component-examples.ts +272 -0
- package/src/browse/library-commands.ts +64 -104
- package/src/browse/library-layouts.ts +263 -49
- package/src/browse/library-model.ts +181 -133
- package/src/browse/library-pane.ts +738 -446
- package/src/browse/library-preview.ts +149 -19
- package/src/browse/library-source.ts +308 -41
- package/src/browse/preview-root.ts +78 -0
- package/src/browse/preview-style.ts +155 -0
- package/src/canvas/asset-refs.ts +16 -1
- package/src/canvas/canvas-live-render.ts +222 -30
- package/src/canvas/canvas-origin.ts +37 -12
- package/src/canvas/canvas-page-context.ts +112 -0
- package/src/canvas/canvas-render.ts +113 -107
- package/src/canvas/canvas-utils.ts +57 -12
- package/src/canvas/iframe-drop.ts +107 -0
- package/src/canvas/iframe-entry.ts +24 -12
- package/src/canvas/iframe-host.ts +134 -62
- package/src/canvas/iframe-keys.ts +11 -0
- package/src/canvas/iframe-patch.ts +8 -7
- package/src/canvas/iframe-protocol.ts +24 -5
- package/src/canvas/iframe-render.ts +48 -1
- package/src/canvas/iframe-subtree.ts +5 -2
- package/src/canvas/npm-modules.ts +22 -0
- package/src/canvas/preview-navigate.ts +16 -0
- package/src/canvas/repeater-sources.ts +200 -0
- package/src/canvas/stage-scrollbar.ts +5 -1
- package/src/canvas/surface-registry.ts +6 -0
- package/src/commands/app-commands.ts +16 -6
- package/src/commands/budget.ts +10 -8
- package/src/commands/context.ts +35 -10
- package/src/commands/defaults.ts +69 -45
- package/src/commands/keymap.ts +9 -0
- package/src/commands/levels.ts +11 -5
- package/src/commands/live-context.ts +2 -0
- package/src/commands/registry.ts +10 -1
- package/src/content/collection-match.ts +6 -5
- package/src/content/collection-pages.ts +412 -0
- package/src/content/content-collections.ts +270 -0
- package/src/content/entry-commands.ts +51 -60
- package/src/content/entry-editor.ts +111 -18
- package/src/content/entry-fields.ts +13 -1
- package/src/content/entry-inspector.ts +225 -0
- package/src/content/entry-model.ts +17 -3
- package/src/content/entry-open.ts +80 -0
- package/src/content/entry-summaries.ts +440 -0
- package/src/content/file-record-ids.ts +80 -0
- package/src/content/file-records.ts +125 -0
- package/src/content/page-summaries.ts +129 -0
- package/src/content/record-entry.ts +201 -0
- package/src/content/writing-banner.ts +177 -0
- package/src/create/add-new-commands.ts +185 -0
- package/src/create/add-new-flow.ts +1116 -0
- package/src/create/add-new.ts +1014 -0
- package/src/create/element-name.ts +121 -0
- package/src/editor/convert-to-component.ts +67 -43
- package/src/editor/file-drop-action.ts +9 -1
- package/src/editor/inline-edit-apply.ts +44 -0
- package/src/editor/inline-edit.ts +10 -0
- package/src/editor/insert-component.ts +91 -0
- package/src/editor/insert-zone-action.ts +13 -4
- package/src/editor/shortcuts.ts +44 -22
- package/src/editor/slash-menu.ts +51 -8
- package/src/files/components.ts +74 -10
- package/src/files/file-ops.ts +15 -5
- package/src/files/files.ts +164 -150
- package/src/files/fs-events.ts +18 -7
- package/src/files/media-meta.ts +95 -1
- package/src/files/media-types.ts +55 -0
- package/src/files/media-upload.ts +209 -52
- package/src/files/new-file-name.ts +156 -0
- package/src/files/serialize-document.ts +13 -3
- package/src/format/format-host.ts +15 -0
- package/src/github/github-auth.ts +2 -2
- package/src/github/github-publish.ts +4 -3
- package/src/grid/grid-controller.ts +5 -1
- package/src/grid/grid-open.ts +0 -27
- package/src/grid/grid-panel.ts +54 -2
- package/src/grid/grid-reveal.ts +34 -0
- package/src/grid/grid-source.ts +3 -25
- package/src/grid/grid-view.ts +31 -6
- package/src/grid/sources/content-source.ts +75 -7
- package/src/grid/tabulator-tables.d.ts +6 -0
- package/src/hosting/document.ts +2 -2
- package/src/i18n/i18n-commands.ts +2 -1
- package/src/media/media-commands.ts +181 -0
- package/src/media/media-library-model.ts +232 -0
- package/src/media/media-library.ts +1283 -0
- package/src/media/media-pane.ts +47 -19
- package/src/packages/pull-package-sync.ts +1 -1
- package/src/panels/activity-panel.ts +21 -5
- package/src/panels/ai-chat/chat-markdown.ts +8 -8
- package/src/panels/block-action-bar.ts +11 -11
- package/src/panels/canvas-dnd-bridge.ts +5 -2
- package/src/panels/chat-panel.ts +6 -6
- package/src/panels/collections-panel.ts +306 -0
- package/src/panels/component-preview.ts +35 -13
- package/src/panels/data-explorer.ts +1 -1
- package/src/panels/data-grid.ts +4 -0
- package/src/panels/dnd.ts +17 -30
- package/src/panels/elements-panel.ts +9 -2
- package/src/panels/empty-state.ts +2 -2
- package/src/panels/formula-workspace.ts +2 -3
- package/src/panels/frontmatter-fields.ts +9 -9
- package/src/panels/git-diff-open.ts +9 -5
- package/src/panels/head-panel.ts +369 -103
- package/src/panels/i18n-panel.ts +11 -10
- package/src/panels/imports-panel.ts +2 -0
- package/src/panels/jump-bar.ts +27 -2
- package/src/panels/layers-panel.ts +36 -30
- package/src/panels/left-panel.ts +22 -8
- package/src/panels/navigator-panels.ts +23 -11
- package/src/panels/pane-context.ts +111 -29
- package/src/panels/pane-grid.ts +6 -6
- package/src/panels/panel-registry.ts +14 -9
- package/src/panels/properties-panel.ts +7 -3
- package/src/panels/right-panel.ts +199 -43
- package/src/panels/seo-modal.ts +41 -108
- package/src/panels/settings-menu.ts +52 -50
- package/src/panels/settings-pane.ts +268 -162
- package/src/panels/signals-panel.ts +3 -4
- package/src/panels/site-model.ts +367 -0
- package/src/panels/site-panel.ts +638 -0
- package/src/panels/style-panel.ts +37 -3
- package/src/panels/stylebook-doc.ts +142 -10
- package/src/panels/stylebook-layers-panel.ts +39 -80
- package/src/panels/stylebook-panel.ts +47 -10
- package/src/panels/styles-panel.ts +327 -0
- package/src/panels/tab-strip.ts +109 -25
- package/src/platform.ts +1 -1
- package/src/platforms/cloud.ts +28 -1
- package/src/platforms/default-platform.ts +4 -4
- package/src/platforms/devserver.ts +51 -25
- package/src/publish/deploy-checklist.ts +12 -7
- package/src/publish/pages-service.ts +38 -14
- package/src/publish/publish-changes.ts +491 -0
- package/src/publish/publish-commands.ts +83 -18
- package/src/publish/publish-ids.ts +49 -0
- package/src/publish/publish-quick.ts +148 -0
- package/src/publish/publish-workspace.ts +926 -0
- package/src/publish/source-control.ts +907 -0
- package/src/services/automation.ts +16 -20
- package/src/services/cf-settings.ts +4 -4
- package/src/services/connection.ts +2 -2
- package/src/services/directory-picker.ts +2 -2
- package/src/services/references.ts +0 -0
- package/src/services/render-critic.ts +21 -2
- package/src/services/settings/definitions.ts +25 -14
- package/src/settings/contributed-section.ts +49 -10
- package/src/settings/css-vars-editor.ts +93 -27
- package/src/settings/developer-panels.ts +43 -0
- package/src/settings/extension-sections.ts +20 -2
- package/src/settings/general-settings.ts +91 -21
- package/src/settings/preferences-dialog.ts +8 -1
- package/src/settings/project-sections.ts +27 -10
- package/src/settings/schema-field-ui.ts +3 -1
- package/src/settings/section-registry.ts +116 -11
- package/src/settings/settings-dialog.ts +192 -0
- package/src/settings/settings-document.ts +182 -162
- package/src/shell.ts +467 -431
- package/src/site-context.ts +64 -10
- package/src/state.ts +28 -9
- package/src/studio.ts +194 -41
- package/src/style/project-styles.ts +34 -0
- package/src/style/stylebook-specimens.ts +89 -0
- package/src/style/stylebook-target.ts +26 -0
- package/src/style/tag-inheritance.ts +105 -0
- package/src/style/variables-focus.ts +61 -0
- package/src/style/variables-view.ts +235 -0
- package/src/surfaces/add-new.json +1482 -0
- package/src/surfaces/add-new.ts +325 -0
- package/src/surfaces/ai-chat.ts +2 -2
- package/src/surfaces/boot-failure.json +4 -3
- package/src/surfaces/bottom-dock.json +1 -1
- package/src/surfaces/canvas-stage.json +30 -19
- package/src/surfaces/canvas-stage.ts +5 -5
- package/src/surfaces/collections-panel.json +615 -0
- package/src/surfaces/collections-panel.ts +168 -0
- package/src/surfaces/commandbar.json +241 -96
- package/src/surfaces/commandbar.ts +134 -99
- package/src/surfaces/empty-state.json +1 -1
- package/src/surfaces/entry-editor.json +136 -0
- package/src/surfaces/entry-editor.ts +21 -0
- package/src/surfaces/entry-inspector.json +371 -0
- package/src/surfaces/entry-inspector.ts +143 -0
- package/src/surfaces/inspector-dock.json +162 -14
- package/src/surfaces/inspector-dock.ts +46 -19
- package/src/surfaces/library-pane.json +670 -437
- package/src/surfaces/library-pane.ts +94 -59
- package/src/surfaces/media-browser.json +62 -6
- package/src/surfaces/media-browser.ts +15 -1
- package/src/surfaces/media-field.json +1 -1
- package/src/surfaces/media-library.json +1586 -0
- package/src/surfaces/media-library.ts +282 -0
- package/src/surfaces/media-pick-dialog.json +71 -0
- package/src/surfaces/media-pick-dialog.ts +132 -0
- package/src/surfaces/menu.ts +18 -0
- package/src/surfaces/pane-context.json +144 -77
- package/src/surfaces/pane-context.ts +24 -0
- package/src/surfaces/panel-deploy-checklist.json +12 -6
- package/src/surfaces/panel-deploy-checklist.ts +3 -1
- package/src/surfaces/panel-page.json +72 -2
- package/src/surfaces/panel-page.ts +38 -7
- package/src/surfaces/panel-signals.json +1 -1
- package/src/surfaces/panel-signals.ts +5 -5
- package/src/surfaces/panel-stylebook-layers.json +71 -204
- package/src/surfaces/panel-stylebook-layers.ts +0 -21
- package/src/surfaces/preferences.json +120 -48
- package/src/surfaces/preferences.ts +8 -0
- package/src/surfaces/publish-quick.json +428 -0
- package/src/surfaces/publish-quick.ts +165 -0
- package/src/surfaces/publish-workspace.json +2892 -0
- package/src/surfaces/publish-workspace.ts +391 -0
- package/src/surfaces/rail.json +1 -159
- package/src/surfaces/rail.ts +18 -75
- package/src/surfaces/schema-form.json +10 -2
- package/src/surfaces/schema-form.ts +2 -0
- package/src/surfaces/seo.json +1 -1
- package/src/surfaces/settings-contributed.json +5 -5
- package/src/surfaces/settings-contributed.ts +18 -2
- package/src/surfaces/settings-css-vars.json +44 -36
- package/src/surfaces/settings-css-vars.ts +77 -4
- package/src/surfaces/settings-deploy.json +2 -15
- package/src/surfaces/settings-deploy.ts +1 -1
- package/src/surfaces/settings-dialog.json +51 -0
- package/src/surfaces/settings-dialog.ts +169 -0
- package/src/surfaces/settings-overview.json +3 -3
- package/src/surfaces/settings-overview.ts +9 -2
- package/src/surfaces/settings-pane.json +269 -46
- package/src/surfaces/settings-pane.ts +85 -24
- package/src/surfaces/shell.json +2 -1
- package/src/surfaces/site-panel.json +1029 -0
- package/src/surfaces/site-panel.ts +233 -0
- package/src/surfaces/slash-menu.json +63 -21
- package/src/surfaces/slash-menu.ts +23 -0
- package/src/surfaces/statusbar.ts +39 -15
- package/src/surfaces/styles-panel.json +735 -0
- package/src/surfaces/styles-panel.ts +195 -0
- package/src/surfaces/styles-variables.json +149 -0
- package/src/surfaces/styles-variables.ts +145 -0
- package/src/surfaces/tab-strip.json +4 -4
- package/src/surfaces/welcome.ts +1 -1
- package/src/surfaces/writing-banner.json +94 -0
- package/src/surfaces/writing-banner.ts +80 -0
- package/src/tabs/bare-repeaters.ts +101 -0
- package/src/tabs/tab.ts +47 -7
- package/src/types.ts +21 -26
- package/src/ui/form-controls.ts +47 -8
- package/src/ui/layers.ts +13 -0
- package/src/ui/media-picker.ts +284 -40
- package/src/ui/regions.ts +7 -6
- package/src/ui/schema-form.ts +259 -27
- package/src/ui/virtual-window.ts +26 -1
- package/src/utils/base64.ts +3 -3
- package/src/utils/edit-display.ts +322 -67
- package/src/utils/local-day.ts +18 -0
- package/src/workspace/pane-derive.ts +4 -4
- package/src/workspace/session.ts +28 -7
- package/src/workspace/tab-workspace.ts +137 -0
- package/src/workspace/workspace-back.ts +189 -0
- package/src/workspace/workspace-home.ts +133 -0
- package/src/workspace/workspace-ids.ts +129 -0
- package/src/workspace/workspace-switch.ts +372 -0
- package/src/workspace/workspace.ts +125 -11
- package/styles/shell-frame.css +30 -7
- package/styles/shell-frame.json +15 -3
- package/dist/chunks/2020-f2gkpy8d.js +0 -4
- package/dist/chunks/adapter-4912g339.js +0 -4
- package/dist/chunks/cf-account-picker-wccaenh6.js +0 -4
- package/dist/chunks/cf-settings-br6105tr.js +0 -4
- package/dist/chunks/color-28ksk2qm.js +0 -4
- package/dist/chunks/components-db68vsn7.js +0 -4
- package/dist/chunks/content-source-1449qesq.js +0 -4
- package/dist/chunks/convert-to-repeater-5h457egj.js +0 -4
- package/dist/chunks/editor-x9jn86a7.js +0 -4
- package/dist/chunks/entry-commands-may24cpt.js +0 -4
- package/dist/chunks/extension-sections-pvr14vxr.js +0 -4
- package/dist/chunks/file-ops-x9v54pcj.js +0 -4
- package/dist/chunks/files-j3knqf0s.js +0 -4
- package/dist/chunks/format-host-tyre2trb.js +0 -4
- package/dist/chunks/fs-events-64ma9htc.js +0 -4
- package/dist/chunks/git-panel-84ps5dex.js +0 -4
- package/dist/chunks/iframe-entry-fvbk89gm.js +0 -5
- package/dist/chunks/iframe-host-ck6vejt5.js +0 -4
- package/dist/chunks/index-b8xw3vy9.js +0 -4
- package/dist/chunks/jsonMode-w15cmrcm.js +0 -13
- package/dist/chunks/jx-validate-at3zn8wa.js +0 -4
- package/dist/chunks/layers-h4xp1pss.js +0 -4
- package/dist/chunks/layers-panel-m5hw1d7g.js +0 -4
- package/dist/chunks/lit-html-8t8t3dnr.js +0 -4
- package/dist/chunks/media-picker-2cweexc5.js +0 -4
- package/dist/chunks/menu-ynw13y0s.js +0 -4
- package/dist/chunks/monaco-buffer-qzxn567r.js +0 -4
- package/dist/chunks/monaco-setup-gxf6656g.js +0 -4
- package/dist/chunks/notify-cj5zbrs2.js +0 -4
- package/dist/chunks/parse-b7ddhr8m.js +0 -4
- package/dist/chunks/platform-3dfws9js.js +0 -4
- package/dist/chunks/popover-jt2gxmzs.js +0 -4
- package/dist/chunks/publish-panel-1gvxbj21.js +0 -4
- package/dist/chunks/quick-search-0dajrwqg.js +0 -4
- package/dist/chunks/references-49qgt404.js +0 -4
- package/dist/chunks/right-panel-jm1bwe53.js +0 -4
- package/dist/chunks/section-registry-6kwc4fky.js +0 -4
- package/dist/chunks/studio-0rt52vpq.js +0 -5
- package/dist/chunks/studio-18vgbhs5.js +0 -5
- package/dist/chunks/studio-24mccdrj.js +0 -5
- package/dist/chunks/studio-2eh507zk.js +0 -9
- package/dist/chunks/studio-2hcbccfv.js +0 -5
- package/dist/chunks/studio-2jbs3rxv.js +0 -5
- package/dist/chunks/studio-4h8k4dw9.js +0 -5
- package/dist/chunks/studio-5f6n18kx.js +0 -5
- package/dist/chunks/studio-5gthpky6.js +0 -5
- package/dist/chunks/studio-6ep3js6b.js +0 -9
- package/dist/chunks/studio-6wkmf3wz.js +0 -9
- package/dist/chunks/studio-841rf3cg.js +0 -5
- package/dist/chunks/studio-8gmwgheg.js +0 -5
- package/dist/chunks/studio-8qm0ep50.js +0 -5
- package/dist/chunks/studio-924p1tm1.js +0 -6
- package/dist/chunks/studio-a3shpz9y.js +0 -5
- package/dist/chunks/studio-amsbaaar.js +0 -6
- package/dist/chunks/studio-at5spjbc.js +0 -7
- package/dist/chunks/studio-b2xv945e.js +0 -5
- package/dist/chunks/studio-bn5nkafw.js +0 -5
- package/dist/chunks/studio-bw6q5xjf.js +0 -9
- package/dist/chunks/studio-c7q0t9x1.js +0 -5
- package/dist/chunks/studio-camnhc96.js +0 -6
- package/dist/chunks/studio-cffqvnzd.js +0 -5
- package/dist/chunks/studio-efvfrsf8.js +0 -5
- package/dist/chunks/studio-er30bpcx.js +0 -5
- package/dist/chunks/studio-ezscgr64.js +0 -5
- package/dist/chunks/studio-ffrrncvz.js +0 -5
- package/dist/chunks/studio-fpphgn8y.js +0 -10
- package/dist/chunks/studio-j1kvhdjk.js +0 -4
- package/dist/chunks/studio-j430n16g.js +0 -7
- package/dist/chunks/studio-jjkg84nj.js +0 -5
- package/dist/chunks/studio-m0q32ars.js +0 -4
- package/dist/chunks/studio-m6bdst11.js +0 -5
- package/dist/chunks/studio-nv2cptd4.js +0 -64
- package/dist/chunks/studio-nwfrc98n.js +0 -5
- package/dist/chunks/studio-p1wgvp7r.js +0 -5
- package/dist/chunks/studio-pag2wncm.js +0 -5
- package/dist/chunks/studio-qvanvzfd.js +0 -5
- package/dist/chunks/studio-qwa64kt7.js +0 -5
- package/dist/chunks/studio-rk1zc4x3.js +0 -928
- package/dist/chunks/studio-se2r3ptc.js +0 -5
- package/dist/chunks/studio-sg2a0dh0.js +0 -5
- package/dist/chunks/studio-tjzjhe68.js +0 -5
- package/dist/chunks/studio-v2w7q8r1.js +0 -7
- package/dist/chunks/studio-v5vjq1h0.js +0 -4
- package/dist/chunks/studio-v8aga3vp.js +0 -14
- package/dist/chunks/studio-vfcdrfmv.js +0 -5
- package/dist/chunks/studio-vmfkgdjf.js +0 -5
- package/dist/chunks/studio-wt1816jj.js +0 -5
- package/dist/chunks/studio-wz73q5kq.js +0 -4
- package/dist/chunks/studio-y04qtxvp.js +0 -7
- package/dist/chunks/studio-y21g8zzg.js +0 -5
- package/dist/chunks/studio-y64hrt8p.js +0 -12
- package/dist/chunks/studio-ynn90f58.js +0 -16
- package/dist/chunks/studio-yxz682sx.js +0 -5
- package/dist/chunks/studio-zp7snvkq.js +0 -5
- package/dist/chunks/studio-zq4z6tm6.js +0 -5
- package/dist/chunks/toast-c9fn075p.js +0 -4
- package/dist/chunks/tsMode-sf49ee9x.js +0 -14
- package/dist/chunks/workspace-jtfahpee.js +0 -4
- package/src/panels/frontmatter-panel.ts +0 -711
- package/src/panels/git-panel.ts +0 -1108
- package/src/surfaces/doc-header.json +0 -776
- package/src/surfaces/doc-header.ts +0 -222
- package/src/surfaces/git-panel.json +0 -1880
- package/src/surfaces/git-panel.ts +0 -264
|
@@ -46,6 +46,93 @@ const VOID_TAGS = new Set([
|
|
|
46
46
|
"wbr",
|
|
47
47
|
]);
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Phrasing content (HTML's content model) that is NOT also an embedded or interactive block an
|
|
51
|
+
* author drops as its own block: text-level elements. Only these may land inside a paragraph. An
|
|
52
|
+
* image, a video and a component are phrasing by the letter of HTML, but a card dragged from the
|
|
53
|
+
* Site panel onto a paragraph means "put it here", not "glue it into this sentence": in Markdown
|
|
54
|
+
* the latter serialises as an inline directive or image stuck to the text.
|
|
55
|
+
*/
|
|
56
|
+
const TEXT_LEVEL_TAGS = new Set([
|
|
57
|
+
"a",
|
|
58
|
+
"abbr",
|
|
59
|
+
"b",
|
|
60
|
+
"bdi",
|
|
61
|
+
"bdo",
|
|
62
|
+
"br",
|
|
63
|
+
"cite",
|
|
64
|
+
"code",
|
|
65
|
+
"data",
|
|
66
|
+
"del",
|
|
67
|
+
"dfn",
|
|
68
|
+
"em",
|
|
69
|
+
"i",
|
|
70
|
+
"ins",
|
|
71
|
+
"kbd",
|
|
72
|
+
"mark",
|
|
73
|
+
"q",
|
|
74
|
+
"s",
|
|
75
|
+
"samp",
|
|
76
|
+
"small",
|
|
77
|
+
"span",
|
|
78
|
+
"strong",
|
|
79
|
+
"sub",
|
|
80
|
+
"sup",
|
|
81
|
+
"time",
|
|
82
|
+
"u",
|
|
83
|
+
"var",
|
|
84
|
+
"wbr",
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
/** Elements whose content model is phrasing only: a block dropped inside one breaks it. */
|
|
88
|
+
const PHRASING_HOSTS = new Set([
|
|
89
|
+
...TEXT_LEVEL_TAGS,
|
|
90
|
+
"button",
|
|
91
|
+
"dt",
|
|
92
|
+
"h1",
|
|
93
|
+
"h2",
|
|
94
|
+
"h3",
|
|
95
|
+
"h4",
|
|
96
|
+
"h5",
|
|
97
|
+
"h6",
|
|
98
|
+
"label",
|
|
99
|
+
"legend",
|
|
100
|
+
"p",
|
|
101
|
+
"pre",
|
|
102
|
+
"summary",
|
|
103
|
+
]);
|
|
104
|
+
|
|
105
|
+
/** A node's tag, lower-cased, `div` when it names none. */
|
|
106
|
+
function tagOf(node: JxMutableNode | null | undefined): string {
|
|
107
|
+
return (displayTagName(node?.tagName) || "div").toLowerCase();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Whether the dragged thing is text-level content, which may be placed inside a paragraph. */
|
|
111
|
+
function isTextLevelSource(src: DragSrcKind, shadowDoc: JxMutableNode): boolean {
|
|
112
|
+
const tag = src.type === "block" ? (src.tag ?? "") : tagOf(getNodeAtPath(shadowDoc, src.path));
|
|
113
|
+
return TEXT_LEVEL_TAGS.has(tag.toLowerCase());
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The outermost phrasing host at or above `el` (the paragraph around a `<strong>`), or null when
|
|
118
|
+
* `el` is in none. A block is placed beside that host, never inside it.
|
|
119
|
+
*/
|
|
120
|
+
function phrasingHostOf(el: HTMLElement, shadowDoc: JxMutableNode): HTMLElement | null {
|
|
121
|
+
let host: HTMLElement | null = null;
|
|
122
|
+
let current: HTMLElement | null = el;
|
|
123
|
+
while (current) {
|
|
124
|
+
const path = parseJxPath(current.dataset.jxPath ?? "");
|
|
125
|
+
if (path.length === 0) {
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
if (PHRASING_HOSTS.has(tagOf(getNodeAtPath(shadowDoc, path)))) {
|
|
129
|
+
host = current;
|
|
130
|
+
}
|
|
131
|
+
current = nearestPathEl(current.parentElement);
|
|
132
|
+
}
|
|
133
|
+
return host;
|
|
134
|
+
}
|
|
135
|
+
|
|
49
136
|
/**
|
|
50
137
|
* Walk up from an element to the nearest ancestor carrying a `data-jx-path`. Refactored out of the
|
|
51
138
|
* `nearestHit` walk (iframe-interaction.ts) to take an element directly so the hit-test adapter can
|
|
@@ -122,6 +209,26 @@ export function computeDropInstruction(
|
|
|
122
209
|
return null;
|
|
123
210
|
}
|
|
124
211
|
|
|
212
|
+
/* A block over a paragraph (or anything inside one) lands above or below the paragraph: a
|
|
213
|
+
component or an image nested in a `<p>` is serialised glued to its text. */
|
|
214
|
+
const host = isTextLevelSource(src, shadowDoc) ? null : phrasingHostOf(targetEl, shadowDoc);
|
|
215
|
+
if (host) {
|
|
216
|
+
const hostPath = parseJxPath(host.dataset.jxPath ?? "");
|
|
217
|
+
if (!canDrop(src, hostPath)) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
const hostRect = rectFor(host);
|
|
221
|
+
const hostRelY = hostRect.height === 0 ? 0 : (cursorY - hostRect.y) / hostRect.height;
|
|
222
|
+
return hostRelY < 0.5
|
|
223
|
+
? { edge: "top", instruction: "reorder-above", referenceRect: hostRect, targetPath: hostPath }
|
|
224
|
+
: {
|
|
225
|
+
edge: "bottom",
|
|
226
|
+
instruction: "reorder-below",
|
|
227
|
+
referenceRect: hostRect,
|
|
228
|
+
targetPath: hostPath,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
125
232
|
const node = getNodeAtPath(shadowDoc, targetPath);
|
|
126
233
|
const tag = (displayTagName(node?.tagName) || "div").toLowerCase();
|
|
127
234
|
const hasElementChildren =
|
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
applyCanvasDialogOpen,
|
|
13
13
|
applyCanvasPopoverOpen,
|
|
14
14
|
applyPreviewColorScheme,
|
|
15
|
+
applyPreviewLocale,
|
|
16
|
+
captureLocaleBaseline,
|
|
15
17
|
applySiteStyle,
|
|
16
18
|
installCanvasImageRetry,
|
|
17
19
|
renderResolvedDocument,
|
|
@@ -54,9 +56,11 @@ import {
|
|
|
54
56
|
redefineElement,
|
|
55
57
|
resetDocumentStyles,
|
|
56
58
|
setCanvasAssetResolver,
|
|
59
|
+
setNpmModuleResolver,
|
|
57
60
|
setResolveToken,
|
|
58
61
|
} from "@jxsuite/runtime";
|
|
59
62
|
import { resolveAssetRef } from "./asset-resolve";
|
|
63
|
+
import { npmModuleUrl } from "./npm-modules";
|
|
60
64
|
import type { AssetContext } from "./asset-resolve";
|
|
61
65
|
import { KIT_LOADERS } from "@jxsuite/ui/loaders";
|
|
62
66
|
import type { CanvasEnvelope, IframeChannel } from "./iframe-channel";
|
|
@@ -92,6 +96,14 @@ for (const [specifier, load] of Object.entries(KIT_LOADERS)) {
|
|
|
92
96
|
preloadModule(specifier, load);
|
|
93
97
|
}
|
|
94
98
|
|
|
99
|
+
/*
|
|
100
|
+
* A document's `npm:` sidecar, from the package the project installed. The build bundles one
|
|
101
|
+
* (`compiler/src/site/bundler.ts`); this frame asks the dev server, which bundles
|
|
102
|
+
* `/node_modules/<package>/<subpath>` on demand through the package's own `exports`, the URL space
|
|
103
|
+
* `registerElements` already imports a bare `$elements` specifier from.
|
|
104
|
+
*/
|
|
105
|
+
setNpmModuleResolver((specifier) => npmModuleUrl(specifier, location.href));
|
|
106
|
+
|
|
95
107
|
/**
|
|
96
108
|
* Resolve the drop placement for a forwarded cursor: point hit-test → nearest `[data-jx-path]` →
|
|
97
109
|
* pure {@link computeDropInstruction}. Returns null when the cursor resolves to no droppable target.
|
|
@@ -300,6 +312,8 @@ export function startCanvasIframe(opts: {
|
|
|
300
312
|
// Alongside the handle so a superseded render's refs can't keep posting.
|
|
301
313
|
let stopDataScopeWatch: (() => void) | null = null;
|
|
302
314
|
let latestGen = -1;
|
|
315
|
+
// The root's language as the frame booted it, which a render with no language goes back to.
|
|
316
|
+
const localeBaseline = captureLocaleBaseline(container.ownerDocument);
|
|
303
317
|
// The raw page doc the current DOM was rendered from — the patch source-of-truth. `renderedGen`
|
|
304
318
|
// Tracks which generation it (and the DOM) reflect, so patches for an in-flight/superseded render
|
|
305
319
|
// Are handled correctly rather than applied against the wrong tree.
|
|
@@ -963,17 +977,12 @@ export function startCanvasIframe(opts: {
|
|
|
963
977
|
/* The other document-level attribute flip, and the whole visible half of an axis-3 locale:
|
|
964
978
|
`dir` is what makes an RTL preview actually mirror, and `lang` is what CSS's `:lang()` and
|
|
965
979
|
the font stack select on. Patch-free like the scheme above — the TEXT is whatever file is
|
|
966
|
-
open, because a translation in Jx is a different file rather than a different rendering.
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
root.removeAttribute("dir");
|
|
973
|
-
} else {
|
|
974
|
-
root.setAttribute("lang", msg.locale);
|
|
975
|
-
root.setAttribute("dir", msg.dir);
|
|
976
|
-
}
|
|
980
|
+
open, because a translation in Jx is a different file rather than a different rendering. */
|
|
981
|
+
applyPreviewLocale(
|
|
982
|
+
container.ownerDocument,
|
|
983
|
+
msg.locale === null ? null : { dir: msg.dir, locale: msg.locale },
|
|
984
|
+
localeBaseline,
|
|
985
|
+
);
|
|
977
986
|
return;
|
|
978
987
|
}
|
|
979
988
|
if (msg.kind === "siteStyleUpdate") {
|
|
@@ -985,6 +994,7 @@ export function startCanvasIframe(opts: {
|
|
|
985
994
|
return;
|
|
986
995
|
}
|
|
987
996
|
applyPreviewColorScheme(container.ownerDocument, msg.colorScheme ?? null);
|
|
997
|
+
applyPreviewLocale(container.ownerDocument, msg.locale ?? null, localeBaseline);
|
|
988
998
|
// A render replaces the DOM under a live edit session — COMMIT it first (never discard). The
|
|
989
999
|
// Resulting editCommit/editEnd post synchronously here, so on the FIFO channel they precede
|
|
990
1000
|
// This render's renderComplete and the parent routes them by the host's not-yet-flipped tab
|
|
@@ -1080,6 +1090,8 @@ export function startCanvasIframe(opts: {
|
|
|
1080
1090
|
channel.post({ kind: "ready" });
|
|
1081
1091
|
return () => {
|
|
1082
1092
|
off();
|
|
1093
|
+
// Leave the root as it booted, so a frame started after this one captures the same baseline.
|
|
1094
|
+
applyPreviewLocale(container.ownerDocument, null, localeBaseline);
|
|
1083
1095
|
stopInteraction();
|
|
1084
1096
|
stopKeyForwarding();
|
|
1085
1097
|
stopInlineEdit();
|
|
@@ -1127,7 +1139,7 @@ export function bootCanvasIframe(win: BootWindow): () => void {
|
|
|
1127
1139
|
setResolveToken(params.get("rpcToken"));
|
|
1128
1140
|
// ParentOrigin authenticates the parent peer. The host (iframe-host.ts) passes it ONLY for an
|
|
1129
1141
|
// Http(s) parent (dev / chromium — same-origin, the origin round-trips). It OMITS it for a
|
|
1130
|
-
// Non-http(s) parent (
|
|
1142
|
+
// Non-http(s) parent (a custom scheme), whose custom scheme may not surface as a postMessage
|
|
1131
1143
|
// Origin: a missing value here means fall back to "*" — token-gated, NOT a silent omission — and
|
|
1132
1144
|
// Log it loudly so the looser origin check is visible.
|
|
1133
1145
|
const explicitParentOrigin = params.get("parentOrigin");
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
import { canvasRectToParent, createOverlayLayer } from "./iframe-overlay";
|
|
24
24
|
import { serializeJxPath } from "./path-mapping";
|
|
25
25
|
import { getActivePanel, panelMediaToActiveMedia } from "./canvas-helpers";
|
|
26
|
-
import { panToParentRect } from "./canvas-utils";
|
|
26
|
+
import { panToParentRect, revealParentRect } from "./canvas-utils";
|
|
27
27
|
import { clearDragGhost, moveDragGhost } from "../panels/drag-ghost";
|
|
28
28
|
import { applyDropInstruction } from "../panels/dnd";
|
|
29
29
|
import { rectOf } from "../utils/geometry";
|
|
@@ -67,7 +67,9 @@ import type {
|
|
|
67
67
|
SerializableRect,
|
|
68
68
|
SerializedKey,
|
|
69
69
|
SyncedChord,
|
|
70
|
+
WireLocale,
|
|
70
71
|
} from "./iframe-protocol";
|
|
72
|
+
import { getEffectiveRenderLocale } from "../site-context";
|
|
71
73
|
import type { JxDocOp } from "../tabs/patch-ops";
|
|
72
74
|
import type { IframeChannel } from "./iframe-channel";
|
|
73
75
|
import type { OverlayLayer, OverlayPlacement } from "./iframe-overlay";
|
|
@@ -136,9 +138,8 @@ export interface HostState {
|
|
|
136
138
|
canvasEl: HTMLElement;
|
|
137
139
|
channel: IframeChannel<ParentToIframe, IframeToParent>;
|
|
138
140
|
/**
|
|
139
|
-
* The resolved canvasUrl this iframe was built with — so a host built
|
|
140
|
-
*
|
|
141
|
-
* async).
|
|
141
|
+
* The resolved canvasUrl this iframe was built with — so a host built with one URL is rebuilt if
|
|
142
|
+
* the platform later reports a different one.
|
|
142
143
|
*/
|
|
143
144
|
canvasUrl: string;
|
|
144
145
|
ready: boolean;
|
|
@@ -154,7 +155,21 @@ export interface HostState {
|
|
|
154
155
|
selectionPath: (string | number)[] | null;
|
|
155
156
|
/** The whole selection this host last measured, so a re-measure redraws every box. */
|
|
156
157
|
selectionPaths: readonly JxPath[];
|
|
157
|
-
/**
|
|
158
|
+
/**
|
|
159
|
+
* The allocator every `measure` request this host posts draws its id from: selection, presence,
|
|
160
|
+
* pan-to-card and {@link measureCanvasPath}. One counter keeps the ids disjoint, so the `geometry`
|
|
161
|
+
* handler can dispatch on the id alone.
|
|
162
|
+
*/
|
|
163
|
+
measureSeq: number;
|
|
164
|
+
/**
|
|
165
|
+
* Id of the most recent SELECTION `measure` request, so a stale selection reply is dropped.
|
|
166
|
+
*
|
|
167
|
+
* It names the request, not the counter. It used to be both, so any other measure posted while a
|
|
168
|
+
* selection measure was in flight superseded it: picking a tag in the Styles Outline posts the
|
|
169
|
+
* selection measure and then a pan-to-card measure in the same tick, the pan took the newer id,
|
|
170
|
+
* and the selection reply arrived to find itself stale. The specimen was centred and never
|
|
171
|
+
* outlined. A live peer's presence measure did the same to the page selection.
|
|
172
|
+
*/
|
|
158
173
|
selReqId: number;
|
|
159
174
|
/**
|
|
160
175
|
* The NON-primary selected paths the in-flight selection `measure` covers, serialized. The
|
|
@@ -162,7 +177,7 @@ export interface HostState {
|
|
|
162
177
|
* selected node leaves it empty, so nothing but the selection box is ever drawn.
|
|
163
178
|
*/
|
|
164
179
|
coSelectionKeys: Set<string>;
|
|
165
|
-
/** Id of the most recent presence `measure` request (allocated from
|
|
180
|
+
/** Id of the most recent presence `measure` request (allocated from {@link HostState.measureSeq}). */
|
|
166
181
|
presenceReqId: number;
|
|
167
182
|
/** Serialized peer path → presence box meta for the in-flight presence measure. */
|
|
168
183
|
presenceMeta: Map<string, { color: string; label: string }>;
|
|
@@ -270,8 +285,8 @@ export interface HostState {
|
|
|
270
285
|
/**
|
|
271
286
|
* Resolvers for {@link measureCanvasPath} requests, keyed by the `measure` reqId.
|
|
272
287
|
*
|
|
273
|
-
* Allocated from the same `
|
|
274
|
-
* can never collide and the `geometry` handler can dispatch on the id alone.
|
|
288
|
+
* Allocated from the same `measureSeq` counter as the selection and presence measures, so the
|
|
289
|
+
* three can never collide and the `geometry` handler can dispatch on the id alone.
|
|
275
290
|
*/
|
|
276
291
|
pendingMeasures: Map<number, (hits: NodeHit[]) => void>;
|
|
277
292
|
/**
|
|
@@ -772,8 +787,8 @@ function measureIn(
|
|
|
772
787
|
path: readonly (string | number)[],
|
|
773
788
|
): Promise<CanvasPoint | null> {
|
|
774
789
|
return new Promise((resolve) => {
|
|
775
|
-
host.
|
|
776
|
-
const reqId = host.
|
|
790
|
+
host.measureSeq += 1;
|
|
791
|
+
const reqId = host.measureSeq;
|
|
777
792
|
const timer = setTimeout(() => {
|
|
778
793
|
host.pendingMeasures.delete(reqId);
|
|
779
794
|
resolve(null);
|
|
@@ -1716,8 +1731,8 @@ function requestPresence(host: HostState): void {
|
|
|
1716
1731
|
host.overlay.setPresence([]);
|
|
1717
1732
|
return;
|
|
1718
1733
|
}
|
|
1719
|
-
host.
|
|
1720
|
-
host.presenceReqId = host.
|
|
1734
|
+
host.measureSeq += 1;
|
|
1735
|
+
host.presenceReqId = host.measureSeq;
|
|
1721
1736
|
host.channel.post({ kind: "measure", paths, reqId: host.presenceReqId });
|
|
1722
1737
|
}
|
|
1723
1738
|
|
|
@@ -1741,6 +1756,8 @@ function requestSelection(host: HostState, sel: readonly JxPath[]): void {
|
|
|
1741
1756
|
return;
|
|
1742
1757
|
}
|
|
1743
1758
|
if (!primary) {
|
|
1759
|
+
// Nothing selected, so a reply still in flight answers a question nobody is asking any more.
|
|
1760
|
+
host.selReqId = -1;
|
|
1744
1761
|
host.coSelectionKeys.clear();
|
|
1745
1762
|
host.overlay.setSelection(null);
|
|
1746
1763
|
host.overlay.setCoSelection([]);
|
|
@@ -1753,7 +1770,8 @@ function requestSelection(host: HostState, sel: readonly JxPath[]): void {
|
|
|
1753
1770
|
// Cross the postMessage boundary.
|
|
1754
1771
|
const others = cloneSelection(sel.slice(0, -1));
|
|
1755
1772
|
host.coSelectionKeys = new Set(others.map((path) => JSON.stringify(path)));
|
|
1756
|
-
host.
|
|
1773
|
+
host.measureSeq += 1;
|
|
1774
|
+
host.selReqId = host.measureSeq;
|
|
1757
1775
|
host.channel.post({
|
|
1758
1776
|
kind: "measure",
|
|
1759
1777
|
paths: [[...primary], ...others],
|
|
@@ -1774,13 +1792,15 @@ function requestStylebookSelection(host: HostState): void {
|
|
|
1774
1792
|
const tag = shell.stylebook.selection;
|
|
1775
1793
|
const cardPath = tag ? host.stylebook?.tagToCardPath.get(tag) : undefined;
|
|
1776
1794
|
if (!tag || !cardPath) {
|
|
1795
|
+
host.selReqId = -1;
|
|
1777
1796
|
host.overlay.setSelection(null);
|
|
1778
1797
|
return;
|
|
1779
1798
|
}
|
|
1780
1799
|
if (!host.ready) {
|
|
1781
1800
|
return;
|
|
1782
1801
|
}
|
|
1783
|
-
host.
|
|
1802
|
+
host.measureSeq += 1;
|
|
1803
|
+
host.selReqId = host.measureSeq;
|
|
1784
1804
|
host.channel.post({ kind: "measure", paths: [[...cardPath]], reqId: host.selReqId });
|
|
1785
1805
|
}
|
|
1786
1806
|
|
|
@@ -1789,9 +1809,9 @@ function requestStylebookSelection(host: HostState): void {
|
|
|
1789
1809
|
*
|
|
1790
1810
|
* This was the literal `/packages/studio/canvas.html` — a repo dev-server path baked into a browser
|
|
1791
1811
|
* bundle, correct on exactly one host out of four. It happened to work because every other host
|
|
1792
|
-
* overrides `canvasUrl`: the chromium launcher builds one from its token
|
|
1793
|
-
*
|
|
1794
|
-
*
|
|
1812
|
+
* overrides `canvasUrl`: the chromium launcher builds one from its token and the cloud adapter
|
|
1813
|
+
* hard-codes its own. So the default was never the default; it was the dev server's URL with
|
|
1814
|
+
* nothing saying so.
|
|
1795
1815
|
*
|
|
1796
1816
|
* `bundleUrl` resolves it against the ENTRY's directory, which is the one fact every host agrees on
|
|
1797
1817
|
* (see services/bundle-base.ts), so the fallback is now correct everywhere rather than accidentally
|
|
@@ -1801,12 +1821,6 @@ function defaultCanvasUrl(): string {
|
|
|
1801
1821
|
return bundleUrl("../canvas.html");
|
|
1802
1822
|
}
|
|
1803
1823
|
|
|
1804
|
-
/**
|
|
1805
|
-
* Loads nothing, deliberately: what a platform that resolves its canvasUrl LATER gets in the
|
|
1806
|
-
* meantime. See {@link StudioPlatform.canvasUrlDeferred}.
|
|
1807
|
-
*/
|
|
1808
|
-
const DEFERRED_CANVAS_URL = "about:blank";
|
|
1809
|
-
|
|
1810
1824
|
/**
|
|
1811
1825
|
* Release one host: its channel, its overlay, its frame, and everything awaiting a reply from it.
|
|
1812
1826
|
*
|
|
@@ -1852,27 +1866,12 @@ function releaseHost(host: HostState): void {
|
|
|
1852
1866
|
liveHosts.delete(host);
|
|
1853
1867
|
}
|
|
1854
1868
|
|
|
1855
|
-
/**
|
|
1856
|
-
* Which document this pane's canvas iframe should load.
|
|
1857
|
-
*
|
|
1858
|
-
* The `canvasUrlDeferred` branch is the one that needs saying. Electrobun resolves its canvasUrl
|
|
1859
|
-
* asynchronously — it is this window's loopback port, fetched over RPC inside `activate()` — and
|
|
1860
|
-
* until the fix above, the bundle-relative default resolved to nothing servable under `views://`,
|
|
1861
|
-
* so an early frame simply failed and `ensureHost` rebuilt against the real URL when it landed. Now
|
|
1862
|
-
* that default RESOLVES: `views://studio/canvas.html` is a document electrobun really does stage.
|
|
1863
|
-
* An early frame would therefore boot the whole canvas bundle inside the SHELL's app-privileged
|
|
1864
|
-
* origin, in a CEF instance running `disable-site-isolation-trials` — and the cross-origin loopback
|
|
1865
|
-
* canvas exists precisely so that never happens.
|
|
1866
|
-
*/
|
|
1869
|
+
/** Which document this pane's canvas iframe should load. */
|
|
1867
1870
|
function resolveCanvasUrl(): string {
|
|
1868
1871
|
if (!hasPlatform()) {
|
|
1869
1872
|
return defaultCanvasUrl();
|
|
1870
1873
|
}
|
|
1871
|
-
|
|
1872
|
-
if (platform.canvasUrl) {
|
|
1873
|
-
return platform.canvasUrl;
|
|
1874
|
-
}
|
|
1875
|
-
return platform.canvasUrlDeferred ? DEFERRED_CANVAS_URL : defaultCanvasUrl();
|
|
1874
|
+
return getPlatform().canvasUrl || defaultCanvasUrl();
|
|
1876
1875
|
}
|
|
1877
1876
|
|
|
1878
1877
|
/**
|
|
@@ -1912,9 +1911,8 @@ function ensureHost(canvasEl: HTMLElement): HostState {
|
|
|
1912
1911
|
if (existing.canvasUrl === canvasUrl) {
|
|
1913
1912
|
return existing;
|
|
1914
1913
|
}
|
|
1915
|
-
// The platform
|
|
1916
|
-
//
|
|
1917
|
-
// Right cross-origin origin.
|
|
1914
|
+
// The platform now reports a different canvasUrl than this host was built with — tear the
|
|
1915
|
+
// Iframe down and rebuild against the right origin.
|
|
1918
1916
|
releaseHost(existing);
|
|
1919
1917
|
}
|
|
1920
1918
|
// ParentOrigin is the parent's real origin, passed into the iframe URL so the cross-origin iframe
|
|
@@ -1922,8 +1920,8 @@ function ensureHost(canvasEl: HTMLElement): HostState {
|
|
|
1922
1920
|
const parentOrigin = location.origin;
|
|
1923
1921
|
const token = crypto.randomUUID();
|
|
1924
1922
|
// IframeOrigin is the iframe's own origin. For a RELATIVE canvasUrl (dev / chromium) it resolves to
|
|
1925
|
-
// The parent's location.origin (same-origin). For an absolute
|
|
1926
|
-
//
|
|
1923
|
+
// The parent's location.origin (same-origin). For an absolute canvasUrl it is
|
|
1924
|
+
// That URL's origin, so the channel accepts/targets the right cross-origin peer.
|
|
1927
1925
|
const iframeOrigin = new URL(canvasUrl, location.href).origin;
|
|
1928
1926
|
const iframe = document.createElement("iframe");
|
|
1929
1927
|
iframe.className = "jx-canvas-iframe";
|
|
@@ -1932,16 +1930,16 @@ function ensureHost(canvasEl: HTMLElement): HostState {
|
|
|
1932
1930
|
iframe.title = "Canvas — live page render";
|
|
1933
1931
|
iframe.style.cssText =
|
|
1934
1932
|
"width:100%;min-height:480px;height:100%;border:0;display:block;background:#fff";
|
|
1935
|
-
// Preserve any query already on canvasUrl (e.g.
|
|
1933
|
+
// Preserve any query already on canvasUrl (e.g. a per-window `?win=7`) and append the token (always)
|
|
1936
1934
|
// Plus parentOrigin (conditionally — see below).
|
|
1937
1935
|
const srcUrl = new URL(canvasUrl, location.href);
|
|
1938
1936
|
srcUrl.searchParams.set("token", token);
|
|
1939
1937
|
// Pass parentOrigin into the iframe src ONLY when the PARENT is served over http(s) (dev / chromium
|
|
1940
1938
|
// — same-origin, so the origin round-trips and the iframe can keep its acceptOrigin STRICT). For a
|
|
1941
|
-
// Non-http(s) parent (
|
|
1939
|
+
// Non-http(s) parent (a custom scheme) OMIT it: a custom scheme may not surface as a postMessage
|
|
1942
1940
|
// Origin (event.origin), so the iframe falls back to acceptOrigin '*' + the shared token (it logs
|
|
1943
1941
|
// The warn) rather than silently stalling. The PARENT side here stays STRICT — acceptOrigin /
|
|
1944
|
-
// TargetOrigin are the real
|
|
1942
|
+
// TargetOrigin are the real iframeOrigin below, a gateable origin.
|
|
1945
1943
|
if (location.protocol === "http:" || location.protocol === "https:") {
|
|
1946
1944
|
srcUrl.searchParams.set("parentOrigin", parentOrigin);
|
|
1947
1945
|
}
|
|
@@ -1987,6 +1985,7 @@ function ensureHost(canvasEl: HTMLElement): HostState {
|
|
|
1987
1985
|
lastHover: null,
|
|
1988
1986
|
lastSelectionRect: null,
|
|
1989
1987
|
lastSnapshotSeq: 0,
|
|
1988
|
+
measureSeq: 0,
|
|
1990
1989
|
overlay,
|
|
1991
1990
|
panReqId: -1,
|
|
1992
1991
|
pending: null,
|
|
@@ -2002,7 +2001,7 @@ function ensureHost(canvasEl: HTMLElement): HostState {
|
|
|
2002
2001
|
ready: false,
|
|
2003
2002
|
selectionPath: null,
|
|
2004
2003
|
selectionPaths: [],
|
|
2005
|
-
selReqId:
|
|
2004
|
+
selReqId: -1,
|
|
2006
2005
|
snapshot: null,
|
|
2007
2006
|
stylebook: null,
|
|
2008
2007
|
tabId: null,
|
|
@@ -2397,7 +2396,7 @@ function handleMessage(state: HostState, msg: IframeToParent): void {
|
|
|
2397
2396
|
const [hit] = msg.hits;
|
|
2398
2397
|
if (hit) {
|
|
2399
2398
|
const { rect: ifr, scale } = hostDragGeometry(state);
|
|
2400
|
-
|
|
2399
|
+
revealParentRect({ height: hit.rect.height * scale, top: hit.rect.y * scale + ifr.top });
|
|
2401
2400
|
}
|
|
2402
2401
|
return;
|
|
2403
2402
|
}
|
|
@@ -2884,6 +2883,7 @@ function onDomUpdated(state: HostState, gen: number): void {
|
|
|
2884
2883
|
requestSelection(state, state.selectionPaths);
|
|
2885
2884
|
requestPresence(state);
|
|
2886
2885
|
hideInsertZoneNow(state);
|
|
2886
|
+
servePendingStylebookPan(state);
|
|
2887
2887
|
if (state.pendingEnterEdit && gen >= state.pendingEnterEdit.minGen) {
|
|
2888
2888
|
const { offset, path, prop } = state.pendingEnterEdit;
|
|
2889
2889
|
state.pendingEnterEdit = null;
|
|
@@ -3008,7 +3008,7 @@ function drawHover(state: HostState, hit: NodeHit | null): void {
|
|
|
3008
3008
|
*/
|
|
3009
3009
|
type PreparedRender = Omit<
|
|
3010
3010
|
Extract<ParentToIframe, { kind: "render" }>,
|
|
3011
|
-
"colorScheme" | "gen" | "kind"
|
|
3011
|
+
"colorScheme" | "gen" | "kind" | "locale"
|
|
3012
3012
|
>;
|
|
3013
3013
|
|
|
3014
3014
|
/** One render pass's prepared payloads, by document IDENTITY. */
|
|
@@ -3237,6 +3237,8 @@ export async function mountIframeCanvas(
|
|
|
3237
3237
|
colorScheme: schemeWireFor(viewTab),
|
|
3238
3238
|
gen,
|
|
3239
3239
|
kind: "render",
|
|
3240
|
+
// The language this artboard draws in, per tab and at post time like the scheme.
|
|
3241
|
+
locale: localeWireFor(viewTab),
|
|
3240
3242
|
// Read at POST time for the same reason `colorScheme` is: a render replaces the DOM, so a panel
|
|
3241
3243
|
// The author opened before this pass would close under them without it.
|
|
3242
3244
|
popoverOpen: viewTab?.session.ui.openPopover ?? null,
|
|
@@ -3267,14 +3269,27 @@ export async function mountIframeCanvas(
|
|
|
3267
3269
|
* until it says `ready`. Counted either way: the message is this pass's work for this host whether
|
|
3268
3270
|
* or not the frame has finished loading.
|
|
3269
3271
|
*/
|
|
3270
|
-
function deliverRender(state: HostState, message:
|
|
3272
|
+
function deliverRender(state: HostState, message: RenderMsg): void {
|
|
3271
3273
|
canvasPerf.hostRenderPosts += 1;
|
|
3272
3274
|
if (state.ready) {
|
|
3273
3275
|
syncAssetVersions(state);
|
|
3274
3276
|
state.channel.post(message);
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
+
return;
|
|
3278
|
+
}
|
|
3279
|
+
/* The queue holds ONE render, and it must be the NEWEST, not the last to arrive. A page render
|
|
3280
|
+
awaits its own resolution, so two renders started in order can finish out of order: on a
|
|
3281
|
+
reload that restores two tabs, the frame is still booting, the first-opened tab's render (an
|
|
3282
|
+
older gen) can resolve after the active tab's, and overwriting the slot posted the stale one
|
|
3283
|
+
on `ready`. The frame drew the other tab's document, the ack adopted that tab's identity, and
|
|
3284
|
+
the active tab's render was lost. A ready frame drops a stale gen itself (`latestGen`); the
|
|
3285
|
+
queue has to make the same call. */
|
|
3286
|
+
const queued = state.pending;
|
|
3287
|
+
if (queued?.kind === "render" && queued.gen > message.gen) {
|
|
3288
|
+
// Never posted, so never acked: its identity must not wait for an ack that cannot come.
|
|
3289
|
+
state.pendingTabIds.delete(message.gen);
|
|
3290
|
+
return;
|
|
3277
3291
|
}
|
|
3292
|
+
state.pending = message;
|
|
3278
3293
|
}
|
|
3279
3294
|
|
|
3280
3295
|
/**
|
|
@@ -3304,13 +3319,15 @@ export function mountStylebookCanvas(
|
|
|
3304
3319
|
// (and fake test channels pass messages by reference, so sharing one object would alias them).
|
|
3305
3320
|
const cloneableDoc = plainCopy(generated.doc);
|
|
3306
3321
|
const cloneableShadow = plainCopy(generated.doc);
|
|
3307
|
-
const message:
|
|
3322
|
+
const message: RenderMsg = {
|
|
3308
3323
|
// The specimen carries no tab identity, but the STAGE it is mounted into does: a stylebook is
|
|
3309
3324
|
// Opened as a tab like anything else, and its `previewColorScheme` is that tab's.
|
|
3310
3325
|
/* A stylebook specimen is generated, not a project document, so it references no project
|
|
3311
3326
|
media and needs no resolution. */
|
|
3312
3327
|
assets: null,
|
|
3313
3328
|
colorScheme: schemeWireFor(tabOfContainer(canvasEl)),
|
|
3329
|
+
// And its language, for the same reason: a stylebook draws `:lang()` rules and `dir` too.
|
|
3330
|
+
locale: localeWireFor(tabOfContainer(canvasEl)),
|
|
3314
3331
|
doc: cloneableDoc,
|
|
3315
3332
|
docBase: `${canvasBaseOrigin()}/`,
|
|
3316
3333
|
gen,
|
|
@@ -3392,6 +3409,21 @@ export function postColorSchemeToLiveHosts(
|
|
|
3392
3409
|
* `dir` is computed here and sent with the tag: `localeDirection` is CLDR's answer through
|
|
3393
3410
|
* `Intl.Locale`, and a frame deriving it again is a second copy of the RTL script list to keep.
|
|
3394
3411
|
*/
|
|
3412
|
+
/** A locale tag as the frame applies it, with its direction; null stays null. */
|
|
3413
|
+
function localeWire(locale: string | null): WireLocale | null {
|
|
3414
|
+
return locale === null ? null : { dir: localeDirection(locale), locale };
|
|
3415
|
+
}
|
|
3416
|
+
|
|
3417
|
+
/**
|
|
3418
|
+
* The language a TAB's artboard draws in, as wire data (studio.md §20.2): the one rule
|
|
3419
|
+
* `getEffectiveRenderLocale` answers, read at post time for `schemeWireFor`'s reason.
|
|
3420
|
+
*/
|
|
3421
|
+
function localeWireFor(tab: Tab | null): WireLocale | null {
|
|
3422
|
+
return localeWire(
|
|
3423
|
+
tab ? getEffectiveRenderLocale(tab.session.ui.previewLocale, tab.documentPath) : null,
|
|
3424
|
+
);
|
|
3425
|
+
}
|
|
3426
|
+
|
|
3395
3427
|
export function postLocaleToLiveHosts(locale: string | null, root?: HTMLElement | null): void {
|
|
3396
3428
|
const dir = localeDirection(locale);
|
|
3397
3429
|
for (const host of liveHosts) {
|
|
@@ -3404,6 +3436,12 @@ export function postLocaleToLiveHosts(locale: string | null, root?: HTMLElement
|
|
|
3404
3436
|
}
|
|
3405
3437
|
if (host.ready) {
|
|
3406
3438
|
host.channel.post({ dir, kind: "setLocale", locale });
|
|
3439
|
+
} else if (host.pending?.kind === "render") {
|
|
3440
|
+
/* A host still booting draws the render it is waiting for, so THAT is what learns the
|
|
3441
|
+
language: a restored session writes `previewLocale` after its files have opened, by which
|
|
3442
|
+
time a pane's render may already be pending with the old value, and no render follows. A
|
|
3443
|
+
host with nothing pending is skipped; its render reads the value when it is posted. */
|
|
3444
|
+
host.pending = { ...host.pending, locale: localeWire(locale) };
|
|
3407
3445
|
}
|
|
3408
3446
|
}
|
|
3409
3447
|
}
|
|
@@ -3484,23 +3522,57 @@ export function postStyleUpdateToStylebookHosts(style: JxStyle): number {
|
|
|
3484
3522
|
return posted;
|
|
3485
3523
|
}
|
|
3486
3524
|
|
|
3525
|
+
/**
|
|
3526
|
+
* A pan asked for before any stylebook canvas could serve it: the tag, served by the next stylebook
|
|
3527
|
+
* render that draws its card while it is still the selection ({@link servePendingStylebookPan}).
|
|
3528
|
+
*/
|
|
3529
|
+
let pendingStylebookPan: string | null = null;
|
|
3530
|
+
|
|
3531
|
+
/** Post the measure that pans `host` to `tag`'s card. `false` when the host cannot serve it yet. */
|
|
3532
|
+
function postStylebookPan(host: HostState | null, tag: string): boolean {
|
|
3533
|
+
if (!host?.stylebook || !host.ready) {
|
|
3534
|
+
return false;
|
|
3535
|
+
}
|
|
3536
|
+
const cardPath = host.stylebook.tagToCardPath.get(tag);
|
|
3537
|
+
if (!cardPath) {
|
|
3538
|
+
return false;
|
|
3539
|
+
}
|
|
3540
|
+
host.measureSeq += 1;
|
|
3541
|
+
host.panReqId = host.measureSeq;
|
|
3542
|
+
host.channel.post({ kind: "measure", paths: [[...cardPath]], reqId: host.panReqId });
|
|
3543
|
+
return true;
|
|
3544
|
+
}
|
|
3545
|
+
|
|
3487
3546
|
/**
|
|
3488
3547
|
* Pan the canvas so the selected tag's card is centered (layers-panel "locate" affordance). The
|
|
3489
3548
|
* card lives inside the iframe, so it is measured over the bridge and the reply pans by the
|
|
3490
3549
|
* converted parent-viewport rect (see the `geometry` handler's panReqId branch).
|
|
3550
|
+
*
|
|
3551
|
+
* A pan the canvas cannot serve yet is KEPT, not dropped. The Styles panel switches the pane to the
|
|
3552
|
+
* Elements view and selects a tag in one tick, from the Variables view, where no stylebook frame
|
|
3553
|
+
* exists: the frame that will draw the card has not been mounted. The request waits for it.
|
|
3491
3554
|
*/
|
|
3492
3555
|
export function panToStylebookTag(tag: string): void {
|
|
3493
|
-
|
|
3494
|
-
|
|
3556
|
+
pendingStylebookPan = postStylebookPan(hostForActivePanel(), tag) ? null : tag;
|
|
3557
|
+
}
|
|
3558
|
+
|
|
3559
|
+
/**
|
|
3560
|
+
* Serve a kept pan on a stylebook render that has just landed: on the canvas the author is in, and
|
|
3561
|
+
* only while its tag is still the selection, so a request the author has since moved past is
|
|
3562
|
+
* forgotten rather than served late.
|
|
3563
|
+
*/
|
|
3564
|
+
function servePendingStylebookPan(state: HostState): void {
|
|
3565
|
+
const tag = pendingStylebookPan;
|
|
3566
|
+
if (tag === null || !state.stylebook) {
|
|
3495
3567
|
return;
|
|
3496
3568
|
}
|
|
3497
|
-
|
|
3498
|
-
|
|
3569
|
+
if (shell.stylebook.selection !== tag) {
|
|
3570
|
+
pendingStylebookPan = null;
|
|
3499
3571
|
return;
|
|
3500
3572
|
}
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3573
|
+
if (state === hostForActivePanel() && postStylebookPan(state, tag)) {
|
|
3574
|
+
pendingStylebookPan = null;
|
|
3575
|
+
}
|
|
3504
3576
|
}
|
|
3505
3577
|
|
|
3506
3578
|
// ─── Format-toolbar bridge (Phase 4b-2) ─────────────────────────────────────────
|
|
@@ -56,6 +56,17 @@ import type { IframeToParent, ParentToIframe, SerializedKey, SyncedChord } from
|
|
|
56
56
|
*/
|
|
57
57
|
export const FRAME_KEY_SCOPES = ["caret", "canvas", "global"] as const;
|
|
58
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Commands whose chords the frame never forwards, though their scope is on its stack.
|
|
61
|
+
*
|
|
62
|
+
* `pane.backToHome` holds bare Escape in the global scope, and it applies only to a view opened
|
|
63
|
+
* beside a strip-less workspace's home (a media viewer, a comparison, `project.json` as Code), none
|
|
64
|
+
* of which is a canvas frame. Projected into the table, it made every frame cancel Escape in
|
|
65
|
+
* Preview and mid-sentence too, where nothing else claims it, so an author's own `<dialog>` or
|
|
66
|
+
* popover in the rendered page could no longer be dismissed with it.
|
|
67
|
+
*/
|
|
68
|
+
export const HOST_ONLY_COMMANDS: ReadonlySet<string> = new Set(["pane.backToHome"]);
|
|
69
|
+
|
|
59
70
|
/** The scope stack a caret session is in — app chords still fire, element-level ones do not. */
|
|
60
71
|
const CARET_STACK = ["caret", "global"] as const;
|
|
61
72
|
/** The stack with a selection but no caret: structural verbs are live. */
|