@jxsuite/studio 6.1.1 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/chunks/2020-5wtzce5g.js +4 -0
- package/dist/chunks/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
- 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-6rbra5dy.js +4 -0
- package/dist/chunks/color-field-gy56c94g.js +4 -0
- package/dist/chunks/color-m7r1vk54.js +4 -0
- package/dist/chunks/color-slider-sqqdyf6c.js +4 -0
- package/dist/chunks/combobox-72h32ejk.js +4 -0
- 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/dialog-c4x05vyx.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-qg1b5eqx.js +51 -0
- package/dist/chunks/icons-63bjtbs7.js +4 -0
- package/dist/chunks/iframe-entry-2zggzajv.js +5 -0
- package/dist/chunks/iframe-entry-76j8vwwx.js +5 -0
- package/dist/chunks/iframe-entry-99nr5zfb.js +5 -0
- package/dist/chunks/iframe-entry-pkgmcgp0.js +5 -0
- package/dist/chunks/iframe-host-ssv7kyj0.js +4 -0
- package/dist/chunks/{index-2veqmnhr.js → index-32eqzv1k.js} +3 -3
- package/dist/chunks/index-f0jn7nnp.js +4 -0
- package/dist/chunks/{javascript-8nbvs12s.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-c421cf8c.js +4 -0
- 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-bdpzbfvs.js +4 -0
- package/dist/chunks/monaco-binding-vq1hgnn0.js +4 -0
- 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/number-field-y62xq0ty.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/select-rzds841e.js +4 -0
- package/dist/chunks/source-control-kwktr9y6.js +4 -0
- package/dist/chunks/split-c9zfdgxf.js +4 -0
- 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-6m380wp7.js +5 -0
- package/dist/chunks/studio-80jyh1xh.js +4 -0
- package/dist/chunks/studio-83mk4bgg.js +9 -0
- package/dist/chunks/{studio-kggey1jt.js → studio-881z1xrx.js} +4 -4
- package/dist/chunks/studio-8m0y2qe7.js +5 -0
- package/dist/chunks/studio-8tr6cfrc.js +5 -0
- 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-bbe4c90a.js +5 -0
- 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-8grwxtqk.js → studio-jcnsdaep.js} +4 -4
- package/dist/chunks/studio-jsgf2q5k.js +7 -0
- package/dist/chunks/{studio-1q1sh2ax.js → studio-k3xxbagr.js} +3 -3
- package/dist/chunks/studio-k7evxqh4.js +5 -0
- 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-rv11kfwa.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-h46vtzk8.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-wszjyh0j.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-pre0skq6.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-t6b6qe31.js → studio-r5qy30vx.js} +4 -4
- 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/swatch-group-ewh24n1f.js +4 -0
- package/dist/chunks/tabs-f5cw3tgp.js +4 -0
- package/dist/chunks/textfield-wewc8rq2.js +4 -0
- package/dist/chunks/toast-1gv0h53h.js +4 -0
- package/dist/chunks/toast-host-1yg5ar8d.js +4 -0
- package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
- package/dist/chunks/tooltip-yypz28gq.js +4 -0
- package/dist/chunks/tree-9xa4hm7n.js +4 -0
- 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-bv552sfx.js +4 -0
- package/dist/iframe-entry.js +20 -16
- package/dist/manifest.json +77 -63
- package/dist/studio.js +106 -107
- package/dist/workers/ts.worker.js +3 -3
- package/package.json +17 -16
- package/src/about/about-modal.ts +4 -3
- package/src/account/action-flow.ts +45 -38
- package/src/account-status.ts +7 -2
- package/src/browse/component-examples.ts +272 -0
- package/src/browse/library-commands.ts +64 -104
- package/src/browse/library-layouts.ts +270 -53
- package/src/browse/library-model.ts +194 -134
- package/src/browse/library-pane.ts +748 -440
- package/src/browse/library-preview.ts +161 -26
- 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 +40 -10
- package/src/canvas/asset-resolve.ts +19 -23
- package/src/canvas/canvas-helpers.ts +7 -6
- package/src/canvas/canvas-live-render.ts +260 -77
- package/src/canvas/canvas-origin.ts +37 -12
- package/src/canvas/canvas-page-context.ts +112 -0
- package/src/canvas/canvas-patcher.ts +30 -30
- package/src/canvas/canvas-perf.ts +11 -5
- package/src/canvas/canvas-render.ts +175 -148
- package/src/canvas/canvas-surface.ts +5 -3
- package/src/canvas/canvas-utils.ts +147 -61
- package/src/canvas/dialog-path.ts +9 -4
- package/src/canvas/dialog-state.ts +1 -2
- package/src/canvas/diff-marks.ts +9 -16
- package/src/canvas/diff-toolbar.ts +8 -7
- package/src/canvas/edit-width-drag.ts +4 -1
- package/src/canvas/edit-width.ts +1 -3
- package/src/canvas/iframe-channel.ts +27 -13
- package/src/canvas/iframe-drop.ts +120 -12
- package/src/canvas/iframe-editable-root.ts +29 -16
- package/src/canvas/iframe-entry.ts +104 -75
- package/src/canvas/iframe-eval.ts +73 -49
- package/src/canvas/iframe-host.ts +269 -158
- package/src/canvas/iframe-inline-edit.ts +49 -30
- package/src/canvas/iframe-insert.ts +5 -4
- package/src/canvas/iframe-interaction.ts +30 -25
- package/src/canvas/iframe-keys.ts +11 -0
- package/src/canvas/iframe-overlay.ts +1 -1
- package/src/canvas/iframe-patch.ts +25 -21
- package/src/canvas/iframe-position.ts +12 -6
- package/src/canvas/iframe-protocol.ts +36 -21
- package/src/canvas/iframe-render.ts +84 -35
- package/src/canvas/iframe-slash.ts +24 -11
- package/src/canvas/iframe-subtree.ts +10 -3
- package/src/canvas/npm-modules.ts +22 -0
- package/src/canvas/path-mapping.ts +19 -12
- package/src/canvas/popover-path.ts +7 -3
- package/src/canvas/popover-state.ts +1 -2
- package/src/canvas/preview-navigate.ts +16 -0
- package/src/canvas/repeater-sources.ts +200 -0
- package/src/canvas/serialize-scope.ts +13 -5
- package/src/canvas/stage-scrollbar.ts +7 -2
- package/src/canvas/surface-registry.ts +27 -3
- package/src/collab/collab-commands.ts +7 -2
- package/src/collab/collab-session.ts +84 -45
- package/src/collab/collab-state.ts +4 -3
- package/src/collab/monaco-binding.ts +16 -13
- package/src/collab/monaco-cursors.ts +5 -2
- package/src/commands/app-commands.ts +16 -6
- package/src/commands/budget.ts +13 -11
- package/src/commands/command-args.ts +103 -71
- package/src/commands/context.ts +55 -28
- package/src/commands/defaults.ts +69 -45
- package/src/commands/keymap.ts +56 -43
- package/src/commands/levels.ts +14 -8
- package/src/commands/live-context.ts +9 -7
- package/src/commands/reference.ts +2 -1
- package/src/commands/registry.ts +22 -11
- package/src/commands/run-reported.ts +15 -10
- package/src/component-props.ts +46 -30
- package/src/content/collection-match.ts +11 -9
- package/src/content/collection-pages.ts +412 -0
- package/src/content/content-collections.ts +270 -0
- package/src/content/draft-state.ts +4 -3
- package/src/content/entry-commands.ts +54 -62
- package/src/content/entry-editor.ts +137 -32
- package/src/content/entry-fields.ts +25 -8
- package/src/content/entry-inspector.ts +225 -0
- package/src/content/entry-model.ts +38 -15
- 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/canvas-context-menu.ts +1 -2
- package/src/editor/canvas-slash-bridge.ts +3 -6
- package/src/editor/content-slice.ts +16 -14
- package/src/editor/context-menu.ts +35 -22
- package/src/editor/convert-targets.ts +30 -35
- package/src/editor/convert-to-component.ts +78 -48
- package/src/editor/convert-to-repeater.ts +34 -22
- package/src/editor/editable-tags.ts +17 -2
- package/src/editor/file-drop-action.ts +29 -22
- package/src/editor/inline-edit-apply.ts +79 -17
- package/src/editor/inline-edit.ts +76 -50
- package/src/editor/inline-format.ts +59 -56
- package/src/editor/inline-link.ts +40 -15
- package/src/editor/insert-component.ts +91 -0
- package/src/editor/insert-zone-action.ts +14 -5
- package/src/editor/merge-tags.ts +58 -19
- package/src/editor/repeater-scope.ts +39 -28
- package/src/editor/shortcuts.ts +76 -42
- package/src/editor/slash-menu.ts +52 -14
- package/src/files/asset-versions.ts +4 -4
- package/src/files/components.ts +89 -20
- package/src/files/elements.ts +5 -6
- package/src/files/file-ops.ts +92 -41
- package/src/files/files.ts +248 -239
- package/src/files/fs-events.ts +18 -7
- package/src/files/media-meta.ts +97 -2
- package/src/files/media-paths.ts +3 -0
- 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 +15 -5
- package/src/format/constraints.ts +1 -1
- package/src/format/convert-file.ts +27 -13
- package/src/format/format-choices.ts +2 -1
- package/src/format/format-host.ts +91 -50
- package/src/github/github-auth-status.ts +27 -3
- package/src/github/github-auth.ts +21 -11
- package/src/github/github-publish.ts +28 -23
- package/src/grid/cell-editors.ts +46 -31
- package/src/grid/cell-popovers.ts +5 -3
- package/src/grid/edit-buffer.ts +10 -9
- package/src/grid/grid-controller.ts +25 -23
- package/src/grid/grid-layout.ts +21 -5
- package/src/grid/grid-open.ts +3 -33
- package/src/grid/grid-panel.ts +65 -6
- package/src/grid/grid-reveal.ts +34 -0
- package/src/grid/grid-source.ts +9 -31
- package/src/grid/grid-view.ts +45 -23
- package/src/grid/redirects-grid.ts +14 -5
- package/src/grid/redirects.ts +16 -14
- package/src/grid/schema-columns.ts +25 -19
- package/src/grid/sources/connector-source.ts +47 -20
- package/src/grid/sources/content-source.ts +100 -31
- package/src/grid/sources/csv-file-source.ts +2 -2
- package/src/grid/tabulator-tables.d.ts +61 -34
- package/src/hosting/document.ts +2 -2
- package/src/hosting/stage.ts +7 -7
- package/src/i18n/i18n-commands.ts +3 -3
- 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 +51 -20
- package/src/new-project/add-repo-modal.ts +20 -19
- package/src/new-project/import-tab.ts +10 -14
- package/src/new-project/location-fields.ts +2 -1
- package/src/new-project/new-project-modal.ts +12 -9
- package/src/packages/jxsuite-update.ts +4 -3
- package/src/packages/pull-package-sync.ts +26 -25
- package/src/page-params.ts +97 -68
- package/src/panels/activity-panel.ts +38 -14
- package/src/panels/ai-chat/attached-context.ts +13 -7
- package/src/panels/ai-chat/chat-markdown.ts +8 -8
- package/src/panels/ai-chat/chat-view.ts +80 -73
- package/src/panels/ai-chat/composer.ts +30 -33
- package/src/panels/ai-chat/sessions-view.ts +1 -2
- package/src/panels/ai-panel.ts +23 -20
- package/src/panels/block-action-bar.ts +57 -46
- package/src/panels/bottom-dock.ts +5 -3
- package/src/panels/canvas-dnd-bridge.ts +36 -26
- 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 +63 -26
- package/src/panels/data-grid.ts +18 -11
- package/src/panels/dnd.ts +115 -138
- package/src/panels/editors.ts +52 -21
- package/src/panels/elements-panel.ts +19 -5
- package/src/panels/empty-state.ts +2 -2
- package/src/panels/events-panel.ts +84 -69
- package/src/panels/formula-workspace.ts +78 -54
- package/src/panels/frontmatter-fields.ts +33 -28
- package/src/panels/git-diff-open.ts +10 -6
- package/src/panels/head-panel.ts +488 -202
- package/src/panels/i18n-panel.ts +20 -12
- package/src/panels/imports-panel.ts +25 -47
- package/src/panels/jump-bar.ts +75 -31
- package/src/panels/layers-panel.ts +130 -101
- package/src/panels/left-panel.ts +25 -11
- package/src/panels/navigator-panels.ts +23 -11
- package/src/panels/pane-context.ts +140 -49
- package/src/panels/pane-grid.ts +55 -26
- package/src/panels/panel-registry.ts +36 -46
- package/src/panels/properties-panel.ts +182 -124
- package/src/panels/quick-search.ts +53 -31
- package/src/panels/right-panel.ts +201 -45
- package/src/panels/seo-modal.ts +54 -125
- package/src/panels/settings-menu.ts +63 -61
- package/src/panels/settings-pane.ts +268 -162
- package/src/panels/signals-panel.ts +156 -135
- package/src/panels/site-model.ts +367 -0
- package/src/panels/site-panel.ts +638 -0
- package/src/panels/statement-editor.ts +230 -140
- package/src/panels/style-panel.ts +253 -206
- package/src/panels/style-utils.ts +114 -51
- package/src/panels/stylebook-doc.ts +195 -60
- package/src/panels/stylebook-layers-panel.ts +48 -89
- package/src/panels/stylebook-panel.ts +60 -27
- package/src/panels/styles-panel.ts +327 -0
- package/src/panels/tab-drop.ts +27 -11
- package/src/panels/tab-strip.ts +143 -49
- package/src/platform-errors.ts +57 -43
- package/src/platform.ts +59 -31
- package/src/platforms/cloud.ts +373 -176
- package/src/platforms/default-platform.ts +14 -8
- package/src/platforms/devserver.ts +180 -142
- package/src/platforms/read-batcher.ts +16 -8
- package/src/project-list.ts +2 -1
- package/src/publish/deploy-checklist.ts +20 -9
- package/src/publish/pages-service.ts +66 -27
- package/src/publish/publish-changes.ts +491 -0
- package/src/publish/publish-commands.ts +88 -22
- package/src/publish/publish-ids.ts +49 -0
- package/src/publish/publish-panel.ts +10 -6
- 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/recent-projects.ts +15 -8
- package/src/resize-edges.ts +26 -36
- package/src/services/a11y-report.ts +26 -19
- package/src/services/agent-seed.ts +23 -11
- package/src/services/ai-ask.ts +9 -12
- package/src/services/ai-command-tools.ts +68 -62
- package/src/services/ai-import-tools.ts +80 -67
- package/src/services/ai-models.ts +17 -13
- package/src/services/ai-project-tools.ts +68 -32
- package/src/services/ai-session-store.ts +19 -10
- package/src/services/ai-system-prompt.ts +46 -20
- package/src/services/ai-tools.ts +71 -27
- package/src/services/ai-write-report.ts +20 -12
- package/src/services/ai-writes.ts +4 -4
- package/src/services/automation.ts +74 -51
- package/src/services/cem-export.ts +149 -58
- package/src/services/cf-settings.ts +4 -4
- package/src/services/clock.ts +6 -1
- package/src/services/code-services.ts +37 -31
- package/src/services/connection.ts +2 -2
- package/src/services/context-manager.ts +14 -10
- package/src/services/context-resolver.ts +20 -8
- package/src/services/data-service.ts +19 -15
- package/src/services/directory-picker.ts +20 -14
- package/src/services/document-assistant.ts +39 -19
- package/src/services/gated-registry.ts +10 -6
- package/src/services/harness/chat-reducer.ts +23 -1
- package/src/services/import-client.ts +91 -38
- package/src/services/import-seed.ts +8 -2
- package/src/services/jx-validate.ts +28 -31
- package/src/services/live-preview.ts +0 -0
- package/src/services/live-surfaces.ts +6 -3
- package/src/services/model-uri.ts +10 -2
- package/src/services/module-preloads.ts +12 -8
- package/src/services/monaco-buffer.ts +43 -24
- package/src/services/monaco-lazy.ts +7 -8
- package/src/services/monaco-setup.ts +23 -16
- package/src/services/notify.ts +44 -17
- package/src/services/popover-report.ts +25 -10
- package/src/services/preview-eval.ts +20 -8
- package/src/services/profile.ts +13 -6
- package/src/services/project-path.ts +13 -10
- package/src/services/references.ts +0 -0
- package/src/services/render-critic.ts +29 -9
- package/src/services/settings/definitions.ts +25 -14
- package/src/services/settings/kernel.ts +13 -4
- package/src/services/settings/write-queue.ts +9 -9
- package/src/services/token-lint.ts +12 -10
- package/src/services/tool-executor.ts +17 -5
- package/src/services/tool-outcomes.ts +44 -24
- package/src/services/trusted-types.ts +24 -7
- package/src/settings/contexts-section.ts +11 -8
- package/src/settings/contributed-section.ts +128 -70
- package/src/settings/css-vars-editor.ts +119 -32
- package/src/settings/defs-editor.ts +38 -35
- package/src/settings/developer-panels.ts +43 -0
- package/src/settings/extension-rows.ts +16 -8
- package/src/settings/extension-sections.ts +42 -14
- package/src/settings/extensions-section.ts +4 -1
- package/src/settings/general-settings.ts +101 -28
- package/src/settings/locales-section.ts +20 -12
- package/src/settings/preferences-dialog.ts +17 -7
- package/src/settings/preferences-keymap.ts +7 -5
- package/src/settings/preferences-sections.ts +11 -5
- package/src/settings/project-sections.ts +28 -11
- package/src/settings/schema-field-ui.ts +12 -1
- package/src/settings/section-registry.ts +116 -11
- package/src/settings/settings-dialog.ts +192 -0
- package/src/settings/settings-document.ts +186 -166
- package/src/shell/tree.ts +6 -5
- package/src/shell.ts +536 -477
- package/src/site-context.ts +101 -32
- package/src/state.ts +68 -57
- package/src/store.ts +54 -34
- package/src/studio.ts +219 -116
- package/src/style/live-preview.ts +1 -1
- package/src/style/project-styles.ts +40 -7
- 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/token-ref.ts +5 -4
- package/src/style/variables-focus.ts +61 -0
- package/src/style/variables-view.ts +235 -0
- package/src/surfaces/about.ts +18 -19
- package/src/surfaces/add-new.json +1482 -0
- package/src/surfaces/add-new.ts +325 -0
- package/src/surfaces/add-repo.ts +17 -19
- package/src/surfaces/ai-chat.ts +33 -38
- package/src/surfaces/ai-credentials-form.ts +6 -16
- package/src/surfaces/ai-managed-connect.ts +3 -4
- package/src/surfaces/ai-model-picker.ts +3 -5
- package/src/surfaces/block-action-bar.ts +22 -11
- package/src/surfaces/boot-failure.json +4 -3
- package/src/surfaces/boot-failure.ts +4 -5
- package/src/surfaces/bottom-dock.json +1 -1
- package/src/surfaces/bottom-dock.ts +9 -18
- package/src/surfaces/canvas-stage.json +30 -19
- package/src/surfaces/canvas-stage.ts +17 -16
- package/src/surfaces/cf-account-picker.ts +17 -18
- 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 +145 -105
- package/src/surfaces/convert-repeater.ts +17 -19
- package/src/surfaces/data-actions.ts +9 -7
- package/src/surfaces/dialog.ts +26 -28
- package/src/surfaces/diff-toolbar.ts +9 -7
- package/src/surfaces/empty-state.json +1 -1
- package/src/surfaces/empty-state.ts +7 -10
- package/src/surfaces/entry-editor.json +136 -0
- package/src/surfaces/entry-editor.ts +35 -11
- package/src/surfaces/entry-inspector.json +371 -0
- package/src/surfaces/entry-inspector.ts +143 -0
- package/src/surfaces/expression-editor.ts +11 -25
- package/src/surfaces/files-panel.ts +27 -14
- package/src/surfaces/formula-palette.ts +4 -5
- package/src/surfaces/github-auth.ts +16 -20
- package/src/surfaces/github-publish.ts +17 -22
- package/src/surfaces/grid-cell.ts +30 -31
- package/src/surfaces/grid-open.ts +10 -14
- package/src/surfaces/grid-panel.ts +13 -9
- package/src/surfaces/grid-replace.ts +13 -13
- package/src/surfaces/grid-views.ts +15 -18
- package/src/surfaces/inspector-dock.json +162 -14
- package/src/surfaces/inspector-dock.ts +59 -31
- package/src/surfaces/jump-bar.ts +5 -6
- package/src/surfaces/jxsuite-update.ts +16 -22
- package/src/surfaces/library-pane.json +670 -437
- package/src/surfaces/library-pane.ts +111 -77
- package/src/surfaces/logic-panel.ts +17 -30
- package/src/surfaces/logic-workspace.ts +13 -15
- package/src/surfaces/media-browser.json +62 -6
- package/src/surfaces/media-browser.ts +26 -11
- package/src/surfaces/media-field.json +1 -1
- package/src/surfaces/media-field.ts +4 -5
- package/src/surfaces/media-library.json +1586 -0
- package/src/surfaces/media-library.ts +282 -0
- package/src/surfaces/media-pane.ts +8 -7
- package/src/surfaces/media-pick-dialog.json +71 -0
- package/src/surfaces/media-pick-dialog.ts +132 -0
- package/src/surfaces/menu.ts +47 -23
- package/src/surfaces/navigator-dock.ts +11 -12
- package/src/surfaces/new-project.ts +27 -26
- package/src/surfaces/pane-context.json +144 -77
- package/src/surfaces/pane-context.ts +44 -25
- package/src/surfaces/pane-grid.ts +15 -10
- package/src/surfaces/panel-activity.ts +5 -6
- package/src/surfaces/panel-data.ts +3 -4
- package/src/surfaces/panel-deploy-checklist.json +12 -6
- package/src/surfaces/panel-deploy-checklist.ts +8 -7
- package/src/surfaces/panel-elements.ts +5 -7
- package/src/surfaces/panel-i18n.ts +5 -7
- package/src/surfaces/panel-imports.ts +6 -13
- package/src/surfaces/panel-outline.ts +25 -19
- package/src/surfaces/panel-page.json +72 -2
- package/src/surfaces/panel-page.ts +49 -25
- package/src/surfaces/panel-problems.ts +5 -7
- package/src/surfaces/panel-signals.json +1 -1
- package/src/surfaces/panel-signals.ts +25 -39
- package/src/surfaces/panel-stylebook-layers.json +71 -204
- package/src/surfaces/panel-stylebook-layers.ts +5 -29
- package/src/surfaces/preferences.json +120 -48
- package/src/surfaces/preferences.ts +29 -11
- package/src/surfaces/progress-modal.ts +15 -9
- package/src/surfaces/properties-panel.json +1 -1
- package/src/surfaces/properties-panel.ts +20 -42
- 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/publish.ts +18 -18
- package/src/surfaces/push-plan.ts +7 -8
- package/src/surfaces/rail.json +1 -159
- package/src/surfaces/rail.ts +22 -79
- package/src/surfaces/reference-field.ts +11 -15
- package/src/surfaces/schema-builder.ts +16 -22
- package/src/surfaces/schema-form.json +10 -2
- package/src/surfaces/schema-form.ts +17 -25
- package/src/surfaces/secret-field.ts +9 -6
- package/src/surfaces/seo.json +1 -1
- package/src/surfaces/seo.ts +21 -15
- package/src/surfaces/settings-contexts.ts +9 -7
- package/src/surfaces/settings-contributed.json +5 -5
- package/src/surfaces/settings-contributed.ts +32 -12
- package/src/surfaces/settings-css-vars.json +44 -36
- package/src/surfaces/settings-css-vars.ts +82 -16
- package/src/surfaces/settings-defs.json +2 -2
- package/src/surfaces/settings-defs.ts +17 -21
- package/src/surfaces/settings-deploy.json +2 -15
- package/src/surfaces/settings-deploy.ts +9 -16
- package/src/surfaces/settings-dialog.json +51 -0
- package/src/surfaces/settings-dialog.ts +169 -0
- package/src/surfaces/settings-extensions.ts +5 -6
- package/src/surfaces/settings-head.ts +33 -39
- package/src/surfaces/settings-locales.ts +8 -20
- package/src/surfaces/settings-overview.json +3 -3
- package/src/surfaces/settings-overview.ts +14 -8
- package/src/surfaces/settings-packages.ts +8 -7
- package/src/surfaces/settings-pane.json +269 -46
- package/src/surfaces/settings-pane.ts +88 -36
- package/src/surfaces/settings-rawjson.ts +5 -6
- package/src/surfaces/shell.json +2 -1
- package/src/surfaces/shell.ts +1 -2
- 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 +42 -9
- package/src/surfaces/statements.ts +13 -18
- package/src/surfaces/statusbar.ts +56 -29
- package/src/surfaces/style-panel.ts +18 -31
- package/src/surfaces/stylebook-chrome.ts +3 -5
- 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/tab-strip.ts +14 -13
- package/src/surfaces/target-line.ts +6 -7
- package/src/surfaces/welcome.ts +6 -8
- 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/patch-ops.ts +4 -3
- package/src/tabs/project-config.ts +32 -21
- package/src/tabs/selection.ts +36 -8
- package/src/tabs/tab.ts +99 -48
- package/src/tabs/transact.ts +98 -53
- package/src/types.ts +53 -43
- package/src/ui/ai-credentials-form.ts +10 -13
- package/src/ui/ai-model-picker.ts +3 -3
- package/src/ui/cf-account-picker.ts +7 -9
- package/src/ui/color-selector.ts +9 -5
- package/src/ui/dynamic-slot.ts +7 -8
- package/src/ui/expression-editor.ts +112 -105
- package/src/ui/form-controls.ts +104 -56
- package/src/ui/formula-catalog.ts +239 -230
- package/src/ui/formula-chips.ts +33 -18
- package/src/ui/layers.ts +57 -31
- package/src/ui/media-picker.ts +300 -47
- package/src/ui/popover-surface.ts +20 -12
- package/src/ui/progress-modal.ts +13 -8
- package/src/ui/regions.ts +14 -12
- package/src/ui/schema-form.ts +372 -97
- package/src/ui/surface.ts +71 -8
- package/src/ui/timing.ts +9 -0
- package/src/ui/value-source.ts +44 -31
- package/src/ui/virtual-window.ts +29 -3
- package/src/utils/base64.ts +6 -4
- package/src/utils/edit-display.ts +366 -111
- package/src/utils/element-selectors.ts +3 -2
- package/src/utils/google-fonts.ts +15 -14
- package/src/utils/inherited-style.ts +18 -20
- package/src/utils/link-target.ts +1 -1
- package/src/utils/local-day.ts +18 -0
- package/src/utils/preview-format.ts +25 -3
- package/src/utils/strip-events.ts +49 -22
- package/src/utils/studio-utils.ts +29 -14
- package/src/view.ts +2 -3
- package/src/workspace/pane-derive.ts +14 -16
- package/src/workspace/session.ts +81 -50
- 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 +165 -47
- package/styles/shell-frame.css +30 -7
- package/styles/shell-frame.json +15 -3
- package/dist/chunks/2020-va2wwra4.js +0 -4
- package/dist/chunks/adapter-f93pafd7.js +0 -4
- package/dist/chunks/cf-account-picker-af1h381v.js +0 -4
- package/dist/chunks/cf-settings-125tdm0w.js +0 -4
- package/dist/chunks/color-area-jqhna8zy.js +0 -4
- package/dist/chunks/color-field-embq5ctg.js +0 -4
- package/dist/chunks/color-fpezvnkt.js +0 -4
- package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
- package/dist/chunks/combobox-773hdzyj.js +0 -4
- package/dist/chunks/components-ax2f1fnn.js +0 -4
- package/dist/chunks/content-source-108aqtk1.js +0 -4
- package/dist/chunks/convert-to-repeater-ry5rmppr.js +0 -4
- package/dist/chunks/dialog-mtm9fq5t.js +0 -4
- package/dist/chunks/editor-pfgdmkb0.js +0 -4
- package/dist/chunks/entry-commands-t0k1q0kx.js +0 -4
- package/dist/chunks/extension-sections-6mwh2hf8.js +0 -4
- package/dist/chunks/file-ops-meej5mqf.js +0 -4
- package/dist/chunks/files-44vp8a2s.js +0 -4
- package/dist/chunks/format-host-7q1petb9.js +0 -4
- package/dist/chunks/fs-events-h2mwnxaz.js +0 -4
- package/dist/chunks/git-panel-zngbymvd.js +0 -4
- package/dist/chunks/grid-view-sx9vynsp.js +0 -51
- package/dist/chunks/icons-p44xhjf0.js +0 -4
- package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
- package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
- package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
- package/dist/chunks/iframe-host-qk3ycq87.js +0 -4
- package/dist/chunks/index-wkyfjeqz.js +0 -4
- package/dist/chunks/jsonMode-s8kt9dsj.js +0 -13
- package/dist/chunks/jx-validate-psgd7vsx.js +0 -4
- package/dist/chunks/layers-panel-1kq2jyfk.js +0 -4
- package/dist/chunks/layers-xd92fg8d.js +0 -4
- package/dist/chunks/listbox-s8fkmnq8.js +0 -4
- package/dist/chunks/lit-html-ac4cwwr4.js +0 -4
- package/dist/chunks/media-picker-0svzkdyb.js +0 -4
- package/dist/chunks/menu-37d07z9m.js +0 -4
- package/dist/chunks/menu-5c55ea3d.js +0 -4
- package/dist/chunks/monaco-binding-z6r70pdt.js +0 -4
- package/dist/chunks/monaco-buffer-fz6gq5y7.js +0 -4
- package/dist/chunks/monaco-setup-q4axkgj7.js +0 -4
- package/dist/chunks/notify-0xgtn8q1.js +0 -4
- package/dist/chunks/number-field-gw7sq8rn.js +0 -4
- package/dist/chunks/parse-897fvqah.js +0 -4
- package/dist/chunks/platform-v1qctbe6.js +0 -4
- package/dist/chunks/popover-8htra4er.js +0 -4
- package/dist/chunks/publish-panel-ym1fmgq5.js +0 -4
- package/dist/chunks/quick-search-a54e6t5n.js +0 -4
- package/dist/chunks/references-gmqp82fs.js +0 -4
- package/dist/chunks/right-panel-v7t9awbk.js +0 -4
- package/dist/chunks/section-registry-vhyf3zsr.js +0 -4
- package/dist/chunks/select-n3v7gwas.js +0 -4
- package/dist/chunks/split-pff8f3ze.js +0 -4
- package/dist/chunks/studio-0bhx5hz6.js +0 -5
- package/dist/chunks/studio-0k1ddnyy.js +0 -6
- package/dist/chunks/studio-1b04pd0j.js +0 -64
- package/dist/chunks/studio-4dwbj6gb.js +0 -5
- package/dist/chunks/studio-4tanh828.js +0 -5
- package/dist/chunks/studio-55h4mstj.js +0 -4
- package/dist/chunks/studio-5tnvjkz4.js +0 -5
- package/dist/chunks/studio-60dqgb0c.js +0 -5
- package/dist/chunks/studio-61dp09qg.js +0 -9
- package/dist/chunks/studio-63epcrj2.js +0 -5
- package/dist/chunks/studio-74k29dy9.js +0 -5
- package/dist/chunks/studio-7vg6jcd3.js +0 -5
- package/dist/chunks/studio-7zx31knw.js +0 -9
- package/dist/chunks/studio-8bxk97km.js +0 -5
- package/dist/chunks/studio-933e30n4.js +0 -5
- package/dist/chunks/studio-98wnwhbg.js +0 -5
- package/dist/chunks/studio-9mccjwjh.js +0 -14
- package/dist/chunks/studio-a2ke1e4t.js +0 -5
- package/dist/chunks/studio-e3a2a6v3.js +0 -4
- package/dist/chunks/studio-e81q1vb9.js +0 -5
- package/dist/chunks/studio-epgrmqqm.js +0 -5
- package/dist/chunks/studio-ery42sqr.js +0 -4
- package/dist/chunks/studio-g1shz58g.js +0 -5
- package/dist/chunks/studio-gf0fz03c.js +0 -5
- package/dist/chunks/studio-gjtpe62q.js +0 -6
- package/dist/chunks/studio-gkskhg7m.js +0 -5
- package/dist/chunks/studio-gx4dnjzd.js +0 -5
- package/dist/chunks/studio-j03zga3y.js +0 -9
- package/dist/chunks/studio-jhpxeckz.js +0 -5
- package/dist/chunks/studio-k01r7ykp.js +0 -5
- package/dist/chunks/studio-kk7h30ne.js +0 -7
- package/dist/chunks/studio-kt1zqney.js +0 -5
- package/dist/chunks/studio-m3cwhvye.js +0 -5
- package/dist/chunks/studio-mcayt6hz.js +0 -5
- package/dist/chunks/studio-myjcghv3.js +0 -5
- package/dist/chunks/studio-n8bxwc3y.js +0 -4
- package/dist/chunks/studio-ngm8gvpb.js +0 -5
- package/dist/chunks/studio-nj5a01jy.js +0 -928
- package/dist/chunks/studio-pcgz8heb.js +0 -5
- package/dist/chunks/studio-qcsq0t15.js +0 -5
- package/dist/chunks/studio-qkstvve9.js +0 -5
- package/dist/chunks/studio-qv1pwd3c.js +0 -5
- package/dist/chunks/studio-rc6dvxjb.js +0 -7
- package/dist/chunks/studio-s8dmmz66.js +0 -5
- package/dist/chunks/studio-sp5xzbj4.js +0 -6
- package/dist/chunks/studio-szsjbj0g.js +0 -5
- package/dist/chunks/studio-t1xzawhr.js +0 -16
- package/dist/chunks/studio-tdcprbqb.js +0 -5
- package/dist/chunks/studio-vrmcjf9g.js +0 -7
- package/dist/chunks/studio-vyc0b4he.js +0 -10
- package/dist/chunks/studio-w0cgf6jg.js +0 -5
- package/dist/chunks/studio-w3hskzqk.js +0 -5
- package/dist/chunks/studio-xgrgcdyh.js +0 -9
- package/dist/chunks/studio-xz2yxfcb.js +0 -5
- package/dist/chunks/studio-y6n42tgs.js +0 -5
- package/dist/chunks/studio-yb560vxr.js +0 -5
- package/dist/chunks/studio-yn9f8vtx.js +0 -5
- package/dist/chunks/studio-yw05w8f0.js +0 -7
- package/dist/chunks/studio-z16sgavc.js +0 -5
- package/dist/chunks/studio-zey7zsdw.js +0 -12
- package/dist/chunks/studio-zyqn40w4.js +0 -5
- package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
- package/dist/chunks/tabs-jwthg40w.js +0 -4
- package/dist/chunks/textfield-spy3hc77.js +0 -4
- package/dist/chunks/toast-4d35zd64.js +0 -4
- package/dist/chunks/toast-host-8sjmfed3.js +0 -4
- package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
- package/dist/chunks/tree-h19v1jfz.js +0 -4
- package/dist/chunks/tsMode-2frah6h1.js +0 -14
- package/dist/chunks/workspace-zt81g1ms.js +0 -4
- package/dist/chunks/ws-client-n2bh4hkf.js +0 -4
- package/src/panels/frontmatter-panel.ts +0 -701
- package/src/panels/git-panel.ts +0 -1120
- package/src/surfaces/doc-header.json +0 -776
- package/src/surfaces/doc-header.ts +0 -231
- package/src/surfaces/git-panel.json +0 -1880
- package/src/surfaces/git-panel.ts +0 -272
|
@@ -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";
|
|
@@ -46,6 +46,7 @@ import { formatEditableVerdicts } from "../format/constraints";
|
|
|
46
46
|
import { formatByName } from "../format/format-host";
|
|
47
47
|
import { collabState } from "../collab/collab-state";
|
|
48
48
|
import { DIALOG_COMMANDS, isDialog, POPOVER_COMMANDS } from "@jxsuite/schema/dialogs";
|
|
49
|
+
import { isNodeObject } from "@jxsuite/schema/guards";
|
|
49
50
|
import { isPopover } from "@jxsuite/schema/overlays";
|
|
50
51
|
import { localeDirection } from "@jxsuite/schema/locale";
|
|
51
52
|
import { getPlatform, hasPlatform } from "../platform";
|
|
@@ -66,27 +67,79 @@ import type {
|
|
|
66
67
|
SerializableRect,
|
|
67
68
|
SerializedKey,
|
|
68
69
|
SyncedChord,
|
|
69
|
-
|
|
70
|
+
WireLocale,
|
|
70
71
|
} from "./iframe-protocol";
|
|
72
|
+
import { getEffectiveRenderLocale } from "../site-context";
|
|
73
|
+
import type { JxDocOp } from "../tabs/patch-ops";
|
|
71
74
|
import type { IframeChannel } from "./iframe-channel";
|
|
72
75
|
import type { OverlayLayer, OverlayPlacement } from "./iframe-overlay";
|
|
73
76
|
import type { SlashCommand } from "../editor/inline-edit";
|
|
74
77
|
import type { Tab } from "../tabs/tab";
|
|
75
|
-
import type { JxExpressionNode, JxMutableNode } from "@jxsuite/schema/types";
|
|
78
|
+
import type { JxExpressionNode, JxMutableNode, JxStyle } from "@jxsuite/schema/types";
|
|
76
79
|
import { bundleUrl } from "../services/bundle-base";
|
|
77
80
|
|
|
78
|
-
/**
|
|
79
|
-
|
|
81
|
+
/**
|
|
82
|
+
* A plain-data copy of a value bound for `postMessage`.
|
|
83
|
+
*
|
|
84
|
+
* A JSON round trip rather than `structuredClone`, which throws on exactly what this exists to
|
|
85
|
+
* drop: reactive-proxy internals and stray functions riding on a value read off a live store.
|
|
86
|
+
*/
|
|
87
|
+
function plainCopy<T>(value: T): T {
|
|
88
|
+
/* SAFETY: Every value posted through here is document or config data, which is JSON by contract,
|
|
89
|
+
so the round trip returns the same shape minus only what the realm boundary cannot carry. */
|
|
90
|
+
// oxlint-disable-next-line unicorn/prefer-structured-clone
|
|
91
|
+
return JSON.parse(JSON.stringify(value)) as T;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** A deferred re-entry into inline editing, waiting for the host's DOM to reflect a split/insert. */
|
|
95
|
+
interface PendingEnterEdit {
|
|
96
|
+
path: (string | number)[];
|
|
97
|
+
minGen: number;
|
|
98
|
+
offset?: number;
|
|
99
|
+
/** Set when the deferred re-entry is a PROP host rather than a block (see deferEnterEdit). */
|
|
100
|
+
prop?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** The `enterEdit` message a host posts to re-enter inline editing. */
|
|
104
|
+
type EnterEditMsg = Extract<ParentToIframe, { kind: "enterEdit" }>;
|
|
105
|
+
|
|
106
|
+
/** A full-render message, as one host receives it. */
|
|
107
|
+
type RenderMsg = Extract<ParentToIframe, { kind: "render" }>;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The source data a drag session retains for its drop, exactly what {@link applyDropInstruction}
|
|
111
|
+
* consumes.
|
|
112
|
+
*/
|
|
113
|
+
type RetainedDragData = Parameters<typeof applyDropInstruction>[2];
|
|
114
|
+
|
|
115
|
+
/** The empirical zoom of a host's iframe and the iframe's parent-viewport offset. */
|
|
116
|
+
export interface DragGeometry {
|
|
117
|
+
scale: number;
|
|
118
|
+
rect: { left: number; top: number };
|
|
119
|
+
}
|
|
80
120
|
|
|
81
|
-
|
|
121
|
+
/** The current edit session's editing flag + latest selection snapshot, for the parent toolbar. */
|
|
122
|
+
export interface EditSnapshotState {
|
|
123
|
+
editing: boolean;
|
|
124
|
+
editingProp: string | null;
|
|
125
|
+
snapshot: SelectionSnapshot | null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* One artboard's iframe, overlay, selection and edit session.
|
|
130
|
+
*
|
|
131
|
+
* Exported for the drag coordinator, which holds one as an opaque handle and passes it back to the
|
|
132
|
+
* session API ({@link beginDragSession}/{@link hostDragGeometry}/{@link postDragMessage}) without
|
|
133
|
+
* reading its fields.
|
|
134
|
+
*/
|
|
135
|
+
export interface HostState {
|
|
82
136
|
iframe: HTMLIFrameElement;
|
|
83
137
|
/** The `.canvas-panel-canvas` element hosting the iframe + overlay (the WeakMap key). */
|
|
84
138
|
canvasEl: HTMLElement;
|
|
85
139
|
channel: IframeChannel<ParentToIframe, IframeToParent>;
|
|
86
140
|
/**
|
|
87
|
-
* The resolved canvasUrl this iframe was built with — so a host built
|
|
88
|
-
*
|
|
89
|
-
* 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.
|
|
90
143
|
*/
|
|
91
144
|
canvasUrl: string;
|
|
92
145
|
ready: boolean;
|
|
@@ -101,8 +154,22 @@ interface HostState {
|
|
|
101
154
|
/** Primary selected path (mirrors `session.selection`'s last entry), for hover de-dupe. */
|
|
102
155
|
selectionPath: (string | number)[] | null;
|
|
103
156
|
/** The whole selection this host last measured, so a re-measure redraws every box. */
|
|
104
|
-
selectionPaths: JxPath[];
|
|
105
|
-
/**
|
|
157
|
+
selectionPaths: readonly JxPath[];
|
|
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
|
+
*/
|
|
106
173
|
selReqId: number;
|
|
107
174
|
/**
|
|
108
175
|
* The NON-primary selected paths the in-flight selection `measure` covers, serialized. The
|
|
@@ -110,7 +177,7 @@ interface HostState {
|
|
|
110
177
|
* selected node leaves it empty, so nothing but the selection box is ever drawn.
|
|
111
178
|
*/
|
|
112
179
|
coSelectionKeys: Set<string>;
|
|
113
|
-
/** Id of the most recent presence `measure` request (allocated from
|
|
180
|
+
/** Id of the most recent presence `measure` request (allocated from {@link HostState.measureSeq}). */
|
|
114
181
|
presenceReqId: number;
|
|
115
182
|
/** Serialized peer path → presence box meta for the in-flight presence measure. */
|
|
116
183
|
presenceMeta: Map<string, { color: string; label: string }>;
|
|
@@ -157,7 +224,7 @@ interface HostState {
|
|
|
157
224
|
/** Highest snapshot `seq` seen, so stale (re-ordered) snapshots are dropped. */
|
|
158
225
|
lastSnapshotSeq: number;
|
|
159
226
|
/** The last non-null selection rect drawn (parent/overlay coords) — toolbar position fallback. */
|
|
160
|
-
lastSelectionRect:
|
|
227
|
+
lastSelectionRect: OverlayPlacement | null;
|
|
161
228
|
/** The node the pointer last hovered (iframe-viewport rect), so a zoom can hold it still. */
|
|
162
229
|
lastHover: NodeHit | null;
|
|
163
230
|
/**
|
|
@@ -218,8 +285,8 @@ interface HostState {
|
|
|
218
285
|
/**
|
|
219
286
|
* Resolvers for {@link measureCanvasPath} requests, keyed by the `measure` reqId.
|
|
220
287
|
*
|
|
221
|
-
* Allocated from the same `
|
|
222
|
-
* 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.
|
|
223
290
|
*/
|
|
224
291
|
pendingMeasures: Map<number, (hits: NodeHit[]) => void>;
|
|
225
292
|
/**
|
|
@@ -228,13 +295,7 @@ interface HostState {
|
|
|
228
295
|
* render acks (`renderComplete`) at a bumped one — both satisfy `gen >= minGen`. An immediate
|
|
229
296
|
* `enterEdit` would race the escalated ASYNC render and silently fail to find the element.
|
|
230
297
|
*/
|
|
231
|
-
pendingEnterEdit:
|
|
232
|
-
path: (string | number)[];
|
|
233
|
-
minGen: number;
|
|
234
|
-
offset?: number;
|
|
235
|
-
/** Set when the deferred re-entry is a PROP host rather than a block (see deferEnterEdit). */
|
|
236
|
-
prop?: string;
|
|
237
|
-
} | null;
|
|
298
|
+
pendingEnterEdit: PendingEnterEdit | null;
|
|
238
299
|
/**
|
|
239
300
|
* Stylebook capability (set by {@link mountStylebookCanvas}, cleared by page mounts). The specimen
|
|
240
301
|
* doc's paths decode to TAGS, not tab-document paths: hits route to the injected stylebook
|
|
@@ -250,13 +311,6 @@ interface HostState {
|
|
|
250
311
|
panReqId: number;
|
|
251
312
|
}
|
|
252
313
|
|
|
253
|
-
/**
|
|
254
|
-
* Opaque drag-target host handle for the coordinator bridge. The bridge passes it back to the
|
|
255
|
-
* session API ({@link beginDragSession}/{@link hostDragGeometry}/{@link postDragMessage}) without
|
|
256
|
-
* reading its fields.
|
|
257
|
-
*/
|
|
258
|
-
export type DragHost = HostState;
|
|
259
|
-
|
|
260
314
|
const hosts = new WeakMap<HTMLElement, HostState>();
|
|
261
315
|
|
|
262
316
|
/** Every live host, so the selection watcher can re-measure each one when selection changes. */
|
|
@@ -271,7 +325,7 @@ const liveHosts = new Set<HostState>();
|
|
|
271
325
|
let currentDragSeq = 0;
|
|
272
326
|
|
|
273
327
|
/** Parent-retained source data keyed by `dragSeq` (the block fragment never crosses the boundary). */
|
|
274
|
-
const retainedSrcData = new Map<number,
|
|
328
|
+
const retainedSrcData = new Map<number, RetainedDragData>();
|
|
275
329
|
|
|
276
330
|
/**
|
|
277
331
|
* The last session whose cursor-carrying `dragOver` arrived FROM an iframe, and when. While a
|
|
@@ -421,9 +475,10 @@ export function requestCanvasEval(
|
|
|
421
475
|
}
|
|
422
476
|
evalReqId += 1;
|
|
423
477
|
const reqId = evalReqId;
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
478
|
+
/* Expression nodes come off the reactive document — only plain values may cross postMessage.
|
|
479
|
+
SAFETY: A request's nodes are expression nodes by the caller's contract, and the frame re-checks
|
|
480
|
+
`operator` before evaluating one (`iframe-eval.ts`), reporting anything else per expression. */
|
|
481
|
+
const wireExprs = plainCopy(exprs) as { id: string; node: JxExpressionNode }[];
|
|
427
482
|
target.channel.post({
|
|
428
483
|
contextPath: contextPath ? [...contextPath] : null,
|
|
429
484
|
exprs: wireExprs,
|
|
@@ -541,7 +596,7 @@ export function liveDragHostAt(cursor: { x: number; y: number }): HostState | nu
|
|
|
541
596
|
export function beginDragSession(
|
|
542
597
|
host: HostState,
|
|
543
598
|
src: DragSrcKind,
|
|
544
|
-
srcData:
|
|
599
|
+
srcData: RetainedDragData,
|
|
545
600
|
): number {
|
|
546
601
|
currentDragSeq += 1;
|
|
547
602
|
retainedSrcData.set(currentDragSeq, srcData);
|
|
@@ -569,7 +624,7 @@ export function beginDragSession(
|
|
|
569
624
|
export function adoptDragSession(
|
|
570
625
|
_host: HostState,
|
|
571
626
|
_src: DragSrcKind,
|
|
572
|
-
srcData:
|
|
627
|
+
srcData: RetainedDragData,
|
|
573
628
|
seq: number,
|
|
574
629
|
): number {
|
|
575
630
|
currentDragSeq = seq;
|
|
@@ -587,10 +642,7 @@ export function currentDragSession(): number {
|
|
|
587
642
|
* read FRESH so a pan/zoom mid-drag is reflected. NOT `effectiveZoom()` (a separate path that can
|
|
588
643
|
* desync). The matching iframe parent-viewport rect is returned so the cursor map cancels the pan.
|
|
589
644
|
*/
|
|
590
|
-
export function hostDragGeometry(host: HostState): {
|
|
591
|
-
scale: number;
|
|
592
|
-
rect: { left: number; top: number };
|
|
593
|
-
} {
|
|
645
|
+
export function hostDragGeometry(host: HostState): DragGeometry {
|
|
594
646
|
const rect = rectOf(host.iframe);
|
|
595
647
|
const scale = host.iframe.clientWidth > 0 ? rect.width / host.iframe.clientWidth : 1;
|
|
596
648
|
return { rect, scale };
|
|
@@ -735,8 +787,8 @@ function measureIn(
|
|
|
735
787
|
path: readonly (string | number)[],
|
|
736
788
|
): Promise<CanvasPoint | null> {
|
|
737
789
|
return new Promise((resolve) => {
|
|
738
|
-
host.
|
|
739
|
-
const reqId = host.
|
|
790
|
+
host.measureSeq += 1;
|
|
791
|
+
const reqId = host.measureSeq;
|
|
740
792
|
const timer = setTimeout(() => {
|
|
741
793
|
host.pendingMeasures.delete(reqId);
|
|
742
794
|
resolve(null);
|
|
@@ -1317,7 +1369,7 @@ export function postDialogOpen(tab: { id: string }, path: JxPath | null): void {
|
|
|
1317
1369
|
* `host` is deliberately not a pane-scoped parameter name (see `PANE_PARAM_NAMES`), and the body
|
|
1318
1370
|
* reads no focus: `panelHostingCanvas` resolves the stage from the host's own element.
|
|
1319
1371
|
*/
|
|
1320
|
-
export function postPatchToHosts(forwardOps:
|
|
1372
|
+
export function postPatchToHosts(forwardOps: JxDocOp[], tabId: string | null): number {
|
|
1321
1373
|
let posted = 0;
|
|
1322
1374
|
for (const host of liveHosts) {
|
|
1323
1375
|
if (!host.iframe.isConnected) {
|
|
@@ -1457,14 +1509,14 @@ function hostTab(state: HostState): Tab | null {
|
|
|
1457
1509
|
}
|
|
1458
1510
|
|
|
1459
1511
|
/**
|
|
1460
|
-
* The tab a drag TARGET is showing — the one public reader on the opaque {@link
|
|
1512
|
+
* The tab a drag TARGET is showing — the one public reader on the opaque {@link HostState} handle.
|
|
1461
1513
|
*
|
|
1462
1514
|
* `panels/canvas-dnd-bridge.ts` binds a session to the host under the cursor and then had nothing
|
|
1463
1515
|
* to ask it, so the one fact it needed about the drag — what the dragged node is CALLED — came from
|
|
1464
1516
|
* `activeTab`. The bridge is not supposed to read the handle's fields (that is what "opaque"
|
|
1465
1517
|
* means), so the answer is a function rather than a widened type.
|
|
1466
1518
|
*/
|
|
1467
|
-
export function dragHostTab(host:
|
|
1519
|
+
export function dragHostTab(host: HostState): Tab | null {
|
|
1468
1520
|
return hostTab(host);
|
|
1469
1521
|
}
|
|
1470
1522
|
|
|
@@ -1499,7 +1551,7 @@ function shownSelections(): Map<string, readonly JxPath[]> {
|
|
|
1499
1551
|
if (!tab) {
|
|
1500
1552
|
continue;
|
|
1501
1553
|
}
|
|
1502
|
-
const sel =
|
|
1554
|
+
const sel: readonly JxPath[] = tab.session.selection;
|
|
1503
1555
|
// Track the selection deeply enough that a change WITHIN the set re-measures: the effect
|
|
1504
1556
|
// Reads every path, not just the array reference.
|
|
1505
1557
|
void sel.map((path) => path.join("/")).join("|");
|
|
@@ -1679,8 +1731,8 @@ function requestPresence(host: HostState): void {
|
|
|
1679
1731
|
host.overlay.setPresence([]);
|
|
1680
1732
|
return;
|
|
1681
1733
|
}
|
|
1682
|
-
host.
|
|
1683
|
-
host.presenceReqId = host.
|
|
1734
|
+
host.measureSeq += 1;
|
|
1735
|
+
host.presenceReqId = host.measureSeq;
|
|
1684
1736
|
host.channel.post({ kind: "measure", paths, reqId: host.presenceReqId });
|
|
1685
1737
|
}
|
|
1686
1738
|
|
|
@@ -1698,12 +1750,14 @@ function requestSelection(host: HostState, sel: readonly JxPath[]): void {
|
|
|
1698
1750
|
}
|
|
1699
1751
|
const primary = primarySelection(sel);
|
|
1700
1752
|
host.selectionPath = primary;
|
|
1701
|
-
host.selectionPaths = sel
|
|
1753
|
+
host.selectionPaths = sel;
|
|
1702
1754
|
if (!host.iframe.isConnected) {
|
|
1703
1755
|
liveHosts.delete(host);
|
|
1704
1756
|
return;
|
|
1705
1757
|
}
|
|
1706
1758
|
if (!primary) {
|
|
1759
|
+
// Nothing selected, so a reply still in flight answers a question nobody is asking any more.
|
|
1760
|
+
host.selReqId = -1;
|
|
1707
1761
|
host.coSelectionKeys.clear();
|
|
1708
1762
|
host.overlay.setSelection(null);
|
|
1709
1763
|
host.overlay.setCoSelection([]);
|
|
@@ -1716,7 +1770,8 @@ function requestSelection(host: HostState, sel: readonly JxPath[]): void {
|
|
|
1716
1770
|
// Cross the postMessage boundary.
|
|
1717
1771
|
const others = cloneSelection(sel.slice(0, -1));
|
|
1718
1772
|
host.coSelectionKeys = new Set(others.map((path) => JSON.stringify(path)));
|
|
1719
|
-
host.
|
|
1773
|
+
host.measureSeq += 1;
|
|
1774
|
+
host.selReqId = host.measureSeq;
|
|
1720
1775
|
host.channel.post({
|
|
1721
1776
|
kind: "measure",
|
|
1722
1777
|
paths: [[...primary], ...others],
|
|
@@ -1737,13 +1792,15 @@ function requestStylebookSelection(host: HostState): void {
|
|
|
1737
1792
|
const tag = shell.stylebook.selection;
|
|
1738
1793
|
const cardPath = tag ? host.stylebook?.tagToCardPath.get(tag) : undefined;
|
|
1739
1794
|
if (!tag || !cardPath) {
|
|
1795
|
+
host.selReqId = -1;
|
|
1740
1796
|
host.overlay.setSelection(null);
|
|
1741
1797
|
return;
|
|
1742
1798
|
}
|
|
1743
1799
|
if (!host.ready) {
|
|
1744
1800
|
return;
|
|
1745
1801
|
}
|
|
1746
|
-
host.
|
|
1802
|
+
host.measureSeq += 1;
|
|
1803
|
+
host.selReqId = host.measureSeq;
|
|
1747
1804
|
host.channel.post({ kind: "measure", paths: [[...cardPath]], reqId: host.selReqId });
|
|
1748
1805
|
}
|
|
1749
1806
|
|
|
@@ -1752,9 +1809,9 @@ function requestStylebookSelection(host: HostState): void {
|
|
|
1752
1809
|
*
|
|
1753
1810
|
* This was the literal `/packages/studio/canvas.html` — a repo dev-server path baked into a browser
|
|
1754
1811
|
* bundle, correct on exactly one host out of four. It happened to work because every other host
|
|
1755
|
-
* overrides `canvasUrl`: the chromium launcher builds one from its token
|
|
1756
|
-
*
|
|
1757
|
-
*
|
|
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.
|
|
1758
1815
|
*
|
|
1759
1816
|
* `bundleUrl` resolves it against the ENTRY's directory, which is the one fact every host agrees on
|
|
1760
1817
|
* (see services/bundle-base.ts), so the fallback is now correct everywhere rather than accidentally
|
|
@@ -1764,12 +1821,6 @@ function defaultCanvasUrl(): string {
|
|
|
1764
1821
|
return bundleUrl("../canvas.html");
|
|
1765
1822
|
}
|
|
1766
1823
|
|
|
1767
|
-
/**
|
|
1768
|
-
* Loads nothing, deliberately: what a platform that resolves its canvasUrl LATER gets in the
|
|
1769
|
-
* meantime. See {@link StudioPlatform.canvasUrlDeferred}.
|
|
1770
|
-
*/
|
|
1771
|
-
const DEFERRED_CANVAS_URL = "about:blank";
|
|
1772
|
-
|
|
1773
1824
|
/**
|
|
1774
1825
|
* Release one host: its channel, its overlay, its frame, and everything awaiting a reply from it.
|
|
1775
1826
|
*
|
|
@@ -1815,27 +1866,12 @@ function releaseHost(host: HostState): void {
|
|
|
1815
1866
|
liveHosts.delete(host);
|
|
1816
1867
|
}
|
|
1817
1868
|
|
|
1818
|
-
/**
|
|
1819
|
-
* Which document this pane's canvas iframe should load.
|
|
1820
|
-
*
|
|
1821
|
-
* The `canvasUrlDeferred` branch is the one that needs saying. Electrobun resolves its canvasUrl
|
|
1822
|
-
* asynchronously — it is this window's loopback port, fetched over RPC inside `activate()` — and
|
|
1823
|
-
* until the fix above, the bundle-relative default resolved to nothing servable under `views://`,
|
|
1824
|
-
* so an early frame simply failed and `ensureHost` rebuilt against the real URL when it landed. Now
|
|
1825
|
-
* that default RESOLVES: `views://studio/canvas.html` is a document electrobun really does stage.
|
|
1826
|
-
* An early frame would therefore boot the whole canvas bundle inside the SHELL's app-privileged
|
|
1827
|
-
* origin, in a CEF instance running `disable-site-isolation-trials` — and the cross-origin loopback
|
|
1828
|
-
* canvas exists precisely so that never happens.
|
|
1829
|
-
*/
|
|
1869
|
+
/** Which document this pane's canvas iframe should load. */
|
|
1830
1870
|
function resolveCanvasUrl(): string {
|
|
1831
1871
|
if (!hasPlatform()) {
|
|
1832
1872
|
return defaultCanvasUrl();
|
|
1833
1873
|
}
|
|
1834
|
-
|
|
1835
|
-
if (platform.canvasUrl) {
|
|
1836
|
-
return platform.canvasUrl;
|
|
1837
|
-
}
|
|
1838
|
-
return platform.canvasUrlDeferred ? DEFERRED_CANVAS_URL : defaultCanvasUrl();
|
|
1874
|
+
return getPlatform().canvasUrl || defaultCanvasUrl();
|
|
1839
1875
|
}
|
|
1840
1876
|
|
|
1841
1877
|
/**
|
|
@@ -1875,9 +1911,8 @@ function ensureHost(canvasEl: HTMLElement): HostState {
|
|
|
1875
1911
|
if (existing.canvasUrl === canvasUrl) {
|
|
1876
1912
|
return existing;
|
|
1877
1913
|
}
|
|
1878
|
-
// The platform
|
|
1879
|
-
//
|
|
1880
|
-
// 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.
|
|
1881
1916
|
releaseHost(existing);
|
|
1882
1917
|
}
|
|
1883
1918
|
// ParentOrigin is the parent's real origin, passed into the iframe URL so the cross-origin iframe
|
|
@@ -1885,8 +1920,8 @@ function ensureHost(canvasEl: HTMLElement): HostState {
|
|
|
1885
1920
|
const parentOrigin = location.origin;
|
|
1886
1921
|
const token = crypto.randomUUID();
|
|
1887
1922
|
// IframeOrigin is the iframe's own origin. For a RELATIVE canvasUrl (dev / chromium) it resolves to
|
|
1888
|
-
// The parent's location.origin (same-origin). For an absolute
|
|
1889
|
-
//
|
|
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.
|
|
1890
1925
|
const iframeOrigin = new URL(canvasUrl, location.href).origin;
|
|
1891
1926
|
const iframe = document.createElement("iframe");
|
|
1892
1927
|
iframe.className = "jx-canvas-iframe";
|
|
@@ -1895,16 +1930,16 @@ function ensureHost(canvasEl: HTMLElement): HostState {
|
|
|
1895
1930
|
iframe.title = "Canvas — live page render";
|
|
1896
1931
|
iframe.style.cssText =
|
|
1897
1932
|
"width:100%;min-height:480px;height:100%;border:0;display:block;background:#fff";
|
|
1898
|
-
// 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)
|
|
1899
1934
|
// Plus parentOrigin (conditionally — see below).
|
|
1900
1935
|
const srcUrl = new URL(canvasUrl, location.href);
|
|
1901
1936
|
srcUrl.searchParams.set("token", token);
|
|
1902
1937
|
// Pass parentOrigin into the iframe src ONLY when the PARENT is served over http(s) (dev / chromium
|
|
1903
1938
|
// — same-origin, so the origin round-trips and the iframe can keep its acceptOrigin STRICT). For a
|
|
1904
|
-
// Non-http(s) parent (
|
|
1939
|
+
// Non-http(s) parent (a custom scheme) OMIT it: a custom scheme may not surface as a postMessage
|
|
1905
1940
|
// Origin (event.origin), so the iframe falls back to acceptOrigin '*' + the shared token (it logs
|
|
1906
1941
|
// The warn) rather than silently stalling. The PARENT side here stays STRICT — acceptOrigin /
|
|
1907
|
-
// TargetOrigin are the real
|
|
1942
|
+
// TargetOrigin are the real iframeOrigin below, a gateable origin.
|
|
1908
1943
|
if (location.protocol === "http:" || location.protocol === "https:") {
|
|
1909
1944
|
srcUrl.searchParams.set("parentOrigin", parentOrigin);
|
|
1910
1945
|
}
|
|
@@ -1950,6 +1985,7 @@ function ensureHost(canvasEl: HTMLElement): HostState {
|
|
|
1950
1985
|
lastHover: null,
|
|
1951
1986
|
lastSelectionRect: null,
|
|
1952
1987
|
lastSnapshotSeq: 0,
|
|
1988
|
+
measureSeq: 0,
|
|
1953
1989
|
overlay,
|
|
1954
1990
|
panReqId: -1,
|
|
1955
1991
|
pending: null,
|
|
@@ -1965,7 +2001,7 @@ function ensureHost(canvasEl: HTMLElement): HostState {
|
|
|
1965
2001
|
ready: false,
|
|
1966
2002
|
selectionPath: null,
|
|
1967
2003
|
selectionPaths: [],
|
|
1968
|
-
selReqId:
|
|
2004
|
+
selReqId: -1,
|
|
1969
2005
|
snapshot: null,
|
|
1970
2006
|
stylebook: null,
|
|
1971
2007
|
tabId: null,
|
|
@@ -2017,7 +2053,7 @@ function hideInsertZoneNow(state: HostState): void {
|
|
|
2017
2053
|
*/
|
|
2018
2054
|
function insertButtonHovered(state: HostState): boolean {
|
|
2019
2055
|
const btn = state.overlay.insertButton;
|
|
2020
|
-
return state.insertHover ||
|
|
2056
|
+
return state.insertHover || btn.matches(":hover");
|
|
2021
2057
|
}
|
|
2022
2058
|
|
|
2023
2059
|
/**
|
|
@@ -2173,7 +2209,8 @@ function handleMessage(state: HostState, msg: IframeToParent): void {
|
|
|
2173
2209
|
behind that message with it. The null check is the same guard for a `targetPath` an edit
|
|
2174
2210
|
has since invalidated, which threw for the same reason. */
|
|
2175
2211
|
const target = getNodeAtPath(tab.doc.document, msg.targetPath);
|
|
2176
|
-
|
|
2212
|
+
// A path can resolve to a string child or to nothing at all, whatever the declared type says.
|
|
2213
|
+
if (!isNodeObject(target)) {
|
|
2177
2214
|
return;
|
|
2178
2215
|
}
|
|
2179
2216
|
if (POPOVER_COMMANDS.has(msg.command)) {
|
|
@@ -2359,7 +2396,7 @@ function handleMessage(state: HostState, msg: IframeToParent): void {
|
|
|
2359
2396
|
const [hit] = msg.hits;
|
|
2360
2397
|
if (hit) {
|
|
2361
2398
|
const { rect: ifr, scale } = hostDragGeometry(state);
|
|
2362
|
-
|
|
2399
|
+
revealParentRect({ height: hit.rect.height * scale, top: hit.rect.y * scale + ifr.top });
|
|
2363
2400
|
}
|
|
2364
2401
|
return;
|
|
2365
2402
|
}
|
|
@@ -2370,7 +2407,7 @@ function handleMessage(state: HostState, msg: IframeToParent): void {
|
|
|
2370
2407
|
// The iframe could not resolve is simply absent from `hits`.
|
|
2371
2408
|
const primaryKey = JSON.stringify(state.selectionPath);
|
|
2372
2409
|
const co: OverlayPlacement[] = [];
|
|
2373
|
-
let rect:
|
|
2410
|
+
let rect: OverlayPlacement | null = null;
|
|
2374
2411
|
if (state.stylebook) {
|
|
2375
2412
|
const [hit] = msg.hits;
|
|
2376
2413
|
rect = hit ? canvasRectToParent(hit.rect) : null;
|
|
@@ -2762,9 +2799,8 @@ function handleMessage(state: HostState, msg: IframeToParent): void {
|
|
|
2762
2799
|
const { rect: ifr, scale } = hostDragGeometry(state);
|
|
2763
2800
|
const left = msg.rect.x * scale + ifr.left;
|
|
2764
2801
|
const top = msg.rect.y * scale + ifr.top;
|
|
2765
|
-
|
|
2802
|
+
const request: CanvasSlashRequest = {
|
|
2766
2803
|
filter: msg.filter,
|
|
2767
|
-
...(msg.showFilter === true ? { showFilter: true } : {}),
|
|
2768
2804
|
onDismiss: () => state.channel.post({ kind: "slashDismissed" }),
|
|
2769
2805
|
onSelect: (cmd) => state.channel.post({ cmd: { ...cmd }, kind: "slashSelect" }),
|
|
2770
2806
|
rect: {
|
|
@@ -2774,7 +2810,11 @@ function handleMessage(state: HostState, msg: IframeToParent): void {
|
|
|
2774
2810
|
top,
|
|
2775
2811
|
width: msg.rect.width * scale,
|
|
2776
2812
|
},
|
|
2777
|
-
}
|
|
2813
|
+
};
|
|
2814
|
+
if (msg.showFilter === true) {
|
|
2815
|
+
request.showFilter = true;
|
|
2816
|
+
}
|
|
2817
|
+
canvasSlashHandler?.show(request);
|
|
2778
2818
|
return;
|
|
2779
2819
|
}
|
|
2780
2820
|
case "slashNav": {
|
|
@@ -2843,6 +2883,7 @@ function onDomUpdated(state: HostState, gen: number): void {
|
|
|
2843
2883
|
requestSelection(state, state.selectionPaths);
|
|
2844
2884
|
requestPresence(state);
|
|
2845
2885
|
hideInsertZoneNow(state);
|
|
2886
|
+
servePendingStylebookPan(state);
|
|
2846
2887
|
if (state.pendingEnterEdit && gen >= state.pendingEnterEdit.minGen) {
|
|
2847
2888
|
const { offset, path, prop } = state.pendingEnterEdit;
|
|
2848
2889
|
state.pendingEnterEdit = null;
|
|
@@ -2871,12 +2912,14 @@ function deferEnterEdit(
|
|
|
2871
2912
|
offset?: number,
|
|
2872
2913
|
prop?: string,
|
|
2873
2914
|
): void {
|
|
2874
|
-
state.
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2915
|
+
const pending: PendingEnterEdit = { minGen: state.lastRenderedGen, path: [...path] };
|
|
2916
|
+
if (offset !== undefined) {
|
|
2917
|
+
pending.offset = offset;
|
|
2918
|
+
}
|
|
2919
|
+
if (prop !== undefined) {
|
|
2920
|
+
pending.prop = prop;
|
|
2921
|
+
}
|
|
2922
|
+
state.pendingEnterEdit = pending;
|
|
2880
2923
|
}
|
|
2881
2924
|
|
|
2882
2925
|
/** Ask the host's iframe to (re-)enter inline editing on `path` (a plain copy crosses the bridge). */
|
|
@@ -2886,12 +2929,14 @@ function reenterEdit(
|
|
|
2886
2929
|
offset?: number,
|
|
2887
2930
|
prop?: string,
|
|
2888
2931
|
): void {
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2932
|
+
const enter: EnterEditMsg = { kind: "enterEdit", path: [...path] };
|
|
2933
|
+
if (offset !== undefined) {
|
|
2934
|
+
enter.offset = offset;
|
|
2935
|
+
}
|
|
2936
|
+
if (prop !== undefined) {
|
|
2937
|
+
enter.prop = prop;
|
|
2938
|
+
}
|
|
2939
|
+
state.channel.post(enter);
|
|
2895
2940
|
}
|
|
2896
2941
|
|
|
2897
2942
|
/**
|
|
@@ -2963,7 +3008,7 @@ function drawHover(state: HostState, hit: NodeHit | null): void {
|
|
|
2963
3008
|
*/
|
|
2964
3009
|
type PreparedRender = Omit<
|
|
2965
3010
|
Extract<ParentToIframe, { kind: "render" }>,
|
|
2966
|
-
"colorScheme" | "gen" | "kind"
|
|
3011
|
+
"colorScheme" | "gen" | "kind" | "locale"
|
|
2967
3012
|
>;
|
|
2968
3013
|
|
|
2969
3014
|
/** One render pass's prepared payloads, by document IDENTITY. */
|
|
@@ -3087,11 +3132,9 @@ function preparePassRender(
|
|
|
3087
3132
|
// So a JSON round-trip (NOT structuredClone, which would throw) drops residual functions /
|
|
3088
3133
|
// Reactive proxy artifacts that would otherwise raise DataCloneError and silently drop the
|
|
3089
3134
|
// Entire message.
|
|
3090
|
-
|
|
3091
|
-
const cloneableDoc = JSON.parse(JSON.stringify(resolved.renderDoc)) as unknown;
|
|
3135
|
+
const cloneableDoc = plainCopy(resolved.renderDoc);
|
|
3092
3136
|
// The RAW page doc (forward-op + data-jx-path coordinate space) crosses as the shadow doc.
|
|
3093
|
-
|
|
3094
|
-
const cloneableShadow = JSON.parse(JSON.stringify(doc)) as unknown;
|
|
3137
|
+
const cloneableShadow = plainCopy(doc);
|
|
3095
3138
|
// Which tags can hold a caret depends on the document's vocabulary, so the format's verdicts
|
|
3096
3139
|
// Ride with the render rather than being baked into the frame. Absent for a native document,
|
|
3097
3140
|
// Where the studio's own element metadata answers on its own.
|
|
@@ -3101,21 +3144,27 @@ function preparePassRender(
|
|
|
3101
3144
|
const renderTab = tabId ? (workspace.tabs.get(tabId) ?? null) : null;
|
|
3102
3145
|
const formatElements = formatByName(renderTab?.doc.sourceFormat)?.studio?.elements;
|
|
3103
3146
|
const editableTags = formatElements ? formatEditableVerdicts(formatElements) : undefined;
|
|
3104
|
-
|
|
3147
|
+
const prepared: PreparedRender = {
|
|
3105
3148
|
assets: resolved.assets,
|
|
3106
3149
|
doc: cloneableDoc,
|
|
3107
3150
|
docBase: resolved.docBase ?? `${canvasBaseOrigin()}/`,
|
|
3108
3151
|
mapperCtx: resolved.mapperCtx,
|
|
3109
|
-
/*
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
`git-diff` while git-diff
|
|
3152
|
+
/* SAFETY: `WireMapperCtx.canvasMode` is typed `string` only because it mirrors `PathMapCtx`,
|
|
3153
|
+
which takes `CanvasMode | string`; `resolveCanvasDocument` fills it with the mode this host
|
|
3154
|
+
was asked to render (`modeOverride ?? canvasModeOfTab(tab)`), and only a canvas mode ever
|
|
3155
|
+
mounts a host. It used to narrow to a union that did not list `git-diff` while git-diff
|
|
3156
|
+
renders went through here every day. */
|
|
3113
3157
|
mode: resolved.mapperCtx.canvasMode as CanvasMode,
|
|
3114
3158
|
shadowDoc: cloneableShadow,
|
|
3115
3159
|
siteStyle: resolved.siteStyle,
|
|
3116
|
-
...(editableTags ? { editableTags } : {}),
|
|
3117
|
-
...(allowAutoRequests ? { allowAutoRequests: true } : {}),
|
|
3118
3160
|
};
|
|
3161
|
+
if (editableTags) {
|
|
3162
|
+
prepared.editableTags = editableTags;
|
|
3163
|
+
}
|
|
3164
|
+
if (allowAutoRequests) {
|
|
3165
|
+
prepared.allowAutoRequests = true;
|
|
3166
|
+
}
|
|
3167
|
+
return prepared;
|
|
3119
3168
|
});
|
|
3120
3169
|
byDoc.set(doc, { mode: modeOverride, payload, tabId, viewTabId });
|
|
3121
3170
|
return payload;
|
|
@@ -3180,25 +3229,30 @@ export async function mountIframeCanvas(
|
|
|
3180
3229
|
paneOfContainer(canvasEl),
|
|
3181
3230
|
modeOverride,
|
|
3182
3231
|
);
|
|
3183
|
-
const message:
|
|
3232
|
+
const message: RenderMsg = {
|
|
3184
3233
|
...prepared,
|
|
3185
3234
|
// Per-TAB, and read at POST time so a scheme flip that raced the shared resolution is not
|
|
3186
3235
|
// Baked into the payload every host shares. `viewTab` is this artboard's tab — defaulted from
|
|
3187
3236
|
// `tabOfContainer(canvasEl)`, the same route the rest of this mount takes.
|
|
3188
3237
|
colorScheme: schemeWireFor(viewTab),
|
|
3189
|
-
/* Per-ARTBOARD, and post-time for a sharper version of the same reason. `preparePassRender`
|
|
3190
|
-
memoizes on the document and hands the SAME payload object to every host in the pass, and a
|
|
3191
|
-
git-diff pass has two hosts holding two documents — but marks are a function of BOTH sides,
|
|
3192
|
-
not of the document this host draws, so they are not derivable from that cache key at all.
|
|
3193
|
-
Baking them in would make the two artboards race for whose marks the pass kept. */
|
|
3194
|
-
...(diffMarks ? { diffMarks } : {}),
|
|
3195
3238
|
gen,
|
|
3196
3239
|
kind: "render",
|
|
3240
|
+
// The language this artboard draws in, per tab and at post time like the scheme.
|
|
3241
|
+
locale: localeWireFor(viewTab),
|
|
3197
3242
|
// Read at POST time for the same reason `colorScheme` is: a render replaces the DOM, so a panel
|
|
3198
3243
|
// The author opened before this pass would close under them without it.
|
|
3199
3244
|
popoverOpen: viewTab?.session.ui.openPopover ?? null,
|
|
3200
3245
|
dialogOpen: viewTab?.session.ui.openDialog ?? null,
|
|
3201
3246
|
};
|
|
3247
|
+
/* Diff marks are per-ARTBOARD, and post-time for a sharper version of the colour scheme's
|
|
3248
|
+
reason. `preparePassRender` memoizes on the document and hands the SAME payload object to every
|
|
3249
|
+
host in the pass, and a git-diff pass has two hosts holding two documents — but marks are a
|
|
3250
|
+
function of BOTH sides, not of the document this host draws, so they are not derivable from
|
|
3251
|
+
that cache key at all. Baking them in would make the two artboards race for whose marks the
|
|
3252
|
+
pass kept. */
|
|
3253
|
+
if (diffMarks) {
|
|
3254
|
+
message.diffMarks = diffMarks;
|
|
3255
|
+
}
|
|
3202
3256
|
state.popoverOpen = message.popoverOpen ?? null;
|
|
3203
3257
|
state.dialogOpen = message.dialogOpen ?? null;
|
|
3204
3258
|
// Preview is the fidelity view: no editing messages are honoured from it, no overlay is painted
|
|
@@ -3215,14 +3269,27 @@ export async function mountIframeCanvas(
|
|
|
3215
3269
|
* until it says `ready`. Counted either way: the message is this pass's work for this host whether
|
|
3216
3270
|
* or not the frame has finished loading.
|
|
3217
3271
|
*/
|
|
3218
|
-
function deliverRender(state: HostState, message:
|
|
3272
|
+
function deliverRender(state: HostState, message: RenderMsg): void {
|
|
3219
3273
|
canvasPerf.hostRenderPosts += 1;
|
|
3220
3274
|
if (state.ready) {
|
|
3221
3275
|
syncAssetVersions(state);
|
|
3222
3276
|
state.channel.post(message);
|
|
3223
|
-
|
|
3224
|
-
|
|
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;
|
|
3225
3291
|
}
|
|
3292
|
+
state.pending = message;
|
|
3226
3293
|
}
|
|
3227
3294
|
|
|
3228
3295
|
/**
|
|
@@ -3250,17 +3317,17 @@ export function mountStylebookCanvas(
|
|
|
3250
3317
|
state.iframe.style.width = widthPx ? `${widthPx}px` : "100%";
|
|
3251
3318
|
// Two independent plain clones: the iframe renders `doc` and folds styleUpdates into `shadowDoc`
|
|
3252
3319
|
// (and fake test channels pass messages by reference, so sharing one object would alias them).
|
|
3253
|
-
|
|
3254
|
-
const
|
|
3255
|
-
|
|
3256
|
-
const cloneableShadow = JSON.parse(JSON.stringify(generated.doc)) as unknown;
|
|
3257
|
-
const message: ParentToIframe = {
|
|
3320
|
+
const cloneableDoc = plainCopy(generated.doc);
|
|
3321
|
+
const cloneableShadow = plainCopy(generated.doc);
|
|
3322
|
+
const message: RenderMsg = {
|
|
3258
3323
|
// The specimen carries no tab identity, but the STAGE it is mounted into does: a stylebook is
|
|
3259
3324
|
// Opened as a tab like anything else, and its `previewColorScheme` is that tab's.
|
|
3260
3325
|
/* A stylebook specimen is generated, not a project document, so it references no project
|
|
3261
3326
|
media and needs no resolution. */
|
|
3262
3327
|
assets: null,
|
|
3263
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)),
|
|
3264
3331
|
doc: cloneableDoc,
|
|
3265
3332
|
docBase: `${canvasBaseOrigin()}/`,
|
|
3266
3333
|
gen,
|
|
@@ -3342,6 +3409,21 @@ export function postColorSchemeToLiveHosts(
|
|
|
3342
3409
|
* `dir` is computed here and sent with the tag: `localeDirection` is CLDR's answer through
|
|
3343
3410
|
* `Intl.Locale`, and a frame deriving it again is a second copy of the RTL script list to keep.
|
|
3344
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
|
+
|
|
3345
3427
|
export function postLocaleToLiveHosts(locale: string | null, root?: HTMLElement | null): void {
|
|
3346
3428
|
const dir = localeDirection(locale);
|
|
3347
3429
|
for (const host of liveHosts) {
|
|
@@ -3354,6 +3436,12 @@ export function postLocaleToLiveHosts(locale: string | null, root?: HTMLElement
|
|
|
3354
3436
|
}
|
|
3355
3437
|
if (host.ready) {
|
|
3356
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) };
|
|
3357
3445
|
}
|
|
3358
3446
|
}
|
|
3359
3447
|
}
|
|
@@ -3371,8 +3459,7 @@ export function postLocaleToLiveHosts(locale: string | null, root?: HTMLElement
|
|
|
3371
3459
|
* off a tab's reactive record is a proxy, and a proxy cannot be structured-cloned.
|
|
3372
3460
|
*/
|
|
3373
3461
|
export function postRedefineElementToLiveHosts(doc: JxMutableNode, base: string): number {
|
|
3374
|
-
|
|
3375
|
-
const plain = JSON.parse(JSON.stringify(doc)) as JxMutableNode;
|
|
3462
|
+
const plain = plainCopy(doc);
|
|
3376
3463
|
let posted = 0;
|
|
3377
3464
|
for (const host of liveHosts) {
|
|
3378
3465
|
if (!host.iframe.isConnected) {
|
|
@@ -3398,13 +3485,8 @@ export function postSiteStyleToLiveHosts(): void {
|
|
|
3398
3485
|
return;
|
|
3399
3486
|
}
|
|
3400
3487
|
// Site config comes off a reactive store — only plain values may cross postMessage.
|
|
3401
|
-
|
|
3402
|
-
const
|
|
3403
|
-
string,
|
|
3404
|
-
unknown
|
|
3405
|
-
> | null;
|
|
3406
|
-
// oxlint-disable-next-line unicorn/prefer-structured-clone
|
|
3407
|
-
const media = JSON.parse(JSON.stringify(config.$media ?? {})) as Record<string, string>;
|
|
3488
|
+
const siteStyle = plainCopy(config.style ?? null);
|
|
3489
|
+
const media = plainCopy(config.$media ?? {});
|
|
3408
3490
|
for (const host of liveHosts) {
|
|
3409
3491
|
if (!host.iframe.isConnected) {
|
|
3410
3492
|
liveHosts.delete(host);
|
|
@@ -3422,11 +3504,10 @@ export function postSiteStyleToLiveHosts(): void {
|
|
|
3422
3504
|
* received it — zero means no stylebook iframe is live yet and the caller should fall through to a
|
|
3423
3505
|
* full render. Each post is followed by a selection re-measure so the box tracks the reflow.
|
|
3424
3506
|
*/
|
|
3425
|
-
export function postStyleUpdateToStylebookHosts(style:
|
|
3507
|
+
export function postStyleUpdateToStylebookHosts(style: JxStyle): number {
|
|
3426
3508
|
let posted = 0;
|
|
3427
3509
|
// Style objects come off the reactive doc — only plain values may cross postMessage.
|
|
3428
|
-
|
|
3429
|
-
const cloneable = JSON.parse(JSON.stringify(style)) as Record<string, unknown>;
|
|
3510
|
+
const cloneable = plainCopy(style);
|
|
3430
3511
|
for (const host of liveHosts) {
|
|
3431
3512
|
if (!host.iframe.isConnected) {
|
|
3432
3513
|
liveHosts.delete(host);
|
|
@@ -3441,33 +3522,63 @@ export function postStyleUpdateToStylebookHosts(style: Record<string, unknown>):
|
|
|
3441
3522
|
return posted;
|
|
3442
3523
|
}
|
|
3443
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
|
+
|
|
3444
3546
|
/**
|
|
3445
3547
|
* Pan the canvas so the selected tag's card is centered (layers-panel "locate" affordance). The
|
|
3446
3548
|
* card lives inside the iframe, so it is measured over the bridge and the reply pans by the
|
|
3447
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.
|
|
3448
3554
|
*/
|
|
3449
3555
|
export function panToStylebookTag(tag: string): void {
|
|
3450
|
-
|
|
3451
|
-
|
|
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) {
|
|
3452
3567
|
return;
|
|
3453
3568
|
}
|
|
3454
|
-
|
|
3455
|
-
|
|
3569
|
+
if (shell.stylebook.selection !== tag) {
|
|
3570
|
+
pendingStylebookPan = null;
|
|
3456
3571
|
return;
|
|
3457
3572
|
}
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3573
|
+
if (state === hostForActivePanel() && postStylebookPan(state, tag)) {
|
|
3574
|
+
pendingStylebookPan = null;
|
|
3575
|
+
}
|
|
3461
3576
|
}
|
|
3462
3577
|
|
|
3463
3578
|
// ─── Format-toolbar bridge (Phase 4b-2) ─────────────────────────────────────────
|
|
3464
3579
|
|
|
3465
|
-
/** The current edit session's
|
|
3466
|
-
export function getEditSnapshot(): {
|
|
3467
|
-
editing: boolean;
|
|
3468
|
-
editingProp: string | null;
|
|
3469
|
-
snapshot: SelectionSnapshot | null;
|
|
3470
|
-
} {
|
|
3580
|
+
/** The current edit session's state, for the parent toolbar. */
|
|
3581
|
+
export function getEditSnapshot(): EditSnapshotState {
|
|
3471
3582
|
/* The same connectivity guard {@link isCaretActive} has, and for the same reason: a session
|
|
3472
3583
|
belongs to a frame, and a frame that has left the document has no caret in it. `releaseHost`
|
|
3473
3584
|
clears `activeEditHost`, so this is the second line rather than the first — it covers the frame
|
|
@@ -3578,7 +3689,7 @@ export function commitActiveEditSession(): void {
|
|
|
3578
3689
|
/** The live host backing the active panel's canvas (for non-edit selection-bar positioning). */
|
|
3579
3690
|
function hostForActivePanel(): HostState | null {
|
|
3580
3691
|
const panel = getActivePanel();
|
|
3581
|
-
return panel ? hostForCanvas(panel.canvas
|
|
3692
|
+
return panel ? hostForCanvas(panel.canvas) : null;
|
|
3582
3693
|
}
|
|
3583
3694
|
|
|
3584
3695
|
/**
|
|
@@ -3592,7 +3703,7 @@ function hostForActivePanel(): HostState | null {
|
|
|
3592
3703
|
* (where it evaluates to exactly `editZoom` — the iframe's layout width is `renderWidth / editZoom`
|
|
3593
3704
|
* while its rendered width is `renderWidth`).
|
|
3594
3705
|
*/
|
|
3595
|
-
export function getEditBarAnchorRect():
|
|
3706
|
+
export function getEditBarAnchorRect(): OverlayPlacement | null {
|
|
3596
3707
|
// The bar rests on the SELECTED ELEMENT's box, edit session or not. It used to prefer the caret's
|
|
3597
3708
|
// Snapshot rect while editing, so it hopped line to line with the caret and sat over the text the
|
|
3598
3709
|
// Author was typing; the snapshot still feeds the format state, never the position. Only an edit
|