@jxsuite/studio 4.0.0 → 5.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 +1 -1
- package/data/elements-meta.json +5 -15
- package/data/html-meta.json +51 -6
- package/dist/chunks/{2020-xp8vnwma.js → 2020-g79n01v9.js} +14 -14
- package/dist/chunks/action-group-sp6tna8v.js +118 -0
- package/dist/chunks/adapter-nj7tnjfn.js +13 -0
- package/dist/chunks/cf-account-picker-fyf63pmy.js +495 -0
- package/dist/chunks/cf-settings-71bv5zn9.js +20 -0
- package/dist/chunks/color-area-v17df7b8.js +154 -0
- package/dist/chunks/color-field-anwybnkn.js +208 -0
- package/dist/chunks/color-slider-44ez96fc.js +79 -0
- package/dist/chunks/color-xgg3kfw7.js +35 -0
- package/dist/chunks/combobox-5e7jev23.js +236 -0
- package/dist/chunks/components-2w1f35qs.js +18 -0
- package/dist/chunks/content-source-3wqeas45.js +46 -0
- package/dist/chunks/convert-to-repeater-d0cgnb6d.js +639 -0
- package/dist/chunks/dialog-s890b918.js +85 -0
- package/dist/chunks/editor-3qhbg51x.js +35 -0
- package/dist/chunks/entry-commands-d6g50j7s.js +42 -0
- package/dist/chunks/extension-sections-fy7q4fe9.js +651 -0
- package/dist/chunks/file-ops-3btj6st0.js +47 -0
- package/dist/chunks/files-ef8fgs3w.js +72 -0
- package/dist/chunks/format-host-3c33nwr8.js +40 -0
- package/dist/chunks/fs-events-13tj6sex.js +18 -0
- package/dist/chunks/git-panel-4wp2rn9b.js +49 -0
- package/dist/chunks/icons-yy10wk9r.js +402 -0
- package/dist/chunks/iframe-entry-15g3n6xv.js +114 -0
- package/dist/chunks/iframe-entry-b27vq81n.js +203 -0
- package/dist/chunks/iframe-entry-nbyxee1y.js +154 -0
- package/dist/chunks/iframe-host-jgesd924.js +115 -0
- package/dist/chunks/{index-nj44jpzj.js → index-mdmyx6s2.js} +11 -11
- package/dist/chunks/index-n4j7qxyr.js +109 -0
- package/dist/chunks/{javascript-q8kpmfah.js → javascript-xvrfrpkb.js} +8 -9
- package/dist/chunks/{jsonMode-dkr040ga.js → jsonMode-tyx2kj6p.js} +526 -527
- package/dist/chunks/jx-validate-j0wxk72w.js +15 -0
- package/dist/chunks/layers-1nq5evsh.js +29 -0
- package/dist/chunks/layers-panel-ar2gh90g.js +40 -0
- package/dist/chunks/listbox-6v2ac08j.js +44 -0
- package/dist/chunks/lit-html-m244w9nh.js +17 -0
- package/dist/chunks/media-picker-2qbetq73.js +33 -0
- package/dist/chunks/menu-q99sy9rf.js +285 -0
- package/dist/chunks/menu-rf7n72mf.js +14 -0
- package/dist/chunks/{monaco-binding-rj6xpx9y.js → monaco-binding-sw6en4dw.js} +12 -15
- package/dist/chunks/monaco-buffer-bhy3hb6m.js +24 -0
- package/dist/chunks/{monaco-setup-rws7k4br.js → monaco-setup-8r62fj6y.js} +27 -37
- package/dist/chunks/notify-628t0anh.js +21 -0
- package/dist/chunks/number-field-5cndyft8.js +72 -0
- package/dist/chunks/parse-0zx14y15.js +10 -0
- package/dist/chunks/platform-ts9cg1a4.js +15 -0
- package/dist/chunks/popover-47z3ytva.js +25 -0
- package/dist/chunks/publish-panel-98f7sr3g.js +27 -0
- package/dist/chunks/quick-search-srzz83k2.js +45 -0
- package/dist/chunks/references-n553f0e1.js +26 -0
- package/dist/chunks/right-panel-rrgx2dn3.js +45 -0
- package/dist/chunks/section-registry-5pq32t0q.js +25 -0
- package/dist/chunks/select-2r16ez41.js +49 -0
- package/dist/chunks/split-g7nm1rgb.js +191 -0
- package/dist/chunks/studio-0hqbpbd0.js +62 -0
- package/dist/chunks/studio-18avnhjp.js +2430 -0
- package/dist/chunks/{studio-kryvsw6j.js → studio-1k325pwf.js} +48 -48
- package/dist/chunks/{studio-hbtp0eh1.js → studio-25hkdrkw.js} +356 -85
- package/dist/chunks/studio-26d7myd1.js +258 -0
- package/dist/chunks/{studio-p8j86wag.js → studio-38emantv.js} +22 -5
- package/dist/chunks/studio-3gxv60tn.js +422 -0
- package/dist/chunks/{studio-8swrjbny.js → studio-3hxkd92t.js} +275 -163
- package/dist/chunks/studio-4m0haseg.js +185 -0
- package/dist/chunks/{studio-ynxwkrzd.js → studio-4wbb9ct0.js} +1953 -1785
- package/dist/chunks/{studio-gv8vvshc.js → studio-5523bpzt.js} +11 -11
- package/dist/chunks/{studio-5q69gfag.js → studio-57mf66w2.js} +1753 -2484
- package/dist/chunks/studio-5jy81t3s.js +17463 -0
- package/dist/chunks/studio-5rt7sqa0.js +1168 -0
- package/dist/chunks/studio-5te5tqng.js +81 -0
- package/dist/chunks/{studio-p4ngc046.js → studio-6ewqv390.js} +9 -9
- package/dist/chunks/{studio-9ab8gqsm.js → studio-6nzaktvy.js} +7 -7
- package/dist/chunks/studio-6xa21ej9.js +28 -0
- package/dist/chunks/{studio-5ehhackm.js → studio-727xh0e3.js} +19 -19
- package/dist/chunks/{studio-eenfkt4e.js → studio-79y5sz51.js} +52 -38
- package/dist/chunks/{studio-4q0wznzf.js → studio-7e11jpa9.js} +461 -145
- package/dist/chunks/{studio-q7v10cg2.js → studio-7r42c6ca.js} +17 -7
- package/dist/chunks/studio-7xptrg0j.js +954 -0
- package/dist/chunks/{studio-cft9r4r7.js → studio-81390n6f.js} +22 -22
- package/dist/chunks/{studio-q43a5y9h.js → studio-8jn5yhyn.js} +16 -16
- package/dist/chunks/studio-8qtrpzr3.js +839 -0
- package/dist/chunks/{studio-dg7zyt5x.js → studio-98b3z07n.js} +1 -1
- package/dist/chunks/studio-9xxz1q69.js +1356 -0
- package/dist/chunks/studio-akbww0j5.js +13615 -0
- package/dist/chunks/studio-arfpe389.js +195 -0
- package/dist/chunks/{studio-2zkz8evn.js → studio-az3zd49t.js} +473 -281
- package/dist/chunks/studio-cpvb2ed1.js +1171 -0
- package/dist/chunks/{studio-9r6j5ev1.js → studio-d0300636.js} +5078 -19
- package/dist/chunks/{studio-bgxt93ga.js → studio-d055c37e.js} +13 -13
- package/dist/chunks/studio-d1ja2x9r.js +362 -0
- package/dist/chunks/{studio-b9b6t1dg.js → studio-e1f24eff.js} +5664 -5666
- package/dist/chunks/{studio-4pqqxbrt.js → studio-em9nw8eh.js} +301 -112
- package/dist/chunks/studio-erdatzvp.js +1190 -0
- package/dist/chunks/{studio-g1wdche0.js → studio-esrxgwh6.js} +80 -80
- package/dist/chunks/studio-fabxk6r9.js +2811 -0
- package/dist/chunks/{studio-3n4ndrzh.js → studio-h4nvnjvz.js} +303 -303
- package/dist/chunks/studio-hhvs4sdg.js +195 -0
- package/dist/chunks/{studio-68n67094.js → studio-kcgff4r0.js} +15 -18
- package/dist/chunks/{studio-685s0ytq.js → studio-nqgawfks.js} +572 -572
- package/dist/chunks/{studio-xrapxwwc.js → studio-p1dw8wfw.js} +55 -29
- package/dist/chunks/studio-pm6hgy7r.js +4763 -0
- package/dist/chunks/studio-q0a3yk4n.js +33 -0
- package/dist/chunks/{studio-wcy8trfx.js → studio-q3x06vmj.js} +23 -22
- package/dist/chunks/studio-qahxvnan.js +111 -0
- package/dist/chunks/{studio-53n8bp04.js → studio-r6xmmtfh.js} +1 -1
- package/dist/chunks/{studio-kjjsjak4.js → studio-rkstz940.js} +3661 -6136
- package/dist/chunks/{studio-tvgyw9xw.js → studio-rnyf3f8e.js} +83 -250
- package/dist/chunks/studio-rpyah2ew.js +2805 -0
- package/dist/chunks/studio-rs76k67r.js +12 -0
- package/dist/chunks/{studio-yxrkyv8a.js → studio-s6z853aq.js} +12108 -11766
- package/dist/chunks/{studio-sf7zjgv1.js → studio-sgdc5pfc.js} +8 -8
- package/dist/chunks/studio-tb3ev01j.js +763 -0
- package/dist/chunks/{studio-t5wqwzdh.js → studio-tjjk7jvk.js} +1 -1
- package/dist/chunks/studio-vhv5tgxm.js +51 -0
- package/dist/chunks/{studio-htsf0w6m.js → studio-vz68yn9e.js} +31 -154
- package/dist/chunks/studio-wqpngpsk.js +174 -0
- package/dist/chunks/{studio-eesa1myv.js → studio-x3rty6tr.js} +58 -58
- package/dist/chunks/studio-xsykpvsh.js +8448 -0
- package/dist/chunks/{studio-92ab2jqe.js → studio-y9zedyjn.js} +14 -14
- package/dist/chunks/studio-yxa81f45.js +12 -0
- package/dist/chunks/swatch-group-t0n6h2rn.js +139 -0
- package/dist/chunks/tabs-wbp1cdws.js +156 -0
- package/dist/chunks/textfield-abk6qyee.js +73 -0
- package/dist/chunks/toast-780pvfbv.js +27 -0
- package/dist/chunks/toast-host-3sqv46sn.js +116 -0
- package/dist/chunks/toolbar-xbh5bhtr.js +194 -0
- package/dist/chunks/tooltip-eptb614w.js +369 -0
- package/dist/chunks/tree-a73p0pqm.js +367 -0
- package/dist/chunks/{tsMode-76kr53q0.js → tsMode-jy4m86rv.js} +83 -85
- package/dist/chunks/workspace-wrew8zk4.js +69 -0
- package/dist/chunks/{ws-client-6shc5rze.js → ws-client-ny4zc51r.js} +20 -22
- package/dist/iframe-entry.js +1812 -698
- package/dist/manifest.json +7 -0
- package/dist/studio.js +52900 -36573
- package/dist/workers/editor.worker.js +1040 -1085
- package/dist/workers/json.worker.js +1946 -1991
- package/dist/workers/ts.worker.js +4960 -5005
- package/favicon.ico +0 -0
- package/index.html +2 -0
- package/package.json +22 -55
- package/src/about/about-modal.ts +73 -123
- package/src/browse/library-commands.ts +20 -49
- package/src/browse/library-layouts.ts +87 -218
- package/src/browse/library-pane.ts +406 -438
- package/src/canvas/canvas-helpers.ts +0 -49
- package/src/canvas/canvas-live-render.ts +25 -2
- package/src/canvas/canvas-render.ts +666 -231
- package/src/canvas/canvas-surface.ts +0 -1
- package/src/canvas/canvas-utils.ts +310 -117
- package/src/canvas/dialog-path.ts +76 -0
- package/src/canvas/dialog-state.ts +67 -0
- package/src/canvas/diff-marks.ts +252 -0
- package/src/canvas/diff-toolbar.ts +349 -0
- package/src/canvas/diff-view.ts +123 -0
- package/src/canvas/edit-width-drag.ts +187 -0
- package/src/canvas/edit-width.ts +150 -0
- package/src/canvas/iframe-entry.ts +125 -8
- package/src/canvas/iframe-host.ts +271 -15
- package/src/canvas/iframe-interaction.ts +133 -13
- package/src/canvas/iframe-patch.ts +7 -1
- package/src/canvas/iframe-position.ts +5 -6
- package/src/canvas/iframe-protocol.ts +106 -5
- package/src/canvas/iframe-render.ts +373 -5
- package/src/canvas/iframe-slash.ts +2 -2
- package/src/canvas/iframe-subtree.ts +5 -8
- package/src/canvas/path-mapping.ts +25 -3
- package/src/canvas/popover-path.ts +106 -0
- package/src/canvas/popover-state.ts +155 -0
- package/src/canvas/surface-registry.ts +21 -10
- package/src/collab/presence-chips.ts +51 -73
- package/src/commands/app-commands.ts +10 -0
- package/src/commands/budget.ts +12 -0
- package/src/commands/command-args.ts +369 -6
- package/src/commands/defaults.ts +44 -14
- package/src/commands/live-context.ts +11 -5
- package/src/commands/reference.ts +12 -2
- package/src/commands/registry.ts +165 -8
- package/src/content/entry-commands.ts +16 -23
- package/src/content/entry-editor.ts +144 -101
- package/src/editor/canvas-slash-bridge.ts +2 -2
- package/src/editor/context-menu.ts +49 -200
- package/src/editor/convert-to-component.ts +42 -82
- package/src/editor/convert-to-repeater.ts +132 -173
- package/src/editor/inline-edit.ts +11 -0
- package/src/editor/shortcuts.ts +65 -26
- package/src/editor/slash-menu.ts +150 -157
- package/src/files/file-ops.ts +117 -11
- package/src/files/files.ts +949 -664
- package/src/files/json-layout.ts +474 -0
- package/src/files/media-paths.ts +13 -42
- package/src/files/media-usage.ts +41 -131
- package/src/files/serialize-document.ts +8 -1
- package/src/format/convert-file.ts +16 -10
- package/src/format/format-host.ts +50 -1
- package/src/github/github-auth.ts +71 -29
- package/src/github/github-publish.ts +57 -65
- package/src/grid/cell-editors.ts +46 -4
- package/src/grid/cell-popovers.ts +65 -62
- package/src/grid/grid-open.ts +86 -64
- package/src/grid/grid-panel.ts +390 -469
- package/src/grid/redirects-grid.ts +40 -44
- package/src/hosting/document.ts +2 -0
- package/src/hosting/layout.ts +10 -0
- package/src/i18n/i18n-commands.ts +127 -62
- package/src/media/media-pane.ts +83 -133
- package/src/new-project/add-repo-modal.ts +125 -176
- package/src/new-project/import-tab.ts +201 -250
- package/src/new-project/location-fields.ts +101 -165
- package/src/new-project/new-project-modal.ts +376 -367
- package/src/packages/jxsuite-update.ts +76 -18
- package/src/panels/activity-panel.ts +137 -104
- package/src/panels/ai-chat/chat-markdown.ts +15 -13
- package/src/panels/ai-chat/chat-view.ts +307 -472
- package/src/panels/ai-chat/composer.ts +175 -153
- package/src/panels/ai-chat/sessions-view.ts +31 -62
- package/src/panels/ai-panel.ts +210 -185
- package/src/panels/block-action-bar.ts +437 -643
- package/src/panels/bottom-dock.ts +112 -47
- package/src/panels/chat-panel.ts +19 -14
- package/src/panels/data-explorer.ts +141 -102
- package/src/panels/data-grid.ts +183 -150
- package/src/panels/dnd.ts +75 -20
- package/src/panels/editors.ts +26 -19
- package/src/panels/elements-panel.ts +243 -186
- package/src/panels/empty-state.ts +26 -42
- package/src/panels/events-panel.ts +950 -729
- package/src/panels/formula-workspace.ts +434 -207
- package/src/panels/frontmatter-fields.ts +185 -153
- package/src/panels/frontmatter-panel.ts +411 -187
- package/src/panels/git-diff-open.ts +148 -0
- package/src/panels/git-panel.ts +679 -605
- package/src/panels/head-panel.ts +617 -435
- package/src/panels/i18n-panel.ts +153 -133
- package/src/panels/imports-panel.ts +388 -414
- package/src/panels/jump-bar.ts +174 -147
- package/src/panels/layers-panel.ts +785 -671
- package/src/panels/left-panel.ts +166 -94
- package/src/panels/navigator-panels.ts +1 -1
- package/src/panels/pane-context.ts +529 -677
- package/src/panels/pane-grid.ts +265 -241
- package/src/panels/panel-registry.ts +15 -4
- package/src/panels/problems-panel.ts +177 -99
- package/src/panels/properties-panel.ts +1525 -966
- package/src/panels/provenance.ts +31 -113
- package/src/panels/quick-search.ts +217 -172
- package/src/panels/right-panel.ts +135 -169
- package/src/panels/seo-modal.ts +346 -167
- package/src/panels/settings-menu.ts +109 -646
- package/src/panels/settings-pane.ts +102 -86
- package/src/panels/signals-panel.ts +1318 -1172
- package/src/panels/statement-editor.ts +556 -428
- package/src/panels/style-panel.ts +1367 -630
- package/src/panels/style-utils.ts +36 -32
- package/src/panels/stylebook-doc.ts +30 -73
- package/src/panels/stylebook-layers-panel.ts +202 -109
- package/src/panels/stylebook-panel.ts +124 -88
- package/src/panels/tab-strip.ts +385 -287
- package/src/platforms/cloud.ts +347 -86
- package/src/platforms/devserver.ts +13 -0
- package/src/publish/deploy-checklist.ts +124 -78
- package/src/publish/publish-commands.ts +4 -12
- package/src/publish/publish-panel.ts +165 -299
- package/src/services/a11y-report.ts +100 -43
- package/src/services/ai-command-tools.ts +468 -0
- package/src/services/ai-import-tools.ts +50 -12
- package/src/services/ai-models.ts +108 -1
- package/src/services/ai-session-store.ts +6 -0
- package/src/services/ai-system-prompt.ts +110 -18
- package/src/services/ai-tools.ts +28 -143
- package/src/services/ai-write-report.ts +174 -0
- package/src/services/context-manager.ts +12 -1
- package/src/services/document-assistant.ts +50 -2
- package/src/services/idle.ts +16 -14
- package/src/services/live-surfaces.ts +237 -0
- package/src/services/model-uri.ts +75 -0
- package/src/services/notify.ts +63 -6
- package/src/services/popover-report.ts +325 -0
- package/src/services/surface-registry.ts +56 -0
- package/src/services/tool-executor.ts +17 -0
- package/src/settings/contexts-section.ts +301 -299
- package/src/settings/contributed-section.ts +361 -222
- package/src/settings/css-vars-editor.ts +320 -325
- package/src/settings/defs-editor.ts +572 -535
- package/src/settings/dependencies-editor.ts +79 -107
- package/src/settings/extension-commands.ts +379 -0
- package/src/settings/extension-rows.ts +113 -0
- package/src/settings/extensions-section.ts +287 -0
- package/src/settings/general-settings.ts +130 -181
- package/src/settings/head-editor.ts +10 -305
- package/src/settings/locales-section.ts +146 -196
- package/src/settings/preferences-accounts.ts +193 -12
- package/src/settings/preferences-dialog.ts +384 -307
- package/src/settings/project-sections.ts +108 -181
- package/src/settings/schema-field-ui.ts +11 -399
- package/src/settings/section-registry.ts +8 -1
- package/src/settings/settings-document.ts +31 -29
- package/src/shell/tree.ts +42 -87
- package/src/shell.ts +48 -36
- package/src/studio.ts +90 -67
- package/src/style/token-ref.ts +0 -39
- package/src/surfaces/about.json +263 -0
- package/src/surfaces/about.ts +163 -0
- package/src/surfaces/add-repo.json +486 -0
- package/src/surfaces/add-repo.ts +236 -0
- package/src/surfaces/ai-chat.json +2185 -0
- package/src/surfaces/ai-chat.ts +549 -0
- package/src/surfaces/ai-credentials-form.json +332 -0
- package/src/surfaces/ai-credentials-form.ts +151 -0
- package/src/surfaces/ai-managed-connect.json +108 -0
- package/src/surfaces/ai-managed-connect.ts +123 -0
- package/src/surfaces/ai-model-picker.json +114 -0
- package/src/surfaces/ai-model-picker.ts +139 -0
- package/src/surfaces/block-action-bar.json +640 -0
- package/src/surfaces/block-action-bar.ts +368 -0
- package/src/surfaces/bottom-dock.json +154 -0
- package/src/surfaces/bottom-dock.ts +125 -0
- package/src/surfaces/canvas-stage.json +444 -0
- package/src/surfaces/canvas-stage.ts +253 -0
- package/src/surfaces/cf-account-picker.json +300 -0
- package/src/surfaces/cf-account-picker.ts +214 -0
- package/src/surfaces/commandbar.json +984 -0
- package/src/{panels/toolbar.ts → surfaces/commandbar.ts} +414 -389
- package/src/surfaces/convert-repeater.json +309 -0
- package/src/surfaces/convert-repeater.ts +276 -0
- package/src/surfaces/data-actions.json +157 -0
- package/src/surfaces/data-actions.ts +115 -0
- package/src/surfaces/dialog.json +289 -0
- package/src/surfaces/dialog.ts +343 -0
- package/src/surfaces/diff-toolbar.json +266 -0
- package/src/surfaces/diff-toolbar.ts +139 -0
- package/src/surfaces/doc-header.json +739 -0
- package/src/surfaces/doc-header.ts +223 -0
- package/src/surfaces/empty-state.json +152 -0
- package/src/surfaces/empty-state.ts +173 -0
- package/src/surfaces/entry-editor.json +281 -0
- package/src/surfaces/entry-editor.ts +191 -0
- package/src/surfaces/expression-editor.json +977 -0
- package/src/surfaces/expression-editor.ts +266 -0
- package/src/surfaces/files-panel.json +592 -0
- package/src/surfaces/files-panel.ts +301 -0
- package/src/surfaces/formula-palette.json +364 -0
- package/src/surfaces/formula-palette.ts +340 -0
- package/src/surfaces/git-panel.json +1822 -0
- package/src/surfaces/git-panel.ts +272 -0
- package/src/surfaces/github-auth.json +112 -0
- package/src/surfaces/github-auth.ts +139 -0
- package/src/surfaces/github-publish.json +206 -0
- package/src/surfaces/github-publish.ts +169 -0
- package/src/surfaces/grid-cell.json +218 -0
- package/src/surfaces/grid-cell.ts +120 -0
- package/src/surfaces/grid-open.json +147 -0
- package/src/surfaces/grid-open.ts +87 -0
- package/src/surfaces/grid-panel.json +706 -0
- package/src/surfaces/grid-panel.ts +206 -0
- package/src/surfaces/grid-replace.json +179 -0
- package/src/surfaces/grid-replace.ts +89 -0
- package/src/surfaces/grid-views.json +446 -0
- package/src/surfaces/grid-views.ts +172 -0
- package/src/surfaces/inspector-dock.json +187 -0
- package/src/surfaces/inspector-dock.ts +161 -0
- package/src/surfaces/jump-bar.json +243 -0
- package/src/surfaces/jump-bar.ts +129 -0
- package/src/surfaces/jxsuite-update.json +146 -0
- package/src/surfaces/jxsuite-update.ts +149 -0
- package/src/surfaces/library-pane.json +1509 -0
- package/src/surfaces/library-pane.ts +363 -0
- package/src/surfaces/logic-panel.json +1949 -0
- package/src/surfaces/logic-panel.ts +369 -0
- package/src/surfaces/logic-workspace.json +685 -0
- package/src/surfaces/logic-workspace.ts +238 -0
- package/src/surfaces/media-browser.json +303 -0
- package/src/surfaces/media-browser.ts +145 -0
- package/src/surfaces/media-field.json +163 -0
- package/src/surfaces/media-field.ts +116 -0
- package/src/surfaces/media-pane.json +513 -0
- package/src/surfaces/media-pane.ts +197 -0
- package/src/surfaces/menu.json +232 -0
- package/src/surfaces/menu.ts +375 -0
- package/src/surfaces/navigator-dock.json +113 -0
- package/src/surfaces/navigator-dock.ts +130 -0
- package/src/surfaces/new-project.json +1654 -0
- package/src/surfaces/new-project.ts +411 -0
- package/src/surfaces/palette.json +535 -0
- package/src/surfaces/pane-context.json +1497 -0
- package/src/surfaces/pane-context.ts +513 -0
- package/src/surfaces/pane-grid.json +188 -0
- package/src/surfaces/pane-grid.ts +250 -0
- package/src/surfaces/panel-activity.json +563 -0
- package/src/surfaces/panel-activity.ts +187 -0
- package/src/surfaces/panel-data.json +141 -0
- package/src/surfaces/panel-data.ts +156 -0
- package/src/surfaces/panel-deploy-checklist.json +283 -0
- package/src/surfaces/panel-deploy-checklist.ts +175 -0
- package/src/surfaces/panel-elements.json +367 -0
- package/src/surfaces/panel-elements.ts +175 -0
- package/src/surfaces/panel-i18n.json +569 -0
- package/src/surfaces/panel-i18n.ts +212 -0
- package/src/surfaces/panel-imports.json +780 -0
- package/src/surfaces/panel-imports.ts +209 -0
- package/src/surfaces/panel-outline.json +734 -0
- package/src/surfaces/panel-outline.ts +326 -0
- package/src/surfaces/panel-page.json +1017 -0
- package/src/surfaces/panel-page.ts +240 -0
- package/src/surfaces/panel-problems.json +497 -0
- package/src/surfaces/panel-problems.ts +157 -0
- package/src/surfaces/panel-signals.json +1973 -0
- package/src/surfaces/panel-signals.ts +436 -0
- package/src/surfaces/panel-stylebook-layers.json +317 -0
- package/src/surfaces/panel-stylebook-layers.ts +155 -0
- package/src/surfaces/preferences.json +850 -0
- package/src/surfaces/preferences.ts +332 -0
- package/src/surfaces/progress-modal.json +110 -0
- package/src/surfaces/progress-modal.ts +150 -0
- package/src/surfaces/properties-panel.json +1578 -0
- package/src/surfaces/properties-panel.ts +337 -0
- package/src/surfaces/publish.json +945 -0
- package/src/surfaces/publish.ts +392 -0
- package/src/surfaces/push-plan.json +110 -0
- package/src/surfaces/push-plan.ts +87 -0
- package/src/surfaces/rail.json +255 -0
- package/src/surfaces/rail.ts +206 -0
- package/src/surfaces/reference-field.json +191 -0
- package/src/surfaces/reference-field.ts +168 -0
- package/src/surfaces/schema-builder.json +1011 -0
- package/src/surfaces/schema-builder.ts +181 -0
- package/src/surfaces/schema-form.json +1013 -0
- package/src/surfaces/schema-form.ts +287 -0
- package/src/surfaces/secret-field.json +60 -0
- package/src/surfaces/secret-field.ts +146 -0
- package/src/surfaces/seo.json +932 -0
- package/src/surfaces/seo.ts +334 -0
- package/src/surfaces/settings-contexts.json +538 -0
- package/src/surfaces/settings-contexts.ts +196 -0
- package/src/surfaces/settings-contributed.json +489 -0
- package/src/surfaces/settings-contributed.ts +199 -0
- package/src/surfaces/settings-css-vars.json +820 -0
- package/src/surfaces/settings-css-vars.ts +199 -0
- package/src/surfaces/settings-defs.json +1363 -0
- package/src/surfaces/settings-defs.ts +232 -0
- package/src/surfaces/settings-deploy.json +108 -0
- package/src/surfaces/settings-deploy.ts +135 -0
- package/src/surfaces/settings-extensions.json +486 -0
- package/src/surfaces/settings-extensions.ts +201 -0
- package/src/surfaces/settings-head.json +779 -0
- package/src/surfaces/settings-head.ts +397 -0
- package/src/surfaces/settings-locales.json +420 -0
- package/src/surfaces/settings-locales.ts +137 -0
- package/src/surfaces/settings-overview.json +423 -0
- package/src/surfaces/settings-overview.ts +218 -0
- package/src/surfaces/settings-packages.json +549 -0
- package/src/surfaces/settings-packages.ts +158 -0
- package/src/surfaces/settings-pane.json +147 -0
- package/src/surfaces/settings-pane.ts +150 -0
- package/src/surfaces/settings-rawjson.json +104 -0
- package/src/surfaces/settings-rawjson.ts +107 -0
- package/src/surfaces/shell.json +99 -0
- package/src/surfaces/shell.ts +30 -0
- package/src/surfaces/slash-menu.json +180 -0
- package/src/surfaces/slash-menu.ts +272 -0
- package/src/surfaces/statements.json +607 -0
- package/src/surfaces/statements.ts +238 -0
- package/src/surfaces/statusbar.json +94 -0
- package/src/{panels → surfaces}/statusbar.ts +163 -90
- package/src/surfaces/style-panel.json +1643 -0
- package/src/surfaces/style-panel.ts +338 -0
- package/src/surfaces/stylebook-chrome.json +122 -0
- package/src/surfaces/stylebook-chrome.ts +122 -0
- package/src/surfaces/tab-strip.json +448 -0
- package/src/surfaces/tab-strip.ts +200 -0
- package/src/surfaces/target-line.json +419 -0
- package/src/surfaces/target-line.ts +349 -0
- package/src/surfaces/toasts.json +189 -0
- package/src/surfaces/welcome.json +571 -0
- package/src/surfaces/welcome.ts +338 -0
- package/src/tabs/project-config.ts +71 -15
- package/src/tabs/tab.ts +52 -1
- package/src/types.ts +49 -3
- package/src/ui/ai-credentials-form.ts +104 -100
- package/src/ui/ai-managed-connect.ts +116 -49
- package/src/ui/ai-model-picker.ts +102 -47
- package/src/ui/cf-account-picker.ts +135 -0
- package/src/ui/color-selector.ts +80 -301
- package/src/ui/dynamic-slot.ts +43 -283
- package/src/ui/expression-editor.ts +797 -576
- package/src/ui/field-input.ts +8 -181
- package/src/ui/form-controls.ts +838 -366
- package/src/ui/formula-chips.ts +80 -85
- package/src/ui/kit.ts +33 -0
- package/src/ui/layers.ts +293 -593
- package/src/ui/media-picker.ts +203 -284
- package/src/ui/panel-resize.ts +251 -64
- package/src/ui/popover-surface.ts +153 -0
- package/src/ui/progress-modal.ts +22 -60
- package/src/ui/regions.ts +13 -7
- package/src/ui/schema-form.ts +906 -440
- package/src/ui/surface.ts +122 -0
- package/src/ui/unit-selector.ts +15 -131
- package/src/ui/value-source.ts +14 -0
- package/src/ui/virtual-window.ts +88 -9
- package/src/utils/canvas-media.ts +72 -0
- package/src/utils/edit-display.ts +7 -2
- package/src/utils/element-selectors.ts +69 -0
- package/src/utils/link-target.ts +2 -2
- package/src/utils/studio-utils.ts +0 -10
- package/src/view.ts +15 -0
- package/src/workspace/pane-derive.ts +36 -14
- package/src/workspace/workspace.ts +15 -6
- package/styles/canvas.css +72 -467
- package/styles/forced-colors.css +48 -82
- package/styles/forced-colors.json +41 -0
- package/styles/inspector.css +2 -1301
- package/styles/overlays.css +96 -2823
- package/styles/panels.css +6 -1423
- package/styles/shell-frame.css +272 -0
- package/styles/shell-frame.json +227 -0
- package/styles/shell.css +0 -1532
- package/styles/tokens.css +65 -136
- package/styles/tokens.json +84 -0
- package/dist/chunks/Overlay.dev-723bv0df.js +0 -23
- package/dist/chunks/adapter-jkcyhgtr.js +0 -14
- package/dist/chunks/cf-settings-45fgyx8y.js +0 -21
- package/dist/chunks/components-zmx10t62.js +0 -21
- package/dist/chunks/content-source-t88vb2dr.js +0 -49
- package/dist/chunks/convert-to-repeater-dhw1nrz9.js +0 -268
- package/dist/chunks/editor-cptq5jp1.js +0 -37
- package/dist/chunks/entry-commands-6z6bhxg0.js +0 -46
- package/dist/chunks/extension-sections-3ydgjbdy.js +0 -311
- package/dist/chunks/file-ops-rskmhxyq.js +0 -48
- package/dist/chunks/files-0cratsr0.js +0 -92
- package/dist/chunks/flow-qbfgrpeh.js +0 -634
- package/dist/chunks/focus-trap.esm-ggawf1hy.js +0 -1024
- package/dist/chunks/focus-visible-6eg70z18.js +0 -167
- package/dist/chunks/format-host-tgcmfs4p.js +0 -43
- package/dist/chunks/fs-events-hrrg328g.js +0 -21
- package/dist/chunks/git-panel-0yywyk76.js +0 -58
- package/dist/chunks/index-zqxmqxmh.js +0 -109
- package/dist/chunks/jx-validate-8q2g05x1.js +0 -19
- package/dist/chunks/layers-panel-z3tqe5cd.js +0 -67
- package/dist/chunks/layers-q75tj2mf.js +0 -45
- package/dist/chunks/lit-html-j055mkh8.js +0 -22
- package/dist/chunks/monaco-buffer-dqw0xxpx.js +0 -25
- package/dist/chunks/notify-yjm79n4s.js +0 -30
- package/dist/chunks/parse-24d0gay3.js +0 -19
- package/dist/chunks/platform-ba1j1gbh.js +0 -16
- package/dist/chunks/publish-panel-54jvhskq.js +0 -28
- package/dist/chunks/quick-search-cgfmjwq5.js +0 -65
- package/dist/chunks/references-3qx8fkyp.js +0 -29
- package/dist/chunks/right-panel-cqp8bc4v.js +0 -46
- package/dist/chunks/section-registry-sx1ykvkw.js +0 -30
- package/dist/chunks/sp-overlay.dev-yztmtrs1.js +0 -18
- package/dist/chunks/sp-popover.dev-n2etmqdp.js +0 -9
- package/dist/chunks/sp-progress-circle.dev-hryhj0es.js +0 -15
- package/dist/chunks/sp-tooltip.dev-xcvpnqr0.js +0 -15
- package/dist/chunks/sp-tray.dev-tkbscm06.js +0 -199
- package/dist/chunks/studio-0a5qrh01.js +0 -3
- package/dist/chunks/studio-18j3bmcz.js +0 -14
- package/dist/chunks/studio-1hbqnt19.js +0 -1823
- package/dist/chunks/studio-4rzyrtjz.js +0 -426
- package/dist/chunks/studio-5rywrkxz.js +0 -1903
- package/dist/chunks/studio-7afd21nw.js +0 -67
- package/dist/chunks/studio-7nte2hj4.js +0 -613
- package/dist/chunks/studio-8jpzqk5s.js +0 -128
- package/dist/chunks/studio-8q517dfr.js +0 -24
- package/dist/chunks/studio-9c4k4vhv.js +0 -357
- package/dist/chunks/studio-9n4mrmnb.js +0 -184
- package/dist/chunks/studio-a0tswy0w.js +0 -58
- package/dist/chunks/studio-ahjfdy6e.js +0 -387
- package/dist/chunks/studio-ahnzd9rg.js +0 -23
- package/dist/chunks/studio-bw5dz6km.js +0 -608
- package/dist/chunks/studio-cb12yz9w.js +0 -15055
- package/dist/chunks/studio-d1ks410h.js +0 -175
- package/dist/chunks/studio-eqq1w638.js +0 -113
- package/dist/chunks/studio-ex8zyp98.js +0 -1813
- package/dist/chunks/studio-h4rxscfc.js +0 -10
- package/dist/chunks/studio-kyh9avvv.js +0 -28
- package/dist/chunks/studio-kyk2v92a.js +0 -659
- package/dist/chunks/studio-m3hwn7y1.js +0 -120
- package/dist/chunks/studio-mmv72a27.js +0 -4344
- package/dist/chunks/studio-n8b9wqwy.js +0 -291
- package/dist/chunks/studio-pdfjntbk.js +0 -6939
- package/dist/chunks/studio-qq6jym04.js +0 -53
- package/dist/chunks/studio-r1r7afxx.js +0 -1066
- package/dist/chunks/studio-rdx8jcxy.js +0 -83
- package/dist/chunks/studio-rn9ta2mz.js +0 -111
- package/dist/chunks/studio-t7qb9db8.js +0 -665
- package/dist/chunks/studio-tmc5emrw.js +0 -8
- package/dist/chunks/studio-txwkm6p9.js +0 -12
- package/dist/chunks/studio-v38hmvx1.js +0 -390
- package/dist/chunks/studio-vadzgkrz.js +0 -318
- package/dist/chunks/studio-wx5609xd.js +0 -341
- package/dist/chunks/studio-z6nw2ek2.js +0 -18
- package/dist/chunks/studio-zczps70q.js +0 -378
- package/dist/chunks/workspace-xpres40v.js +0 -89
- package/src/panels/activity-bar.ts +0 -251
- package/src/panels/panel-scheduler.ts +0 -219
- package/src/panels/style-inputs.ts +0 -237
- package/src/panels/target-line.ts +0 -274
- package/src/panels/welcome-screen.ts +0 -346
- package/src/ui/button-group.ts +0 -102
- package/src/ui/choice-field.ts +0 -72
- package/src/ui/field-row.ts +0 -249
- package/src/ui/formula-palette.ts +0 -213
- package/src/ui/icons.ts +0 -52
- package/src/ui/jx-theme.ts +0 -130
- package/src/ui/spectrum.ts +0 -340
- package/src/ui/value-selector.ts +0 -174
- package/src/ui/widgets.ts +0 -172
- /package/dist/chunks/{javascript-s56a8dpk.css → javascript-4abzjcy9.css} +0 -0
- /package/dist/chunks/{jsonMode-zr9sw0c7.css → jsonMode-vvmpmk34.css} +0 -0
- /package/dist/chunks/{monaco-setup-pav68602.css → monaco-setup-8vbyqnhr.css} +0 -0
- /package/dist/chunks/{tsMode-ef187txx.css → tsMode-hnxxb73h.css} +0 -0
|
@@ -6,8 +6,11 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { postMessageChannel } from "./iframe-channel";
|
|
9
|
+
import { rectOf } from "../utils/geometry";
|
|
9
10
|
import { displayTagName } from "@jxsuite/schema/guards";
|
|
10
11
|
import {
|
|
12
|
+
applyCanvasDialogOpen,
|
|
13
|
+
applyCanvasPopoverOpen,
|
|
11
14
|
applyPreviewColorScheme,
|
|
12
15
|
applySiteStyle,
|
|
13
16
|
installCanvasImageRetry,
|
|
@@ -44,7 +47,15 @@ import type { JxPath } from "../state";
|
|
|
44
47
|
// ObserveScope MUST come from the runtime: the $defs refs are created by the runtime's copy of
|
|
45
48
|
// @vue/reactivity, and dep tracking is per module instance — an effect from the studio's own copy
|
|
46
49
|
// Would never re-run when a dev-proxy data source settles.
|
|
47
|
-
import {
|
|
50
|
+
import {
|
|
51
|
+
observeScope,
|
|
52
|
+
preloadModule,
|
|
53
|
+
reapplyStyle,
|
|
54
|
+
redefineElement,
|
|
55
|
+
resetDocumentStyles,
|
|
56
|
+
setResolveToken,
|
|
57
|
+
} from "@jxsuite/runtime";
|
|
58
|
+
import { KIT_LOADERS } from "@jxsuite/ui/loaders";
|
|
48
59
|
import type { IframeChannel } from "./iframe-channel";
|
|
49
60
|
import type {
|
|
50
61
|
CanvasMode,
|
|
@@ -62,6 +73,21 @@ import { setBundleBase } from "../services/bundle-base";
|
|
|
62
73
|
entry may, and tests/entry-anchors.test.ts for the guard. */
|
|
63
74
|
setBundleBase(import.meta.url);
|
|
64
75
|
|
|
76
|
+
/*
|
|
77
|
+
* The kit's behaviours, as LOADERS. A project on the canvas may use a kit element — the kit's own
|
|
78
|
+
* stylebook pages do, and any site that imports one will — and the element's document names its
|
|
79
|
+
* sidecar by `jx-ui:` specifier, which is a scheme nothing serves. The shell answers it by
|
|
80
|
+
* importing every behaviour at boot (`registerUi()`); this frame answers it lazily, one chunk per
|
|
81
|
+
* behaviour on first use, so a page that draws no kit element loads none of them and a page that
|
|
82
|
+
* draws one loads only its own. Registered before anything renders, because the first document
|
|
83
|
+
* may be the one that needs it. The ELEMENTS are not registered here on purpose: the frame draws
|
|
84
|
+
* a project's definitions from the project's files, which is what makes an edit to a kit
|
|
85
|
+
* component show on the canvas rather than the bundled copy (embedding.md §6, ui.md §10).
|
|
86
|
+
*/
|
|
87
|
+
for (const [specifier, load] of Object.entries(KIT_LOADERS)) {
|
|
88
|
+
preloadModule(specifier, load);
|
|
89
|
+
}
|
|
90
|
+
|
|
65
91
|
/**
|
|
66
92
|
* Resolve the drop placement for a forwarded cursor: point hit-test → nearest `[data-jx-path]` →
|
|
67
93
|
* pure {@link computeDropInstruction}. Returns null when the cursor resolves to no droppable target.
|
|
@@ -227,6 +253,15 @@ export function startCanvasIframe(opts: {
|
|
|
227
253
|
// The mode of the LIVE render — gates the interactive surfaces (inline editing, insert zones,
|
|
228
254
|
// Grab-drags) that only design/edit modes own. Adopted alongside shadowDoc.
|
|
229
255
|
let currentMode: CanvasMode = "design";
|
|
256
|
+
/**
|
|
257
|
+
* The popover the artboard is drawing open, as a serialized path, or null.
|
|
258
|
+
*
|
|
259
|
+
* Kept here rather than read back off the DOM because it has to survive a patch: an `attributes`
|
|
260
|
+
* op routes through `replaceSubtree`, which rebuilds the element and takes the attribute with it,
|
|
261
|
+
* and the frame must be able to put it back without a round trip to the host.
|
|
262
|
+
*/
|
|
263
|
+
let popoverOpen: string | null = null;
|
|
264
|
+
let dialogOpen: string | null = null;
|
|
230
265
|
/* The host's chord table. Empty until the first `keymap` message, which the host posts on
|
|
231
266
|
`ready` — before any render, so there is nothing to type into during the gap. An empty table
|
|
232
267
|
forwards nothing, which is the honest cold-start answer: the frame does not guess at what the
|
|
@@ -376,7 +411,7 @@ export function startCanvasIframe(opts: {
|
|
|
376
411
|
getMode: () => currentMode,
|
|
377
412
|
getShadowDoc: () => shadowDoc,
|
|
378
413
|
});
|
|
379
|
-
// Bridge the engine's slash menu to the parent's
|
|
414
|
+
// Bridge the engine's slash menu to the parent's own menu (show/nav/select over the channel).
|
|
380
415
|
const stopSlashBridge = startIframeSlashBridge(channel, container.ownerDocument);
|
|
381
416
|
// Auto-recover canvas images that 404 on a cold first render (component <img>s created in
|
|
382
417
|
// ConnectedCallback fire late, before the loopback server is warm). Re-fires the failed request a
|
|
@@ -392,8 +427,30 @@ export function startCanvasIframe(opts: {
|
|
|
392
427
|
// The true content height.
|
|
393
428
|
const MAX_CANVAS_HEIGHT = 30_000;
|
|
394
429
|
let lastPostedHeight = -1;
|
|
430
|
+
/**
|
|
431
|
+
* The bottom edge of the open popover, relative to the container, or 0 when none is open.
|
|
432
|
+
*
|
|
433
|
+
* A popover is positioned, so it contributes nothing to `scrollHeight` and moves no ancestor box
|
|
434
|
+
* — which is why the `ResizeObserver` below never fires for one. It cannot feed back into an
|
|
435
|
+
* ever-growing height either: it is contained by the canvas's FIXED-SIZE query container, so
|
|
436
|
+
* growing the frame does not move it.
|
|
437
|
+
*/
|
|
438
|
+
function openPopoverBottom(): number {
|
|
439
|
+
// Both overlay kinds: a dialog shown in place is positioned by the same forced rule.
|
|
440
|
+
const panels = container.querySelectorAll(
|
|
441
|
+
"[data-jx-popover][data-jx-popover-open], dialog[data-jx-dialog-open]",
|
|
442
|
+
);
|
|
443
|
+
const root = rectOf(container);
|
|
444
|
+
let bottom = 0;
|
|
445
|
+
for (const panel of panels) {
|
|
446
|
+
bottom = Math.max(bottom, rectOf(panel).bottom - root.top);
|
|
447
|
+
}
|
|
448
|
+
return bottom;
|
|
449
|
+
}
|
|
450
|
+
|
|
395
451
|
function postContentHeight(): void {
|
|
396
|
-
const
|
|
452
|
+
const content = Math.max(container.scrollHeight, openPopoverBottom());
|
|
453
|
+
const measured = Math.min(content, MAX_CANVAS_HEIGHT);
|
|
397
454
|
if (measured > 0 && Math.abs(measured - lastPostedHeight) >= 1) {
|
|
398
455
|
lastPostedHeight = measured;
|
|
399
456
|
// A component-definition root (marked by makeStamper) is a fragment, not a page — tell the host
|
|
@@ -466,6 +523,16 @@ export function startCanvasIframe(opts: {
|
|
|
466
523
|
quietFrames = quiet ? (changed ? 1 : quietFrames + 1) : 0;
|
|
467
524
|
// Two consecutive quiet frames, then stop — the state is stable and any change re-arms us.
|
|
468
525
|
if (quietFrames >= IDLE_QUIET_FRAMES) {
|
|
526
|
+
/* Measure once more now that the box has stopped moving. A CSS TRANSITION changes the content
|
|
527
|
+
height over time, and the two observers that normally catch that both miss the end of one:
|
|
528
|
+
`postContentHeight` fires at the START (from whatever changed the DOM) and reads a height
|
|
529
|
+
the transition has not reached, and the ResizeObserver stops firing once the box settles —
|
|
530
|
+
so the last value posted is a mid-flight one. A closing popover left a 141px component in a
|
|
531
|
+
480px frame exactly this way.
|
|
532
|
+
|
|
533
|
+
Deduped by `lastPostedHeight`, so the common case posts nothing, and it terminates: this
|
|
534
|
+
post arms the watcher, the next settle measures the same height, and nothing is posted. */
|
|
535
|
+
postContentHeight();
|
|
469
536
|
return;
|
|
470
537
|
}
|
|
471
538
|
// A page with a genuinely endless animation never goes quiet. Give up rather than burn a rAF
|
|
@@ -648,11 +715,8 @@ export function startCanvasIframe(opts: {
|
|
|
648
715
|
|
|
649
716
|
const off = channel.onMessage((msg) => {
|
|
650
717
|
if (msg.kind === "measure") {
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
kind: "geometry",
|
|
654
|
-
reqId: msg.reqId,
|
|
655
|
-
});
|
|
718
|
+
const { hidden, hits } = measureHits(msg.paths, container.ownerDocument);
|
|
719
|
+
channel.post({ hidden, hits, kind: "geometry", reqId: msg.reqId });
|
|
656
720
|
return;
|
|
657
721
|
}
|
|
658
722
|
if (msg.kind === "evalExpr") {
|
|
@@ -717,6 +781,11 @@ export function startCanvasIframe(opts: {
|
|
|
717
781
|
}
|
|
718
782
|
try {
|
|
719
783
|
applyIframePatch(shadowDoc, msg.forwardOps, container, renderCtx, msg.echoPaths);
|
|
784
|
+
/* An `attributes` op routes through `replaceSubtree`, which rebuilds the element and takes
|
|
785
|
+
`data-jx-popover-open` with it — so a style edit on the open panel would close it under
|
|
786
|
+
the author's hands. Idempotent, so paying for it on every patch is a no-op. */
|
|
787
|
+
applyCanvasPopoverOpen(container, popoverOpen);
|
|
788
|
+
applyCanvasDialogOpen(container, dialogOpen);
|
|
720
789
|
// Put the caret back where the author left it. Restoring the SELECTION re-activates the
|
|
721
790
|
// Block through the editing host's own selectionchange path — there is no separate
|
|
722
791
|
// "re-enter" step, because a caret in a block IS the edit.
|
|
@@ -811,6 +880,38 @@ export function startCanvasIframe(opts: {
|
|
|
811
880
|
applyPreviewColorScheme(container.ownerDocument, msg.scheme);
|
|
812
881
|
return;
|
|
813
882
|
}
|
|
883
|
+
if (msg.kind === "setPopoverOpen") {
|
|
884
|
+
/* Refused in preview HERE as well as in the host. Preview renders popovers natively and the
|
|
885
|
+
canvas attribute does not exist there, so a stray message would silently do nothing —
|
|
886
|
+
better to refuse it in both realms, which is the discipline §4.2 states for every editing
|
|
887
|
+
affordance: neither side may assume the other's build is current. */
|
|
888
|
+
if (currentMode === "preview") {
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
popoverOpen = msg.path === null ? null : serializeJxPath(msg.path);
|
|
892
|
+
applyCanvasPopoverOpen(container, popoverOpen);
|
|
893
|
+
applyCanvasDialogOpen(container, dialogOpen);
|
|
894
|
+
// The panel entering or leaving flow changes the content box, and the ResizeObserver only
|
|
895
|
+
// Sees `#jx-canvas-root` — an absolutely positioned panel does not move it.
|
|
896
|
+
postContentHeight();
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
if (msg.kind === "setDialogOpen") {
|
|
900
|
+
// The dialog twin, refused in preview for the reason given above.
|
|
901
|
+
if (currentMode === "preview") {
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
dialogOpen = msg.path === null ? null : serializeJxPath(msg.path);
|
|
905
|
+
applyCanvasDialogOpen(container, dialogOpen);
|
|
906
|
+
postContentHeight();
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
909
|
+
if (msg.kind === "redefineElement") {
|
|
910
|
+
/* The canvas half of embedding.md §7. The definition is replaced in THIS realm; instances
|
|
911
|
+
already on the canvas keep the old one until the host's next render replaces them. */
|
|
912
|
+
void redefineElement(msg.doc as never, msg.base);
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
814
915
|
if (msg.kind === "setLocale") {
|
|
815
916
|
/* The other document-level attribute flip, and the whole visible half of an axis-3 locale:
|
|
816
917
|
`dir` is what makes an RTL preview actually mirror, and `lang` is what CSS's `:lang()` and
|
|
@@ -858,6 +959,12 @@ export function startCanvasIframe(opts: {
|
|
|
858
959
|
stopDataScopeWatch?.();
|
|
859
960
|
stopDataScopeWatch = null;
|
|
860
961
|
handle?.dispose();
|
|
962
|
+
/* And its stylesheets. Scope teardown releases each element's rules on its own, so this is
|
|
963
|
+
belt to that braces — but a full re-render replaces every element in the frame, and the
|
|
964
|
+
canvas is the one place where "the sheet only ever grows" would be a live leak rather
|
|
965
|
+
than a theoretical one. It used to be exactly that, one orphaned `<style>` per styled
|
|
966
|
+
element per render. */
|
|
967
|
+
resetDocumentStyles(container.ownerDocument);
|
|
861
968
|
handle = await renderResolvedDocument({
|
|
862
969
|
assets: msg.assets ?? null,
|
|
863
970
|
container,
|
|
@@ -870,11 +977,21 @@ export function startCanvasIframe(opts: {
|
|
|
870
977
|
pageContentOffset: mapperCtx.pageContentOffset,
|
|
871
978
|
pageContentPrefix: mapperCtx.pageContentPrefix,
|
|
872
979
|
},
|
|
980
|
+
diffMarks: msg.diffMarks ?? null,
|
|
873
981
|
mode: msg.mode,
|
|
982
|
+
popoverOpen: msg.popoverOpen ? serializeJxPath(msg.popoverOpen) : null,
|
|
983
|
+
dialogOpen: msg.dialogOpen ? serializeJxPath(msg.dialogOpen) : null,
|
|
874
984
|
siteStyle: msg.siteStyle,
|
|
875
985
|
...(msg.allowAutoRequests ? { allowAutoRequests: true } : {}),
|
|
876
986
|
});
|
|
877
987
|
if (gen === latestGen) {
|
|
988
|
+
/* A render replaces the DOM, so the open attribute goes with it. The host sends the value
|
|
989
|
+
on the render message for exactly this reason; a frame that kept only its own copy
|
|
990
|
+
would reopen the wrong panel after a tab switch. */
|
|
991
|
+
popoverOpen = msg.popoverOpen ? serializeJxPath(msg.popoverOpen) : null;
|
|
992
|
+
dialogOpen = msg.dialogOpen ? serializeJxPath(msg.dialogOpen) : null;
|
|
993
|
+
applyCanvasPopoverOpen(container, popoverOpen);
|
|
994
|
+
applyCanvasDialogOpen(container, dialogOpen);
|
|
878
995
|
// Adopt this generation's shadow doc + render context only once it's the live render.
|
|
879
996
|
shadowDoc = rawDoc;
|
|
880
997
|
renderCtx = handle.ctx;
|
|
@@ -38,12 +38,15 @@ import {
|
|
|
38
38
|
tabOfContainer,
|
|
39
39
|
} from "./canvas-surface";
|
|
40
40
|
import { cloneSelection, primarySelection, toggleSelected } from "../tabs/selection";
|
|
41
|
+
import { activeRegistry } from "../commands/active-registry";
|
|
41
42
|
import { getNodeAtPath } from "../state";
|
|
42
43
|
import type { JxPath } from "../state";
|
|
43
44
|
import { setLayoutSelection, shell } from "../shell";
|
|
44
45
|
import { formatEditableVerdicts } from "../format/constraints";
|
|
45
46
|
import { formatByName } from "../format/format-host";
|
|
46
47
|
import { collabState } from "../collab/collab-state";
|
|
48
|
+
import { DIALOG_COMMANDS, isDialog, POPOVER_COMMANDS } from "@jxsuite/schema/dialogs";
|
|
49
|
+
import { isPopover } from "@jxsuite/schema/overlays";
|
|
47
50
|
import { localeDirection } from "@jxsuite/schema/locale";
|
|
48
51
|
import { getPlatform, hasPlatform } from "../platform";
|
|
49
52
|
import type {
|
|
@@ -56,6 +59,7 @@ import type {
|
|
|
56
59
|
IframeToParent,
|
|
57
60
|
InsertZone,
|
|
58
61
|
NodeHit,
|
|
62
|
+
WireDiffMarks,
|
|
59
63
|
ParentToIframe,
|
|
60
64
|
SelectionSnapshot,
|
|
61
65
|
SerializableRect,
|
|
@@ -121,6 +125,22 @@ interface HostState {
|
|
|
121
125
|
contentHeight: number | null;
|
|
122
126
|
/** Whether the last measured content was a component-definition fragment (drops the 480px floor). */
|
|
123
127
|
contentFragment: boolean;
|
|
128
|
+
/**
|
|
129
|
+
* The popover this host is drawing open, as posted. Kept so `mountIframeCanvas` can seed it onto
|
|
130
|
+
* the `render` message — a render replaces the DOM, so a re-mount would otherwise lose it.
|
|
131
|
+
*/
|
|
132
|
+
popoverOpen: JxPath | null;
|
|
133
|
+
/** The dialog this host is drawing open, kept for the same reason. */
|
|
134
|
+
dialogOpen: JxPath | null;
|
|
135
|
+
/**
|
|
136
|
+
* Paths the frame resolved but could not measure, as serialized keys.
|
|
137
|
+
*
|
|
138
|
+
* Not a rect and not an absence: a node that IS in the document and IS in the DOM but is not
|
|
139
|
+
* rendered. The Outline draws these rows with a "not rendered in the canvas" mark, which is the
|
|
140
|
+
* honest answer for a selection that draws no box — the alternative was a 0×0 marker in the
|
|
141
|
+
* artboard's corner, which read as a bug in the editor rather than a fact about the document.
|
|
142
|
+
*/
|
|
143
|
+
hiddenPaths: Set<string>;
|
|
124
144
|
/** Whether an inline-edit session is live in this host's iframe (drives the format toolbar). */
|
|
125
145
|
editing: boolean;
|
|
126
146
|
/** The prop a live plain session edits (prop-bound text) — null for rich sessions/none. */
|
|
@@ -775,9 +795,25 @@ export async function revealCanvasPath(
|
|
|
775
795
|
path: readonly (string | number)[],
|
|
776
796
|
): Promise<CanvasPoint | null> {
|
|
777
797
|
const host = hostForPath();
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
798
|
+
return host ? revealCanvasPathIn(host, path) : null;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
/**
|
|
802
|
+
* {@link revealCanvasPath}, against an artboard the caller has already resolved.
|
|
803
|
+
*
|
|
804
|
+
* **A diff artboard cannot be found by `hostForPath`.** That resolver prefers the host rendering
|
|
805
|
+
* the focused tab and otherwise takes any ready page host — and BOTH git-diff artboards mount with
|
|
806
|
+
* `tabId: null` (it is what stops them routing mutations anywhere), so neither can match the
|
|
807
|
+
* focused tab and the fallback returns an arbitrary one of the two. A change stepper asking for
|
|
808
|
+
* "the node at this path" would measure and pan whichever it happened to get, on either side, in
|
|
809
|
+
* either pane.
|
|
810
|
+
*
|
|
811
|
+
* Callers with a panel in hand reach their host through {@link hostForCanvas} and come here.
|
|
812
|
+
*/
|
|
813
|
+
export async function revealCanvasPathIn(
|
|
814
|
+
host: HostState,
|
|
815
|
+
path: readonly (string | number)[],
|
|
816
|
+
): Promise<CanvasPoint | null> {
|
|
781
817
|
const before = await measureIn(host, path);
|
|
782
818
|
if (!before) {
|
|
783
819
|
return null;
|
|
@@ -793,6 +829,22 @@ export async function revealCanvasPath(
|
|
|
793
829
|
return measureIn(host, path);
|
|
794
830
|
}
|
|
795
831
|
|
|
832
|
+
/**
|
|
833
|
+
* Measure one node in one artboard, without moving anything.
|
|
834
|
+
*
|
|
835
|
+
* The stepper needs BOTH sides' rects before it pans, because it pans to their union — the two
|
|
836
|
+
* artboards share one `.panzoom-wrap` and therefore one vertical position, and a change sitting at
|
|
837
|
+
* different heights on the two boards is only fully on screen if the move accounts for both.
|
|
838
|
+
* {@link revealCanvasPathIn} measures and moves in one go, which is the wrong shape for that.
|
|
839
|
+
*/
|
|
840
|
+
export function measureInCanvas(
|
|
841
|
+
canvasEl: HTMLElement,
|
|
842
|
+
path: readonly (string | number)[],
|
|
843
|
+
): Promise<CanvasPoint | null> {
|
|
844
|
+
const host = hostForCanvas(canvasEl);
|
|
845
|
+
return host ? measureIn(host, path) : Promise.resolve(null);
|
|
846
|
+
}
|
|
847
|
+
|
|
796
848
|
/**
|
|
797
849
|
* Pin the `.canvas-panel-viewport` (the white "page" surface, the canvas element's parent) to the
|
|
798
850
|
* SCALED content height when edit-mode content zoom is active. A `transform: scale()` on the canvas
|
|
@@ -912,7 +964,7 @@ export const INSERT_HIDE_DELAY = 300;
|
|
|
912
964
|
* The parent-realm insertion handler: open the slash menu anchored at the "+" `btn` and, on select,
|
|
913
965
|
* run `transactDoc → mutateInsertNode` for the captured `zone`. Injected from studio.ts (which owns
|
|
914
966
|
* the slash-menu / transact / defaultDef wiring) so this host module — and its tests — stay free of
|
|
915
|
-
* the
|
|
967
|
+
* the slash-menu and the mutation pipeline, mirroring the native-drag handler.
|
|
916
968
|
*/
|
|
917
969
|
let insertZoneClickHandler: ((btn: HTMLElement, zone: InsertZone) => void) | null = null;
|
|
918
970
|
|
|
@@ -1030,8 +1082,8 @@ export interface CanvasSlashRequest {
|
|
|
1030
1082
|
|
|
1031
1083
|
/**
|
|
1032
1084
|
* The parent-realm slash-menu surface the canvas iframe drives (show at a rect, navigate by key,
|
|
1033
|
-
* dismiss). Injected from studio.ts (which owns the
|
|
1034
|
-
*
|
|
1085
|
+
* dismiss). Injected from studio.ts (which owns the menu) so this host module — and its tests —
|
|
1086
|
+
* stay free of it, mirroring {@link insertZoneClickHandler}.
|
|
1035
1087
|
*/
|
|
1036
1088
|
export interface CanvasSlashHandler {
|
|
1037
1089
|
show: (req: CanvasSlashRequest) => void;
|
|
@@ -1161,6 +1213,50 @@ export function setIframePatchEscalation(fn: (paneId: string) => void): void {
|
|
|
1161
1213
|
patchEscalation = fn;
|
|
1162
1214
|
}
|
|
1163
1215
|
|
|
1216
|
+
/**
|
|
1217
|
+
* Tell every frame showing `tab` which popover to draw open.
|
|
1218
|
+
*
|
|
1219
|
+
* Fans out by `tabId` for the same reason `postPatchToHosts` does: two panes can show the same
|
|
1220
|
+
* document, and both must agree about which panel is open — it is the same element in both. A
|
|
1221
|
+
* PREVIEW host is skipped, and the frame refuses the message as well, because preview renders
|
|
1222
|
+
* popovers natively and the canvas attribute does not exist there.
|
|
1223
|
+
*
|
|
1224
|
+
* Also recorded on the host, so a re-mount can seed it onto the `render` message. A render replaces
|
|
1225
|
+
* the DOM and would otherwise close the panel the author was editing.
|
|
1226
|
+
*
|
|
1227
|
+
* @param tab The tab whose canvas is affected.
|
|
1228
|
+
* @param path The popover's document path, or null to close whatever is open.
|
|
1229
|
+
*/
|
|
1230
|
+
export function postPopoverOpen(tab: { id: string }, path: JxPath | null): void {
|
|
1231
|
+
for (const host of liveHosts) {
|
|
1232
|
+
if (!host.iframe.isConnected) {
|
|
1233
|
+
liveHosts.delete(host);
|
|
1234
|
+
continue;
|
|
1235
|
+
}
|
|
1236
|
+
if (host.ready && host.tabId === tab.id && !host.preview) {
|
|
1237
|
+
host.popoverOpen = path;
|
|
1238
|
+
host.channel.post({ kind: "setPopoverOpen", path });
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
/**
|
|
1244
|
+
* The dialog twin of {@link postPopoverOpen}: tell every editable frame showing `tab` which dialog
|
|
1245
|
+
* to draw open.
|
|
1246
|
+
*/
|
|
1247
|
+
export function postDialogOpen(tab: { id: string }, path: JxPath | null): void {
|
|
1248
|
+
for (const host of liveHosts) {
|
|
1249
|
+
if (!host.iframe.isConnected) {
|
|
1250
|
+
liveHosts.delete(host);
|
|
1251
|
+
continue;
|
|
1252
|
+
}
|
|
1253
|
+
if (host.ready && host.tabId === tab.id && !host.preview) {
|
|
1254
|
+
host.dialogOpen = path;
|
|
1255
|
+
host.channel.post({ kind: "setDialogOpen", path });
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1164
1260
|
/**
|
|
1165
1261
|
* Post a surgical patch (value-carrying forward ops) to every ready live iframe host rendering
|
|
1166
1262
|
* `tabId`'s document — a still-connected host showing another tab's doc must never fold a foreign
|
|
@@ -1729,6 +1825,9 @@ function ensureHost(canvasEl: HTMLElement): HostState {
|
|
|
1729
1825
|
channel,
|
|
1730
1826
|
contentFragment: false,
|
|
1731
1827
|
contentHeight: null,
|
|
1828
|
+
hiddenPaths: new Set<string>(),
|
|
1829
|
+
popoverOpen: null,
|
|
1830
|
+
dialogOpen: null,
|
|
1732
1831
|
editing: false,
|
|
1733
1832
|
editingProp: null,
|
|
1734
1833
|
iframe,
|
|
@@ -1907,6 +2006,77 @@ function handleMessage(state: HostState, msg: IframeToParent): void {
|
|
|
1907
2006
|
canvasPointerDownHandler?.();
|
|
1908
2007
|
return;
|
|
1909
2008
|
}
|
|
2009
|
+
case "popoverTargetClick": {
|
|
2010
|
+
/* The click's OTHER half — the `hit` beside it still selects the button. Routed through the
|
|
2011
|
+
command rather than written here, so the trigger, the palette, the Style tab's selector and
|
|
2012
|
+
the assistant are four renderings of one record (§13) rather than four writers.
|
|
2013
|
+
|
|
2014
|
+
`show`/`hide`/`toggle` collapse to a state because the record is a setter: the frame knows
|
|
2015
|
+
which panel is open only through the host, so `toggle` is resolved HERE, where the model
|
|
2016
|
+
is, and never inside the frame. Refused in preview by the host's own gate below. */
|
|
2017
|
+
const tab = hostTab(state);
|
|
2018
|
+
if (!tab || state.preview) {
|
|
2019
|
+
return;
|
|
2020
|
+
}
|
|
2021
|
+
const targeted =
|
|
2022
|
+
JSON.stringify(tab.session.ui.openPopover) === JSON.stringify(msg.targetPath);
|
|
2023
|
+
const open = msg.action === "show" || (msg.action === "toggle" && !targeted);
|
|
2024
|
+
/* A `hide` closes ITS OWN target and no other: `hidePopover()` on a popover that is not
|
|
2025
|
+
showing does nothing, so an invoker for A must leave B alone. `show` and `toggle` still
|
|
2026
|
+
always run — a toggle either opens the one it names or closes the one it names. */
|
|
2027
|
+
if (open || targeted) {
|
|
2028
|
+
void activeRegistry()?.run("canvas.setPopoverOpen", {
|
|
2029
|
+
open,
|
|
2030
|
+
path: msg.targetPath,
|
|
2031
|
+
});
|
|
2032
|
+
}
|
|
2033
|
+
return;
|
|
2034
|
+
}
|
|
2035
|
+
case "commandTargetClick": {
|
|
2036
|
+
/* An invoker's click, answered the way `popoverTargetClick` is: through the record, with a
|
|
2037
|
+
toggle resolved HERE against the model. A popover command lands on the popover verb, a
|
|
2038
|
+
dialog command on the dialog verb; `hide-popover`, `close` and `request-close` close only
|
|
2039
|
+
the overlay they name when it is the open one, and a custom command is the document's own
|
|
2040
|
+
business. */
|
|
2041
|
+
const tab = hostTab(state);
|
|
2042
|
+
if (!tab || state.preview) {
|
|
2043
|
+
return;
|
|
2044
|
+
}
|
|
2045
|
+
const targeted = (open: JxPath | null) =>
|
|
2046
|
+
JSON.stringify(open) === JSON.stringify(msg.targetPath);
|
|
2047
|
+
/* The command's FAMILY is not the target's KIND, and the dispatch needs both. A
|
|
2048
|
+
`show-popover` aimed at a `<dialog>`, or a `show-modal` at a popover, is an authoring
|
|
2049
|
+
mistake Problems already reports as `command-target-mismatch`, and the platform's answer to
|
|
2050
|
+
it is to ignore the click (spec.md §8.7) — so the canvas ignores it too. Routing on the
|
|
2051
|
+
family alone handed the popover verb a dialog's path, and the record REFUSES one: the
|
|
2052
|
+
`RangeError` came straight back out of this message listener, taking every handler queued
|
|
2053
|
+
behind that message with it. The null check is the same guard for a `targetPath` an edit
|
|
2054
|
+
has since invalidated, which threw for the same reason. */
|
|
2055
|
+
const target = getNodeAtPath(tab.doc.document, msg.targetPath);
|
|
2056
|
+
if (!target || typeof target !== "object") {
|
|
2057
|
+
return;
|
|
2058
|
+
}
|
|
2059
|
+
if (POPOVER_COMMANDS.has(msg.command)) {
|
|
2060
|
+
if (!isPopover(target)) {
|
|
2061
|
+
return;
|
|
2062
|
+
}
|
|
2063
|
+
const open =
|
|
2064
|
+
msg.command === "show-popover" ||
|
|
2065
|
+
(msg.command === "toggle-popover" && !targeted(tab.session.ui.openPopover));
|
|
2066
|
+
if (open || targeted(tab.session.ui.openPopover)) {
|
|
2067
|
+
void activeRegistry()?.run("canvas.setPopoverOpen", { open, path: msg.targetPath });
|
|
2068
|
+
}
|
|
2069
|
+
} else if (DIALOG_COMMANDS.has(msg.command)) {
|
|
2070
|
+
if (!isDialog(target)) {
|
|
2071
|
+
return;
|
|
2072
|
+
}
|
|
2073
|
+
const open = msg.command === "show-modal";
|
|
2074
|
+
if (open || targeted(tab.session.ui.openDialog)) {
|
|
2075
|
+
void activeRegistry()?.run("canvas.setDialogOpen", { open, path: msg.targetPath });
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
return;
|
|
2079
|
+
}
|
|
1910
2080
|
case "hit": {
|
|
1911
2081
|
/* A click in a canvas is a click in a PANE, and the parent realm never saw it. See
|
|
1912
2082
|
`focusHostPane`; it goes first so everything below writes into the pane the person is now
|
|
@@ -1925,7 +2095,14 @@ function handleMessage(state: HostState, msg: IframeToParent): void {
|
|
|
1925
2095
|
// Block action bar anchors to the panel the selection was actually made in, not panel 0.
|
|
1926
2096
|
let panelMedia: string | null = null;
|
|
1927
2097
|
const clicked = panelHostingCanvas(state.canvasEl)?.panel;
|
|
1928
|
-
|
|
2098
|
+
/* A panel with NO media name is not an artboard, and a click in it is not a statement about
|
|
2099
|
+
the breakpoint. Edit draws exactly one full-width column (`canvasPanelTemplate(null, …)`,
|
|
2100
|
+
so `mediaName` is `""`), which `panelMediaToActiveMedia` mapped to `null` — so every click
|
|
2101
|
+
into the page silently reset the pane to Base, undoing the size switcher and, now, any
|
|
2102
|
+
width the author had dragged the column to. Design's own panels are `"base"` or a real
|
|
2103
|
+
breakpoint key, so requiring a name changes nothing there; the only case it drops is the
|
|
2104
|
+
no-`$media` single panel, whose project has no breakpoint to be reset FROM. */
|
|
2105
|
+
if (clicked?.mediaName && !clicked.mediaName.startsWith("git-diff")) {
|
|
1929
2106
|
panelMedia = panelMediaToActiveMedia(clicked.mediaName);
|
|
1930
2107
|
// The breakpoint belongs to the tab THIS host renders, resolved the same way every other
|
|
1931
2108
|
// Doc-touching message in this switch resolves it. `updateUi` writes to `activeTab`, which
|
|
@@ -2089,9 +2266,13 @@ function handleMessage(state: HostState, msg: IframeToParent): void {
|
|
|
2089
2266
|
const sbTag = state.stylebook ? shell.stylebook.selection : null;
|
|
2090
2267
|
state.overlay.setSelection(rect, sbTag ? `<${sbTag}>` : null);
|
|
2091
2268
|
state.overlay.setCoSelection(co);
|
|
2092
|
-
if (rect)
|
|
2093
|
-
|
|
2094
|
-
|
|
2269
|
+
/* Unconditional. `if (rect)` never CLEARED it, so a selection the frame could not measure —
|
|
2270
|
+
now including any node it reports under `hidden` — left the previous rect standing, and
|
|
2271
|
+
`getEditBarAnchorRect` went on returning it. The block action bar stayed anchored to a box
|
|
2272
|
+
that was no longer on screen. `repositionBlockActionBar` already hides the bar on a null
|
|
2273
|
+
anchor, so nothing else has to change. */
|
|
2274
|
+
state.lastSelectionRect = rect;
|
|
2275
|
+
state.hiddenPaths = new Set((msg.hidden ?? []).map((p) => JSON.stringify(p)));
|
|
2095
2276
|
}
|
|
2096
2277
|
return;
|
|
2097
2278
|
}
|
|
@@ -2658,7 +2839,12 @@ type PreparedRender = Omit<
|
|
|
2658
2839
|
/** One render pass's prepared payloads, by document IDENTITY. */
|
|
2659
2840
|
type PreparedDocs = Map<
|
|
2660
2841
|
JxMutableNode,
|
|
2661
|
-
{
|
|
2842
|
+
{
|
|
2843
|
+
tabId: string | null;
|
|
2844
|
+
viewTabId: string | null;
|
|
2845
|
+
mode: string | null;
|
|
2846
|
+
payload: Promise<PreparedRender>;
|
|
2847
|
+
}
|
|
2662
2848
|
>;
|
|
2663
2849
|
|
|
2664
2850
|
/**
|
|
@@ -2696,6 +2882,11 @@ const PREPARED_PASS_LIMIT = 4;
|
|
|
2696
2882
|
* THAT — the document path, the layout toggle, the preview params and the mode. A mismatch in
|
|
2697
2883
|
* either re-prepares rather than reusing. `tabId` alone would not do: an override render nulls it,
|
|
2698
2884
|
* so two git-diff documents would agree on `null` while being views of different tabs.
|
|
2885
|
+
*
|
|
2886
|
+
* The pane's MODE is the third part of the key, because it is now an input to the resolution rather
|
|
2887
|
+
* than something derived from `viewTabId` inside it. Two views of one document in different modes
|
|
2888
|
+
* are two different renders — a Diff lens and the pane it follows are exactly that — and without
|
|
2889
|
+
* this they would agree on both ids and share a payload resolved for whichever asked first.
|
|
2699
2890
|
*/
|
|
2700
2891
|
const preparedPasses = new Map<number, PreparedDocs>();
|
|
2701
2892
|
|
|
@@ -2739,11 +2930,17 @@ function preparePassRender(
|
|
|
2739
2930
|
tabId: string | null,
|
|
2740
2931
|
viewTab: Tab | null,
|
|
2741
2932
|
paneId: string,
|
|
2933
|
+
modeOverride: string | null = null,
|
|
2742
2934
|
): Promise<PreparedRender> {
|
|
2743
2935
|
const byDoc = preparedDocsFor(gen);
|
|
2744
2936
|
const viewTabId = viewTab?.id ?? null;
|
|
2745
2937
|
const cached = byDoc.get(doc);
|
|
2746
|
-
if (
|
|
2938
|
+
if (
|
|
2939
|
+
cached &&
|
|
2940
|
+
cached.tabId === tabId &&
|
|
2941
|
+
cached.viewTabId === viewTabId &&
|
|
2942
|
+
cached.mode === modeOverride
|
|
2943
|
+
) {
|
|
2747
2944
|
return cached.payload;
|
|
2748
2945
|
}
|
|
2749
2946
|
// One-shot per PANE's pass, not per host and not globally. `allowAutoRequestsOnNextRender` arms
|
|
@@ -2755,7 +2952,7 @@ function preparePassRender(
|
|
|
2755
2952
|
const allowAutoRequests = consumeAllowAutoRequests(paneId);
|
|
2756
2953
|
const payload = timeSpanAsync(SPAN_PREPARE_RENDER, async (): Promise<PreparedRender> => {
|
|
2757
2954
|
canvasPerf.renderPreparations += 1;
|
|
2758
|
-
const resolved = await resolveCanvasDocument(doc, viewTab);
|
|
2955
|
+
const resolved = await resolveCanvasDocument(doc, viewTab, modeOverride);
|
|
2759
2956
|
// The doc must be structured-cloneable to cross postMessage. A Jx document is JSON by contract,
|
|
2760
2957
|
// So a JSON round-trip (NOT structuredClone, which would throw) drops residual functions /
|
|
2761
2958
|
// Reactive proxy artifacts that would otherwise raise DataCloneError and silently drop the
|
|
@@ -2779,6 +2976,10 @@ function preparePassRender(
|
|
|
2779
2976
|
doc: cloneableDoc,
|
|
2780
2977
|
docBase: resolved.docBase ?? `${canvasBaseOrigin()}/`,
|
|
2781
2978
|
mapperCtx: resolved.mapperCtx,
|
|
2979
|
+
/* Still a cast, but no longer a lie: `WireMapperCtx.canvasMode` is typed `string` (it mirrors
|
|
2980
|
+
`PathMapCtx`, which carries the mode for `isEditableMode` and takes `CanvasMode | string`),
|
|
2981
|
+
so this narrows a string to the union. It used to narrow it to a union that did not list
|
|
2982
|
+
`git-diff` while git-diff renders went through here every day. */
|
|
2782
2983
|
mode: resolved.mapperCtx.canvasMode as CanvasMode,
|
|
2783
2984
|
shadowDoc: cloneableShadow,
|
|
2784
2985
|
siteStyle: resolved.siteStyle,
|
|
@@ -2786,7 +2987,7 @@ function preparePassRender(
|
|
|
2786
2987
|
...(allowAutoRequests ? { allowAutoRequests: true } : {}),
|
|
2787
2988
|
};
|
|
2788
2989
|
});
|
|
2789
|
-
byDoc.set(doc, { payload, tabId, viewTabId });
|
|
2990
|
+
byDoc.set(doc, { mode: modeOverride, payload, tabId, viewTabId });
|
|
2790
2991
|
return payload;
|
|
2791
2992
|
}
|
|
2792
2993
|
|
|
@@ -2816,6 +3017,11 @@ function preparePassRender(
|
|
|
2816
3017
|
* `paneOfContainer` does everywhere else stage content is handed a host and nothing else; the one
|
|
2817
3018
|
* production caller (`canvas-render.ts`) passes `tabOfPane(surface.paneId)` explicitly, because it
|
|
2818
3019
|
* has already resolved it to pick the document.
|
|
3020
|
+
*
|
|
3021
|
+
* `modeOverride` is the third question in the same family, and it exists because `viewTab` cannot
|
|
3022
|
+
* answer it: a lens draws the source pane's document in a mode that is never written onto that tab,
|
|
3023
|
+
* so resolving the mode from `viewTab` gave a Diff lens's artboards the SOURCE pane's mode. See
|
|
3024
|
+
* {@link resolveCanvasDocument}. Null derives it from `viewTab` as before.
|
|
2819
3025
|
*/
|
|
2820
3026
|
export async function mountIframeCanvas(
|
|
2821
3027
|
gen: number,
|
|
@@ -2824,6 +3030,8 @@ export async function mountIframeCanvas(
|
|
|
2824
3030
|
widthPx?: number | null,
|
|
2825
3031
|
tabId: string | null = null,
|
|
2826
3032
|
viewTab: Tab | null = tabOfContainer(canvasEl),
|
|
3033
|
+
modeOverride: string | null = null,
|
|
3034
|
+
diffMarks: WireDiffMarks | null = null,
|
|
2827
3035
|
): Promise<void> {
|
|
2828
3036
|
const state = ensureHost(canvasEl);
|
|
2829
3037
|
state.pendingTabIds.set(gen, tabId);
|
|
@@ -2834,16 +3042,35 @@ export async function mountIframeCanvas(
|
|
|
2834
3042
|
// Own `latestGen`), so the parent must NOT gate on `view.renderGeneration`: during boot many
|
|
2835
3043
|
// Renders fire and the generation is usually stale by the time resolution finishes, which would
|
|
2836
3044
|
// Otherwise drop every post.
|
|
2837
|
-
const prepared = await preparePassRender(
|
|
3045
|
+
const prepared = await preparePassRender(
|
|
3046
|
+
gen,
|
|
3047
|
+
doc,
|
|
3048
|
+
tabId,
|
|
3049
|
+
viewTab,
|
|
3050
|
+
paneOfContainer(canvasEl),
|
|
3051
|
+
modeOverride,
|
|
3052
|
+
);
|
|
2838
3053
|
const message: ParentToIframe = {
|
|
2839
3054
|
...prepared,
|
|
2840
3055
|
// Per-TAB, and read at POST time so a scheme flip that raced the shared resolution is not
|
|
2841
3056
|
// Baked into the payload every host shares. `viewTab` is this artboard's tab — defaulted from
|
|
2842
3057
|
// `tabOfContainer(canvasEl)`, the same route the rest of this mount takes.
|
|
2843
3058
|
colorScheme: schemeWireFor(viewTab),
|
|
3059
|
+
/* Per-ARTBOARD, and post-time for a sharper version of the same reason. `preparePassRender`
|
|
3060
|
+
memoizes on the document and hands the SAME payload object to every host in the pass, and a
|
|
3061
|
+
git-diff pass has two hosts holding two documents — but marks are a function of BOTH sides,
|
|
3062
|
+
not of the document this host draws, so they are not derivable from that cache key at all.
|
|
3063
|
+
Baking them in would make the two artboards race for whose marks the pass kept. */
|
|
3064
|
+
...(diffMarks ? { diffMarks } : {}),
|
|
2844
3065
|
gen,
|
|
2845
3066
|
kind: "render",
|
|
3067
|
+
// Read at POST time for the same reason `colorScheme` is: a render replaces the DOM, so a panel
|
|
3068
|
+
// The author opened before this pass would close under them without it.
|
|
3069
|
+
popoverOpen: viewTab?.session.ui.openPopover ?? null,
|
|
3070
|
+
dialogOpen: viewTab?.session.ui.openDialog ?? null,
|
|
2846
3071
|
};
|
|
3072
|
+
state.popoverOpen = message.popoverOpen ?? null;
|
|
3073
|
+
state.dialogOpen = message.dialogOpen ?? null;
|
|
2847
3074
|
// Preview is the fidelity view: no editing messages are honoured from it, no overlay is painted
|
|
2848
3075
|
// Over it, and the frame stays viewport-sized so it scrolls for real. A mode switch to preview
|
|
2849
3076
|
// Mid-split must likewise not start an edit session in the preview render. The flag and the frame
|
|
@@ -3000,6 +3227,35 @@ export function postLocaleToLiveHosts(locale: string | null, root?: HTMLElement
|
|
|
3000
3227
|
}
|
|
3001
3228
|
}
|
|
3002
3229
|
|
|
3230
|
+
/**
|
|
3231
|
+
* Replace an element's definition in every live frame (embedding.md §7's canvas half).
|
|
3232
|
+
*
|
|
3233
|
+
* Unscoped on purpose, where the locale and colour-scheme posts take a stage: a definition is a
|
|
3234
|
+
* fact about the REALM, not about a pane, and a frame that kept the old one would draw a different
|
|
3235
|
+
* element from the one beside it. Instances already on a canvas keep the definition they rendered
|
|
3236
|
+
* until their host renders again, which is why {@link redefineElementOnCanvases} follows this with a
|
|
3237
|
+
* render of every pane rather than trusting the message alone.
|
|
3238
|
+
*
|
|
3239
|
+
* The document crosses `postMessage`, so it is cloned to plain data first: a definition that came
|
|
3240
|
+
* off a tab's reactive record is a proxy, and a proxy cannot be structured-cloned.
|
|
3241
|
+
*/
|
|
3242
|
+
export function postRedefineElementToLiveHosts(doc: JxMutableNode, base: string): number {
|
|
3243
|
+
// oxlint-disable-next-line unicorn/prefer-structured-clone
|
|
3244
|
+
const plain = JSON.parse(JSON.stringify(doc)) as JxMutableNode;
|
|
3245
|
+
let posted = 0;
|
|
3246
|
+
for (const host of liveHosts) {
|
|
3247
|
+
if (!host.iframe.isConnected) {
|
|
3248
|
+
liveHosts.delete(host);
|
|
3249
|
+
continue;
|
|
3250
|
+
}
|
|
3251
|
+
if (host.ready) {
|
|
3252
|
+
host.channel.post({ base, doc: plain, kind: "redefineElement" });
|
|
3253
|
+
posted += 1;
|
|
3254
|
+
}
|
|
3255
|
+
}
|
|
3256
|
+
return posted;
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3003
3259
|
/**
|
|
3004
3260
|
* Push the project's current site style to every ready PAGE host as an in-place sheet replace (live
|
|
3005
3261
|
* design-token editing — stylebook hosts pre-merge site style into the specimen doc and are
|