@jxsuite/studio 6.1.2 → 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/adapter-5tphg7xe.js +4 -0
- package/dist/chunks/add-new-flow-psym14sn.js +4 -0
- package/dist/chunks/cf-account-picker-haqazq5r.js +4 -0
- package/dist/chunks/cf-settings-h2wrh6hq.js +4 -0
- package/dist/chunks/{color-area-0fj8a4ga.js → color-area-6rbra5dy.js} +2 -2
- package/dist/chunks/{color-field-xch8kx2g.js → color-field-gy56c94g.js} +3 -3
- package/dist/chunks/color-m7r1vk54.js +4 -0
- package/dist/chunks/{color-slider-jxd8v350.js → color-slider-sqqdyf6c.js} +2 -2
- package/dist/chunks/{combobox-p0efwjke.js → combobox-72h32ejk.js} +3 -3
- package/dist/chunks/components-r22xca09.js +4 -0
- package/dist/chunks/content-source-mmppmcyg.js +4 -0
- package/dist/chunks/convert-to-repeater-he70fc2b.js +4 -0
- package/dist/chunks/editor-ccd9jwsa.js +4 -0
- package/dist/chunks/entry-commands-6qxz9e8p.js +4 -0
- package/dist/chunks/extension-sections-0egb88dm.js +4 -0
- package/dist/chunks/file-ops-qnab36ek.js +4 -0
- package/dist/chunks/files-rcn56qvm.js +4 -0
- package/dist/chunks/format-host-yxz0kjjs.js +4 -0
- package/dist/chunks/fs-events-d1qxq4z4.js +4 -0
- package/dist/chunks/grid-open-4z1g062t.js +4 -0
- package/dist/chunks/{grid-view-d2wq9ezg.js → grid-view-qg1b5eqx.js} +25 -25
- package/dist/chunks/{icons-pnfz478q.js → icons-63bjtbs7.js} +2 -2
- package/dist/chunks/{iframe-entry-jdcktez8.js → iframe-entry-2zggzajv.js} +4 -4
- package/dist/chunks/{iframe-entry-zap785cw.js → iframe-entry-76j8vwwx.js} +4 -4
- package/dist/chunks/iframe-entry-99nr5zfb.js +5 -0
- package/dist/chunks/{iframe-entry-x0ygf2yr.js → iframe-entry-pkgmcgp0.js} +4 -4
- package/dist/chunks/iframe-host-ssv7kyj0.js +4 -0
- package/dist/chunks/{index-zpjmzqfk.js → index-32eqzv1k.js} +3 -3
- package/dist/chunks/index-f0jn7nnp.js +4 -0
- package/dist/chunks/{javascript-m54mnwp6.js → javascript-pjp734q4.js} +3 -3
- package/dist/chunks/jsonMode-njkvsa02.js +13 -0
- package/dist/chunks/jx-validate-ttasrbh7.js +4 -0
- package/dist/chunks/layers-bgyr11tr.js +4 -0
- package/dist/chunks/layers-panel-7ez66zeq.js +4 -0
- package/dist/chunks/{listbox-e74qjyq6.js → listbox-c421cf8c.js} +2 -2
- package/dist/chunks/lit-html-v9gh687x.js +4 -0
- package/dist/chunks/media-library-sq468wts.js +4 -0
- package/dist/chunks/media-picker-shfe59pt.js +4 -0
- package/dist/chunks/{menu-n6yzswmy.js → menu-bdpzbfvs.js} +2 -2
- package/dist/chunks/{monaco-binding-7gx83x3r.js → monaco-binding-vq1hgnn0.js} +3 -3
- package/dist/chunks/monaco-buffer-3afgwvbp.js +4 -0
- package/dist/chunks/monaco-setup-xrd2cbkp.js +4 -0
- package/dist/chunks/notify-kzrjr3fv.js +4 -0
- package/dist/chunks/parse-v77xtwv7.js +4 -0
- package/dist/chunks/platform-7v4rtd7m.js +4 -0
- package/dist/chunks/popover-b89sfej7.js +4 -0
- package/dist/chunks/publish-panel-2z9gw8ee.js +4 -0
- package/dist/chunks/publish-quick-qx2455cj.js +4 -0
- package/dist/chunks/publish-workspace-wrc1dgwx.js +4 -0
- package/dist/chunks/quick-search-n0t0eqxb.js +4 -0
- package/dist/chunks/references-9547rg5s.js +4 -0
- package/dist/chunks/right-panel-wsgnr9pn.js +4 -0
- package/dist/chunks/source-control-kwktr9y6.js +4 -0
- package/dist/chunks/{split-n2gfpm5m.js → split-c9zfdgxf.js} +2 -2
- package/dist/chunks/studio-03ct6yfv.js +9 -0
- package/dist/chunks/studio-07rcfje3.js +5 -0
- package/dist/chunks/studio-3e54qh39.js +7 -0
- package/dist/chunks/studio-3exxhz5g.js +5 -0
- package/dist/chunks/studio-3q40e3rj.js +5 -0
- package/dist/chunks/studio-3qeh9t0h.js +6 -0
- package/dist/chunks/studio-3qqjeep5.js +6 -0
- package/dist/chunks/studio-43sd2mam.js +4 -0
- package/dist/chunks/studio-4hp8pkyt.js +5 -0
- package/dist/chunks/studio-58xg6j2q.js +9 -0
- package/dist/chunks/studio-5g0rprdt.js +7 -0
- package/dist/chunks/{studio-2j1cb95x.js → studio-6m380wp7.js} +4 -4
- package/dist/chunks/studio-80jyh1xh.js +4 -0
- package/dist/chunks/studio-83mk4bgg.js +9 -0
- package/dist/chunks/{studio-v0jzqdjm.js → studio-881z1xrx.js} +4 -4
- package/dist/chunks/studio-8m0y2qe7.js +5 -0
- package/dist/chunks/{studio-d81xfh1g.js → studio-8tr6cfrc.js} +4 -4
- package/dist/chunks/studio-8vcvfs7r.js +6 -0
- package/dist/chunks/studio-9tmebf0s.js +5 -0
- package/dist/chunks/studio-a2bvaptz.js +5 -0
- package/dist/chunks/studio-b7y5mr30.js +5 -0
- package/dist/chunks/studio-bavb31r0.js +5 -0
- package/dist/chunks/{studio-dgz8d0c1.js → studio-bbe4c90a.js} +4 -4
- package/dist/chunks/studio-c05wdnt3.js +5 -0
- package/dist/chunks/studio-ccv2svc6.js +5 -0
- package/dist/chunks/studio-d5grtb9e.js +16 -0
- package/dist/chunks/studio-df0baea9.js +5 -0
- package/dist/chunks/studio-dgk4dqtx.js +7 -0
- package/dist/chunks/studio-e1g64q43.js +5 -0
- package/dist/chunks/studio-ed1hp6zf.js +6 -0
- package/dist/chunks/studio-ed3xx40h.js +7 -0
- package/dist/chunks/studio-f14e1zdj.js +5 -0
- package/dist/chunks/studio-fbhxxc5f.js +5 -0
- package/dist/chunks/studio-fyh0jc96.js +5 -0
- package/dist/chunks/studio-gcxk20n7.js +5 -0
- package/dist/chunks/studio-jaaz8ce9.js +5 -0
- package/dist/chunks/{studio-90pq9km1.js → studio-jcnsdaep.js} +4 -4
- package/dist/chunks/studio-jsgf2q5k.js +7 -0
- package/dist/chunks/{studio-0q988f9w.js → studio-k3xxbagr.js} +3 -3
- package/dist/chunks/{studio-5ve6bbep.js → studio-k7evxqh4.js} +4 -4
- package/dist/chunks/studio-kt3pjkwd.js +5 -0
- package/dist/chunks/studio-m8g16bgz.js +5 -0
- package/dist/chunks/studio-mn0476ag.js +5 -0
- package/dist/chunks/studio-mx1smyq0.js +5 -0
- package/dist/chunks/studio-n0c5h6mf.js +5 -0
- package/dist/chunks/{studio-485046te.js → studio-nh6d342n.js} +7 -7
- package/dist/chunks/studio-nqxqf8p2.js +4 -0
- package/dist/chunks/studio-p4nrkvqr.js +5 -0
- package/dist/chunks/{studio-1fxkaaea.js → studio-pbxa5fpc.js} +4 -4
- package/dist/chunks/studio-pgmvdv7z.js +7 -0
- package/dist/chunks/studio-ph84avkf.js +5 -0
- package/dist/chunks/{studio-tq0rtfwj.js → studio-q0mvbaq6.js} +4 -4
- package/dist/chunks/studio-q0tccd43.js +5 -0
- package/dist/chunks/studio-q7rtx6zq.js +14 -0
- package/dist/chunks/{studio-a3g98wjr.js → studio-qgh13jtz.js} +4 -4
- package/dist/chunks/studio-qmn1xc24.js +5 -0
- package/dist/chunks/studio-qwdqwkj0.js +5 -0
- package/dist/chunks/studio-r5qy30vx.js +5 -0
- package/dist/chunks/studio-rj9eamf8.js +5 -0
- package/dist/chunks/studio-rptgsk96.js +5 -0
- package/dist/chunks/studio-rthyg42z.js +928 -0
- package/dist/chunks/studio-s19tp1xr.js +5 -0
- package/dist/chunks/studio-s32578pn.js +5 -0
- package/dist/chunks/studio-svb7yyve.js +5 -0
- package/dist/chunks/studio-syreb644.js +5 -0
- package/dist/chunks/studio-tf9jryb1.js +10 -0
- package/dist/chunks/studio-tfkznv39.js +5 -0
- package/dist/chunks/studio-tft6r105.js +5 -0
- package/dist/chunks/studio-txf2kysx.js +5 -0
- package/dist/chunks/studio-v8867ddv.js +12 -0
- package/dist/chunks/studio-vxq7fcvv.js +5 -0
- package/dist/chunks/studio-w4rz9hdk.js +5 -0
- package/dist/chunks/studio-wbcjbhy1.js +9 -0
- package/dist/chunks/studio-wc649wss.js +5 -0
- package/dist/chunks/studio-wys23mxz.js +5 -0
- package/dist/chunks/studio-x1x167jh.js +5 -0
- package/dist/chunks/studio-x9hsze61.js +5 -0
- package/dist/chunks/studio-y0n7yxea.js +9 -0
- package/dist/chunks/studio-y3ahhdpx.js +5 -0
- package/dist/chunks/studio-z97c48fk.js +5 -0
- package/dist/chunks/studio-zat62m0c.js +5 -0
- package/dist/chunks/studio-zcd2e7yz.js +5 -0
- package/dist/chunks/studio-zz9qe3rw.js +64 -0
- package/dist/chunks/toast-1gv0h53h.js +4 -0
- package/dist/chunks/{toast-host-ke5z4ng7.js → toast-host-1yg5ar8d.js} +3 -3
- package/dist/chunks/{tooltip-5v8ngwj2.js → tooltip-yypz28gq.js} +3 -3
- package/dist/chunks/{tree-mdq3v5cw.js → tree-9xa4hm7n.js} +2 -2
- package/dist/chunks/tsMode-epyfz1hv.js +14 -0
- package/dist/chunks/workspace-dz7nxfhv.js +4 -0
- package/dist/chunks/workspace-home-xsd7hkjw.js +4 -0
- package/dist/chunks/{ws-client-nze0k6mv.js → ws-client-bv552sfx.js} +3 -3
- package/dist/iframe-entry.js +20 -16
- package/dist/manifest.json +77 -63
- package/dist/studio.js +103 -104
- package/dist/workers/ts.worker.js +3 -3
- package/package.json +12 -11
- package/src/browse/component-examples.ts +272 -0
- package/src/browse/library-commands.ts +64 -104
- package/src/browse/library-layouts.ts +263 -49
- package/src/browse/library-model.ts +181 -133
- package/src/browse/library-pane.ts +738 -446
- package/src/browse/library-preview.ts +149 -19
- package/src/browse/library-source.ts +308 -41
- package/src/browse/preview-root.ts +78 -0
- package/src/browse/preview-style.ts +155 -0
- package/src/canvas/asset-refs.ts +16 -1
- package/src/canvas/canvas-live-render.ts +222 -30
- package/src/canvas/canvas-origin.ts +37 -12
- package/src/canvas/canvas-page-context.ts +112 -0
- package/src/canvas/canvas-render.ts +113 -107
- package/src/canvas/canvas-utils.ts +57 -12
- package/src/canvas/iframe-drop.ts +107 -0
- package/src/canvas/iframe-entry.ts +24 -12
- package/src/canvas/iframe-host.ts +134 -62
- package/src/canvas/iframe-keys.ts +11 -0
- package/src/canvas/iframe-patch.ts +8 -7
- package/src/canvas/iframe-protocol.ts +24 -5
- package/src/canvas/iframe-render.ts +48 -1
- package/src/canvas/iframe-subtree.ts +5 -2
- package/src/canvas/npm-modules.ts +22 -0
- package/src/canvas/preview-navigate.ts +16 -0
- package/src/canvas/repeater-sources.ts +200 -0
- package/src/canvas/stage-scrollbar.ts +5 -1
- package/src/canvas/surface-registry.ts +6 -0
- package/src/commands/app-commands.ts +16 -6
- package/src/commands/budget.ts +10 -8
- package/src/commands/context.ts +35 -10
- package/src/commands/defaults.ts +69 -45
- package/src/commands/keymap.ts +9 -0
- package/src/commands/levels.ts +11 -5
- package/src/commands/live-context.ts +2 -0
- package/src/commands/registry.ts +10 -1
- package/src/content/collection-match.ts +6 -5
- package/src/content/collection-pages.ts +412 -0
- package/src/content/content-collections.ts +270 -0
- package/src/content/entry-commands.ts +51 -60
- package/src/content/entry-editor.ts +111 -18
- package/src/content/entry-fields.ts +13 -1
- package/src/content/entry-inspector.ts +225 -0
- package/src/content/entry-model.ts +17 -3
- package/src/content/entry-open.ts +80 -0
- package/src/content/entry-summaries.ts +440 -0
- package/src/content/file-record-ids.ts +80 -0
- package/src/content/file-records.ts +125 -0
- package/src/content/page-summaries.ts +129 -0
- package/src/content/record-entry.ts +201 -0
- package/src/content/writing-banner.ts +177 -0
- package/src/create/add-new-commands.ts +185 -0
- package/src/create/add-new-flow.ts +1116 -0
- package/src/create/add-new.ts +1014 -0
- package/src/create/element-name.ts +121 -0
- package/src/editor/convert-to-component.ts +67 -43
- package/src/editor/file-drop-action.ts +9 -1
- package/src/editor/inline-edit-apply.ts +44 -0
- package/src/editor/inline-edit.ts +10 -0
- package/src/editor/insert-component.ts +91 -0
- package/src/editor/insert-zone-action.ts +13 -4
- package/src/editor/shortcuts.ts +44 -22
- package/src/editor/slash-menu.ts +51 -8
- package/src/files/components.ts +74 -10
- package/src/files/file-ops.ts +15 -5
- package/src/files/files.ts +164 -150
- package/src/files/fs-events.ts +18 -7
- package/src/files/media-meta.ts +95 -1
- package/src/files/media-types.ts +55 -0
- package/src/files/media-upload.ts +209 -52
- package/src/files/new-file-name.ts +156 -0
- package/src/files/serialize-document.ts +13 -3
- package/src/format/format-host.ts +15 -0
- package/src/github/github-auth.ts +2 -2
- package/src/github/github-publish.ts +4 -3
- package/src/grid/grid-controller.ts +5 -1
- package/src/grid/grid-open.ts +0 -27
- package/src/grid/grid-panel.ts +54 -2
- package/src/grid/grid-reveal.ts +34 -0
- package/src/grid/grid-source.ts +3 -25
- package/src/grid/grid-view.ts +31 -6
- package/src/grid/sources/content-source.ts +75 -7
- package/src/grid/tabulator-tables.d.ts +6 -0
- package/src/hosting/document.ts +2 -2
- package/src/i18n/i18n-commands.ts +2 -1
- package/src/media/media-commands.ts +181 -0
- package/src/media/media-library-model.ts +232 -0
- package/src/media/media-library.ts +1283 -0
- package/src/media/media-pane.ts +47 -19
- package/src/packages/pull-package-sync.ts +1 -1
- package/src/panels/activity-panel.ts +21 -5
- package/src/panels/ai-chat/chat-markdown.ts +8 -8
- package/src/panels/block-action-bar.ts +11 -11
- package/src/panels/canvas-dnd-bridge.ts +5 -2
- package/src/panels/chat-panel.ts +6 -6
- package/src/panels/collections-panel.ts +306 -0
- package/src/panels/component-preview.ts +35 -13
- package/src/panels/data-explorer.ts +1 -1
- package/src/panels/data-grid.ts +4 -0
- package/src/panels/dnd.ts +17 -30
- package/src/panels/elements-panel.ts +9 -2
- package/src/panels/empty-state.ts +2 -2
- package/src/panels/formula-workspace.ts +2 -3
- package/src/panels/frontmatter-fields.ts +9 -9
- package/src/panels/git-diff-open.ts +9 -5
- package/src/panels/head-panel.ts +369 -103
- package/src/panels/i18n-panel.ts +11 -10
- package/src/panels/imports-panel.ts +2 -0
- package/src/panels/jump-bar.ts +27 -2
- package/src/panels/layers-panel.ts +36 -30
- package/src/panels/left-panel.ts +22 -8
- package/src/panels/navigator-panels.ts +23 -11
- package/src/panels/pane-context.ts +111 -29
- package/src/panels/pane-grid.ts +6 -6
- package/src/panels/panel-registry.ts +14 -9
- package/src/panels/properties-panel.ts +7 -3
- package/src/panels/right-panel.ts +199 -43
- package/src/panels/seo-modal.ts +41 -108
- package/src/panels/settings-menu.ts +52 -50
- package/src/panels/settings-pane.ts +268 -162
- package/src/panels/signals-panel.ts +3 -4
- package/src/panels/site-model.ts +367 -0
- package/src/panels/site-panel.ts +638 -0
- package/src/panels/style-panel.ts +37 -3
- package/src/panels/stylebook-doc.ts +142 -10
- package/src/panels/stylebook-layers-panel.ts +39 -80
- package/src/panels/stylebook-panel.ts +47 -10
- package/src/panels/styles-panel.ts +327 -0
- package/src/panels/tab-strip.ts +109 -25
- package/src/platform.ts +1 -1
- package/src/platforms/cloud.ts +28 -1
- package/src/platforms/default-platform.ts +4 -4
- package/src/platforms/devserver.ts +51 -25
- package/src/publish/deploy-checklist.ts +12 -7
- package/src/publish/pages-service.ts +38 -14
- package/src/publish/publish-changes.ts +491 -0
- package/src/publish/publish-commands.ts +83 -18
- package/src/publish/publish-ids.ts +49 -0
- package/src/publish/publish-quick.ts +148 -0
- package/src/publish/publish-workspace.ts +926 -0
- package/src/publish/source-control.ts +907 -0
- package/src/services/automation.ts +16 -20
- package/src/services/cf-settings.ts +4 -4
- package/src/services/connection.ts +2 -2
- package/src/services/directory-picker.ts +2 -2
- package/src/services/references.ts +0 -0
- package/src/services/render-critic.ts +21 -2
- package/src/services/settings/definitions.ts +25 -14
- package/src/settings/contributed-section.ts +49 -10
- package/src/settings/css-vars-editor.ts +93 -27
- package/src/settings/developer-panels.ts +43 -0
- package/src/settings/extension-sections.ts +20 -2
- package/src/settings/general-settings.ts +91 -21
- package/src/settings/preferences-dialog.ts +8 -1
- package/src/settings/project-sections.ts +27 -10
- package/src/settings/schema-field-ui.ts +3 -1
- package/src/settings/section-registry.ts +116 -11
- package/src/settings/settings-dialog.ts +192 -0
- package/src/settings/settings-document.ts +182 -162
- package/src/shell.ts +467 -431
- package/src/site-context.ts +64 -10
- package/src/state.ts +28 -9
- package/src/studio.ts +194 -41
- package/src/style/project-styles.ts +34 -0
- package/src/style/stylebook-specimens.ts +89 -0
- package/src/style/stylebook-target.ts +26 -0
- package/src/style/tag-inheritance.ts +105 -0
- package/src/style/variables-focus.ts +61 -0
- package/src/style/variables-view.ts +235 -0
- package/src/surfaces/add-new.json +1482 -0
- package/src/surfaces/add-new.ts +325 -0
- package/src/surfaces/ai-chat.ts +2 -2
- package/src/surfaces/boot-failure.json +4 -3
- package/src/surfaces/bottom-dock.json +1 -1
- package/src/surfaces/canvas-stage.json +30 -19
- package/src/surfaces/canvas-stage.ts +5 -5
- package/src/surfaces/collections-panel.json +615 -0
- package/src/surfaces/collections-panel.ts +168 -0
- package/src/surfaces/commandbar.json +241 -96
- package/src/surfaces/commandbar.ts +134 -99
- package/src/surfaces/empty-state.json +1 -1
- package/src/surfaces/entry-editor.json +136 -0
- package/src/surfaces/entry-editor.ts +21 -0
- package/src/surfaces/entry-inspector.json +371 -0
- package/src/surfaces/entry-inspector.ts +143 -0
- package/src/surfaces/inspector-dock.json +162 -14
- package/src/surfaces/inspector-dock.ts +46 -19
- package/src/surfaces/library-pane.json +670 -437
- package/src/surfaces/library-pane.ts +94 -59
- package/src/surfaces/media-browser.json +62 -6
- package/src/surfaces/media-browser.ts +15 -1
- package/src/surfaces/media-field.json +1 -1
- package/src/surfaces/media-library.json +1586 -0
- package/src/surfaces/media-library.ts +282 -0
- package/src/surfaces/media-pick-dialog.json +71 -0
- package/src/surfaces/media-pick-dialog.ts +132 -0
- package/src/surfaces/menu.ts +18 -0
- package/src/surfaces/pane-context.json +144 -77
- package/src/surfaces/pane-context.ts +24 -0
- package/src/surfaces/panel-deploy-checklist.json +12 -6
- package/src/surfaces/panel-deploy-checklist.ts +3 -1
- package/src/surfaces/panel-page.json +72 -2
- package/src/surfaces/panel-page.ts +38 -7
- package/src/surfaces/panel-signals.json +1 -1
- package/src/surfaces/panel-signals.ts +5 -5
- package/src/surfaces/panel-stylebook-layers.json +71 -204
- package/src/surfaces/panel-stylebook-layers.ts +0 -21
- package/src/surfaces/preferences.json +120 -48
- package/src/surfaces/preferences.ts +8 -0
- package/src/surfaces/publish-quick.json +428 -0
- package/src/surfaces/publish-quick.ts +165 -0
- package/src/surfaces/publish-workspace.json +2892 -0
- package/src/surfaces/publish-workspace.ts +391 -0
- package/src/surfaces/rail.json +1 -159
- package/src/surfaces/rail.ts +18 -75
- package/src/surfaces/schema-form.json +10 -2
- package/src/surfaces/schema-form.ts +2 -0
- package/src/surfaces/seo.json +1 -1
- package/src/surfaces/settings-contributed.json +5 -5
- package/src/surfaces/settings-contributed.ts +18 -2
- package/src/surfaces/settings-css-vars.json +44 -36
- package/src/surfaces/settings-css-vars.ts +77 -4
- package/src/surfaces/settings-deploy.json +2 -15
- package/src/surfaces/settings-deploy.ts +1 -1
- package/src/surfaces/settings-dialog.json +51 -0
- package/src/surfaces/settings-dialog.ts +169 -0
- package/src/surfaces/settings-overview.json +3 -3
- package/src/surfaces/settings-overview.ts +9 -2
- package/src/surfaces/settings-pane.json +269 -46
- package/src/surfaces/settings-pane.ts +85 -24
- package/src/surfaces/shell.json +2 -1
- package/src/surfaces/site-panel.json +1029 -0
- package/src/surfaces/site-panel.ts +233 -0
- package/src/surfaces/slash-menu.json +63 -21
- package/src/surfaces/slash-menu.ts +23 -0
- package/src/surfaces/statusbar.ts +39 -15
- package/src/surfaces/styles-panel.json +735 -0
- package/src/surfaces/styles-panel.ts +195 -0
- package/src/surfaces/styles-variables.json +149 -0
- package/src/surfaces/styles-variables.ts +145 -0
- package/src/surfaces/tab-strip.json +4 -4
- package/src/surfaces/welcome.ts +1 -1
- package/src/surfaces/writing-banner.json +94 -0
- package/src/surfaces/writing-banner.ts +80 -0
- package/src/tabs/bare-repeaters.ts +101 -0
- package/src/tabs/tab.ts +47 -7
- package/src/types.ts +21 -26
- package/src/ui/form-controls.ts +47 -8
- package/src/ui/layers.ts +13 -0
- package/src/ui/media-picker.ts +284 -40
- package/src/ui/regions.ts +7 -6
- package/src/ui/schema-form.ts +259 -27
- package/src/ui/virtual-window.ts +26 -1
- package/src/utils/base64.ts +3 -3
- package/src/utils/edit-display.ts +322 -67
- package/src/utils/local-day.ts +18 -0
- package/src/workspace/pane-derive.ts +4 -4
- package/src/workspace/session.ts +28 -7
- package/src/workspace/tab-workspace.ts +137 -0
- package/src/workspace/workspace-back.ts +189 -0
- package/src/workspace/workspace-home.ts +133 -0
- package/src/workspace/workspace-ids.ts +129 -0
- package/src/workspace/workspace-switch.ts +372 -0
- package/src/workspace/workspace.ts +125 -11
- package/styles/shell-frame.css +30 -7
- package/styles/shell-frame.json +15 -3
- package/dist/chunks/2020-f2gkpy8d.js +0 -4
- package/dist/chunks/adapter-4912g339.js +0 -4
- package/dist/chunks/cf-account-picker-wccaenh6.js +0 -4
- package/dist/chunks/cf-settings-br6105tr.js +0 -4
- package/dist/chunks/color-28ksk2qm.js +0 -4
- package/dist/chunks/components-db68vsn7.js +0 -4
- package/dist/chunks/content-source-1449qesq.js +0 -4
- package/dist/chunks/convert-to-repeater-5h457egj.js +0 -4
- package/dist/chunks/editor-x9jn86a7.js +0 -4
- package/dist/chunks/entry-commands-may24cpt.js +0 -4
- package/dist/chunks/extension-sections-pvr14vxr.js +0 -4
- package/dist/chunks/file-ops-x9v54pcj.js +0 -4
- package/dist/chunks/files-j3knqf0s.js +0 -4
- package/dist/chunks/format-host-tyre2trb.js +0 -4
- package/dist/chunks/fs-events-64ma9htc.js +0 -4
- package/dist/chunks/git-panel-84ps5dex.js +0 -4
- package/dist/chunks/iframe-entry-fvbk89gm.js +0 -5
- package/dist/chunks/iframe-host-ck6vejt5.js +0 -4
- package/dist/chunks/index-b8xw3vy9.js +0 -4
- package/dist/chunks/jsonMode-w15cmrcm.js +0 -13
- package/dist/chunks/jx-validate-at3zn8wa.js +0 -4
- package/dist/chunks/layers-h4xp1pss.js +0 -4
- package/dist/chunks/layers-panel-m5hw1d7g.js +0 -4
- package/dist/chunks/lit-html-8t8t3dnr.js +0 -4
- package/dist/chunks/media-picker-2cweexc5.js +0 -4
- package/dist/chunks/menu-ynw13y0s.js +0 -4
- package/dist/chunks/monaco-buffer-qzxn567r.js +0 -4
- package/dist/chunks/monaco-setup-gxf6656g.js +0 -4
- package/dist/chunks/notify-cj5zbrs2.js +0 -4
- package/dist/chunks/parse-b7ddhr8m.js +0 -4
- package/dist/chunks/platform-3dfws9js.js +0 -4
- package/dist/chunks/popover-jt2gxmzs.js +0 -4
- package/dist/chunks/publish-panel-1gvxbj21.js +0 -4
- package/dist/chunks/quick-search-0dajrwqg.js +0 -4
- package/dist/chunks/references-49qgt404.js +0 -4
- package/dist/chunks/right-panel-jm1bwe53.js +0 -4
- package/dist/chunks/section-registry-6kwc4fky.js +0 -4
- package/dist/chunks/studio-0rt52vpq.js +0 -5
- package/dist/chunks/studio-18vgbhs5.js +0 -5
- package/dist/chunks/studio-24mccdrj.js +0 -5
- package/dist/chunks/studio-2eh507zk.js +0 -9
- package/dist/chunks/studio-2hcbccfv.js +0 -5
- package/dist/chunks/studio-2jbs3rxv.js +0 -5
- package/dist/chunks/studio-4h8k4dw9.js +0 -5
- package/dist/chunks/studio-5f6n18kx.js +0 -5
- package/dist/chunks/studio-5gthpky6.js +0 -5
- package/dist/chunks/studio-6ep3js6b.js +0 -9
- package/dist/chunks/studio-6wkmf3wz.js +0 -9
- package/dist/chunks/studio-841rf3cg.js +0 -5
- package/dist/chunks/studio-8gmwgheg.js +0 -5
- package/dist/chunks/studio-8qm0ep50.js +0 -5
- package/dist/chunks/studio-924p1tm1.js +0 -6
- package/dist/chunks/studio-a3shpz9y.js +0 -5
- package/dist/chunks/studio-amsbaaar.js +0 -6
- package/dist/chunks/studio-at5spjbc.js +0 -7
- package/dist/chunks/studio-b2xv945e.js +0 -5
- package/dist/chunks/studio-bn5nkafw.js +0 -5
- package/dist/chunks/studio-bw6q5xjf.js +0 -9
- package/dist/chunks/studio-c7q0t9x1.js +0 -5
- package/dist/chunks/studio-camnhc96.js +0 -6
- package/dist/chunks/studio-cffqvnzd.js +0 -5
- package/dist/chunks/studio-efvfrsf8.js +0 -5
- package/dist/chunks/studio-er30bpcx.js +0 -5
- package/dist/chunks/studio-ezscgr64.js +0 -5
- package/dist/chunks/studio-ffrrncvz.js +0 -5
- package/dist/chunks/studio-fpphgn8y.js +0 -10
- package/dist/chunks/studio-j1kvhdjk.js +0 -4
- package/dist/chunks/studio-j430n16g.js +0 -7
- package/dist/chunks/studio-jjkg84nj.js +0 -5
- package/dist/chunks/studio-m0q32ars.js +0 -4
- package/dist/chunks/studio-m6bdst11.js +0 -5
- package/dist/chunks/studio-nv2cptd4.js +0 -64
- package/dist/chunks/studio-nwfrc98n.js +0 -5
- package/dist/chunks/studio-p1wgvp7r.js +0 -5
- package/dist/chunks/studio-pag2wncm.js +0 -5
- package/dist/chunks/studio-qvanvzfd.js +0 -5
- package/dist/chunks/studio-qwa64kt7.js +0 -5
- package/dist/chunks/studio-rk1zc4x3.js +0 -928
- package/dist/chunks/studio-se2r3ptc.js +0 -5
- package/dist/chunks/studio-sg2a0dh0.js +0 -5
- package/dist/chunks/studio-tjzjhe68.js +0 -5
- package/dist/chunks/studio-v2w7q8r1.js +0 -7
- package/dist/chunks/studio-v5vjq1h0.js +0 -4
- package/dist/chunks/studio-v8aga3vp.js +0 -14
- package/dist/chunks/studio-vfcdrfmv.js +0 -5
- package/dist/chunks/studio-vmfkgdjf.js +0 -5
- package/dist/chunks/studio-wt1816jj.js +0 -5
- package/dist/chunks/studio-wz73q5kq.js +0 -4
- package/dist/chunks/studio-y04qtxvp.js +0 -7
- package/dist/chunks/studio-y21g8zzg.js +0 -5
- package/dist/chunks/studio-y64hrt8p.js +0 -12
- package/dist/chunks/studio-ynn90f58.js +0 -16
- package/dist/chunks/studio-yxz682sx.js +0 -5
- package/dist/chunks/studio-zp7snvkq.js +0 -5
- package/dist/chunks/studio-zq4z6tm6.js +0 -5
- package/dist/chunks/toast-c9fn075p.js +0 -4
- package/dist/chunks/tsMode-sf49ee9x.js +0 -14
- package/dist/chunks/workspace-jtfahpee.js +0 -4
- package/src/panels/frontmatter-panel.ts +0 -711
- package/src/panels/git-panel.ts +0 -1108
- package/src/surfaces/doc-header.json +0 -776
- package/src/surfaces/doc-header.ts +0 -222
- package/src/surfaces/git-panel.json +0 -1880
- package/src/surfaces/git-panel.ts +0 -264
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
/**
|
|
3
|
+
* A live preview's root: the shadow root an island shows a rendered document or component in (the
|
|
4
|
+
* Site panel's component cards and the Content home's cards, `specs/studio.md` §5.7 and §9.1.2).
|
|
5
|
+
*
|
|
6
|
+
* A module of its own, apart from `library-preview.ts`, because what a preview IS (the render, the
|
|
7
|
+
* cache, the visibility gate) and where it is SHOWN are separate questions, and the second is plain
|
|
8
|
+
* DOM that every surface hosting a preview answers the same way.
|
|
9
|
+
*
|
|
10
|
+
* @docs studio/interface
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { isFunction } from "@jxsuite/schema/guards";
|
|
14
|
+
import { projectPreviewSheets } from "./preview-style";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The one rule a preview needs that its box cannot give it from outside: an image whose prop
|
|
18
|
+
* defaults to nothing draws a broken-image icon and its alt text, which in a thumbnail is noise,
|
|
19
|
+
* not the component. Everything else about the box (its size, its scale, its light surface) is the
|
|
20
|
+
* surface document's, on the island itself.
|
|
21
|
+
*/
|
|
22
|
+
const PREVIEW_RULES = 'img:not([src]), img[src=""] { visibility: hidden; }';
|
|
23
|
+
|
|
24
|
+
const _previewSheets = new WeakMap<Document, CSSStyleSheet>();
|
|
25
|
+
|
|
26
|
+
/** The preview rules as a sheet of `doc`'s own (a constructed sheet is adoptable only there). */
|
|
27
|
+
function previewSheetFor(doc: Document): CSSStyleSheet | null {
|
|
28
|
+
const known = _previewSheets.get(doc);
|
|
29
|
+
if (known) {
|
|
30
|
+
return known;
|
|
31
|
+
}
|
|
32
|
+
const Sheet = doc.defaultView?.CSSStyleSheet;
|
|
33
|
+
if (!isFunction(Sheet)) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const sheet = new Sheet();
|
|
37
|
+
sheet.replaceSync(PREVIEW_RULES);
|
|
38
|
+
_previewSheets.set(doc, sheet);
|
|
39
|
+
return sheet;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Show a rendered preview in its island, inside a shadow root of the island's own.
|
|
44
|
+
*
|
|
45
|
+
* **A preview is a page's part, rendered in Studio's window, and the shadow root is what keeps it a
|
|
46
|
+
* guest there.** It used to be appended straight into the island, so a component's own ids joined
|
|
47
|
+
* Studio's: Elite Equipment Rental's `<h2 id="equipment">` was the document's `#equipment`, an
|
|
48
|
+
* `aria-labelledby` or a fragment link anywhere in the chrome could resolve to a thumbnail, and two
|
|
49
|
+
* cards of one component made the id a duplicate. Ids, `getElementById` and Studio's linked
|
|
50
|
+
* stylesheets all stop at the root's boundary; inherited properties (the island's text colour and
|
|
51
|
+
* size) still cross it, which is what the light document surface relies on.
|
|
52
|
+
*
|
|
53
|
+
* The runtime's rules are not lost: the Jx runtime writes every element's style into sheets it
|
|
54
|
+
* adopts on the document (`openSink` in `@jxsuite/runtime`), keyed on each element's `data-jx`
|
|
55
|
+
* hash, and those sheets are adopted into the root too, so a component draws as it did. They are
|
|
56
|
+
* read at each fill, so a sheet the runtime opened since the last one is included.
|
|
57
|
+
*
|
|
58
|
+
* @param slot The island the surface document drew empty.
|
|
59
|
+
* @param rendered The preview, from `previewFor` (`library-preview.ts`).
|
|
60
|
+
*/
|
|
61
|
+
export function mountPreview(slot: HTMLElement, rendered: HTMLElement): void {
|
|
62
|
+
const root = slot.shadowRoot ?? slot.attachShadow({ mode: "open" });
|
|
63
|
+
const own = previewSheetFor(slot.ownerDocument);
|
|
64
|
+
/* The project's sheets first, the runtime's after them: on the page, the site's stylesheet is
|
|
65
|
+
in the document and the runtime's rules are adopted after it, so a component's own rule wins
|
|
66
|
+
over a site rule of equal specificity there, and must here. */
|
|
67
|
+
root.adoptedStyleSheets = [
|
|
68
|
+
...projectPreviewSheets(),
|
|
69
|
+
...slot.ownerDocument.adoptedStyleSheets,
|
|
70
|
+
...(own ? [own] : []),
|
|
71
|
+
];
|
|
72
|
+
root.replaceChildren(rendered);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** The preview an island is showing, or null while it shows none. */
|
|
76
|
+
export function shownPreview(slot: Element): Element | null {
|
|
77
|
+
return slot.shadowRoot?.firstElementChild ?? null;
|
|
78
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
/**
|
|
3
|
+
* The project's stylesheet, as a live preview's root adopts it.
|
|
4
|
+
*
|
|
5
|
+
* A component card or a page card in the Site panel and the Content home draws a part of a page in
|
|
6
|
+
* Studio's own window, inside a shadow root of its box (`preview-root.ts`). It drew that part with
|
|
7
|
+
* the runtime's rules alone: none of the site's tokens, typography or linked stylesheets, which is
|
|
8
|
+
* where most of a component's look lives, so a museum card or a site header drew as an empty white
|
|
9
|
+
* box. A page draws with two things this module supplies: `project.json`'s `style`, emitted by the
|
|
10
|
+
* builder the canvas and the build share (`@jxsuite/site/site-style`), and the stylesheets the
|
|
11
|
+
* project's `$head` links.
|
|
12
|
+
*
|
|
13
|
+
* Both address the page's `:root` and `body`, which a shadow root does not have: inside it the box
|
|
14
|
+
* the preview is drawn in is `:host`. The project block is emitted with `:host` as its root and
|
|
15
|
+
* body, and a linked sheet's own `:root`, `html` and `body` selectors are re-pointed at `:host`
|
|
16
|
+
* through the CSSOM, rule by rule, so a site's custom properties and body typography reach the
|
|
17
|
+
* preview the way they reach the page. A web font is the one thing that does not: `@font-face` is
|
|
18
|
+
* not honoured inside a shadow root, so a preview draws in the fallback face.
|
|
19
|
+
*
|
|
20
|
+
* Built once per project configuration and shared by every preview of it.
|
|
21
|
+
*
|
|
22
|
+
* @docs studio/interface
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { buildSiteStyleCSS } from "@jxsuite/site/site-style";
|
|
26
|
+
import { isFunction, isNonNullObject, isString } from "@jxsuite/schema/guards";
|
|
27
|
+
import { previewAssetSrcFor } from "../canvas/asset-refs";
|
|
28
|
+
import { projectState } from "../store";
|
|
29
|
+
import type { JxHeadEntry, ProjectConfig } from "@jxsuite/schema/types";
|
|
30
|
+
|
|
31
|
+
/** The preview box, as a project sheet names the page's root and body inside a shadow root. */
|
|
32
|
+
const HOST_ROOTS = { body: ":host", root: ":host" };
|
|
33
|
+
|
|
34
|
+
/** Every sheet built for a configuration, settled or in flight. */
|
|
35
|
+
const _sheets = new WeakMap<ProjectConfig, Promise<CSSStyleSheet[]>>();
|
|
36
|
+
/** The settled answers, for the synchronous mount. */
|
|
37
|
+
const _settled = new WeakMap<ProjectConfig, CSSStyleSheet[]>();
|
|
38
|
+
|
|
39
|
+
/** A selector of the page's root or body re-pointed at the preview box; `null` when unchanged. */
|
|
40
|
+
export function hostSelector(selector: string): string | null {
|
|
41
|
+
const rewritten = selector
|
|
42
|
+
.replaceAll(/:root\b/g, ":host")
|
|
43
|
+
.replaceAll(/(^|[\s,>+~(])(?:html|body)(?![\w-])/g, "$1:host")
|
|
44
|
+
.replaceAll(/:host(?:\s*>?\s*:host)+/g, ":host");
|
|
45
|
+
return rewritten === selector ? null : rewritten;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** What holds rules: a sheet, or a grouping rule (`@media`, `@supports`, a nesting style rule). */
|
|
49
|
+
type RuleContainer = CSSStyleSheet | CSSGroupingRule;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Re-point every style rule under `container` (at any depth of grouping or nesting) at the box.
|
|
53
|
+
*
|
|
54
|
+
* A rule is REPLACED by its own text under the new selector rather than assigned a new
|
|
55
|
+
* `selectorText`: the assignment is settable in browsers but not in every CSSOM, and replacing it
|
|
56
|
+
* keeps its declarations, its nested rules and its place in source order either way. A rewritten
|
|
57
|
+
* selector the engine cannot parse keeps the rule as it was.
|
|
58
|
+
*/
|
|
59
|
+
function rehostRules(container: RuleContainer): void {
|
|
60
|
+
for (let index = 0; index < container.cssRules.length; index += 1) {
|
|
61
|
+
const rule = container.cssRules[index];
|
|
62
|
+
const rewritten = rule instanceof CSSStyleRule ? hostSelector(rule.selectorText) : null;
|
|
63
|
+
if (rule instanceof CSSStyleRule && rewritten !== null) {
|
|
64
|
+
const text = `${rewritten}${rule.cssText.slice(rule.cssText.indexOf("{"))}`;
|
|
65
|
+
try {
|
|
66
|
+
container.insertRule(text, index);
|
|
67
|
+
container.deleteRule(index + 1);
|
|
68
|
+
} catch {
|
|
69
|
+
// Unparseable under the new selector: the original stays.
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const current = container.cssRules[index];
|
|
73
|
+
if (current instanceof CSSGroupingRule) {
|
|
74
|
+
rehostRules(current);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** The stylesheet `href`s the project's `$head` links, in order. */
|
|
80
|
+
export function headStylesheetHrefs(head: readonly JxHeadEntry[] | undefined): string[] {
|
|
81
|
+
const hrefs: string[] = [];
|
|
82
|
+
for (const entry of head ?? []) {
|
|
83
|
+
if (!isNonNullObject(entry) || String(entry.tagName).toLowerCase() !== "link") {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const { href, rel } = entry.attributes ?? {};
|
|
87
|
+
if (isString(href) && href !== "" && isString(rel) && rel.split(/\s+/).includes("stylesheet")) {
|
|
88
|
+
hrefs.push(href);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return hrefs;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** One linked stylesheet as a preview sheet, or null when it cannot be read. */
|
|
95
|
+
async function linkedSheet(href: string): Promise<CSSStyleSheet | null> {
|
|
96
|
+
const url = previewAssetSrcFor(href, "project.json");
|
|
97
|
+
try {
|
|
98
|
+
const response = await fetch(url);
|
|
99
|
+
if (!response.ok) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
const absolute = new URL(url, location.href).href;
|
|
103
|
+
// Its own URL as the base, so the sheet's relative `url()` references resolve as they do on the
|
|
104
|
+
// Page and not against Studio's address.
|
|
105
|
+
const sheet = new CSSStyleSheet({ baseURL: absolute });
|
|
106
|
+
sheet.replaceSync(await response.text());
|
|
107
|
+
rehostRules(sheet);
|
|
108
|
+
return sheet;
|
|
109
|
+
} catch {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Build every sheet for one configuration: the linked sheets in `$head` order, then the block. */
|
|
115
|
+
async function buildSheets(config: ProjectConfig): Promise<CSSStyleSheet[]> {
|
|
116
|
+
const linked = await Promise.all(
|
|
117
|
+
headStylesheetHrefs(config.$head).map((href) => linkedSheet(href)),
|
|
118
|
+
);
|
|
119
|
+
const sheets = linked.filter((sheet): sheet is CSSStyleSheet => sheet !== null);
|
|
120
|
+
const { style } = config;
|
|
121
|
+
if (isNonNullObject(style)) {
|
|
122
|
+
const block = new CSSStyleSheet();
|
|
123
|
+
block.replaceSync(
|
|
124
|
+
buildSiteStyleCSS(style, config.$media ?? {}, (value) => value, undefined, HOST_ROOTS),
|
|
125
|
+
);
|
|
126
|
+
sheets.push(block);
|
|
127
|
+
}
|
|
128
|
+
return sheets;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Read the open project's preview sheets, building them on first ask. A preview awaits this before
|
|
133
|
+
* it is shown, so {@link projectPreviewSheets} has the answer by the time a box is filled.
|
|
134
|
+
*/
|
|
135
|
+
export function loadProjectPreviewSheets(): Promise<CSSStyleSheet[]> {
|
|
136
|
+
const config = projectState?.projectConfig;
|
|
137
|
+
if (!config || !isFunction(globalThis.CSSStyleSheet)) {
|
|
138
|
+
return Promise.resolve([]);
|
|
139
|
+
}
|
|
140
|
+
let pending = _sheets.get(config);
|
|
141
|
+
if (!pending) {
|
|
142
|
+
pending = buildSheets(config).then((sheets) => {
|
|
143
|
+
_settled.set(config, sheets);
|
|
144
|
+
return sheets;
|
|
145
|
+
});
|
|
146
|
+
_sheets.set(config, pending);
|
|
147
|
+
}
|
|
148
|
+
return pending;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** The open project's preview sheets as far as they are built: none until the first read lands. */
|
|
152
|
+
export function projectPreviewSheets(): readonly CSSStyleSheet[] {
|
|
153
|
+
const config = projectState?.projectConfig;
|
|
154
|
+
return (config && _settled.get(config)) ?? [];
|
|
155
|
+
}
|
package/src/canvas/asset-refs.ts
CHANGED
|
@@ -97,10 +97,25 @@ export function assetContextFor(
|
|
|
97
97
|
* @returns {string} A src the parent realm can load
|
|
98
98
|
*/
|
|
99
99
|
export function previewAssetSrc(value: string): string {
|
|
100
|
+
return previewAssetSrcFor(value, activeTab.value?.documentPath);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* {@link previewAssetSrc} for a value authored in a NAMED document rather than the focused one.
|
|
105
|
+
*
|
|
106
|
+
* A project-level surface (Project Settings › Overview previewing the `$head` favicon of
|
|
107
|
+
* `project.json`) is about the project whatever tab is in front, so it names its document instead
|
|
108
|
+
* of asking which one has the focus.
|
|
109
|
+
*
|
|
110
|
+
* @param {string} value - The reference as the author wrote it
|
|
111
|
+
* @param {string | null | undefined} documentPath - Project-relative path of the authoring document
|
|
112
|
+
* @returns {string} A src the parent realm can load
|
|
113
|
+
*/
|
|
114
|
+
export function previewAssetSrcFor(value: string, documentPath: string | null | undefined): string {
|
|
100
115
|
if (!value) {
|
|
101
116
|
return value;
|
|
102
117
|
}
|
|
103
|
-
const ctx = assetContextFor(
|
|
118
|
+
const ctx = assetContextFor(documentPath, hostAssetDeclarations());
|
|
104
119
|
const versioned = ctx && { ...ctx, versions: assetVersionsSnapshot() };
|
|
105
120
|
return loopbackAssetSrc(resolveAssetRef(value, versioned) ?? value);
|
|
106
121
|
}
|
|
@@ -7,13 +7,20 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { projectState, stripEventHandlers } from "../store";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
displayTagName,
|
|
12
|
+
isJsonObject,
|
|
13
|
+
isMappedArray,
|
|
14
|
+
isNonNullObject,
|
|
15
|
+
isString,
|
|
16
|
+
} from "@jxsuite/schema/guards";
|
|
11
17
|
import { canvasModeOfTab } from "./canvas-surface";
|
|
12
18
|
import { toRaw } from "../reactivity";
|
|
13
19
|
import {
|
|
14
20
|
distributePageIntoLayout,
|
|
15
21
|
getEffectiveElements,
|
|
16
22
|
getEffectiveHead,
|
|
23
|
+
extensionClassPaths,
|
|
17
24
|
getEffectiveImports,
|
|
18
25
|
getEffectiveLayoutPath,
|
|
19
26
|
getEffectiveMedia,
|
|
@@ -21,6 +28,9 @@ import {
|
|
|
21
28
|
} from "../site-context";
|
|
22
29
|
import { documentBase } from "./canvas-origin";
|
|
23
30
|
import { componentRegistry, computeRelativePath } from "../files/components";
|
|
31
|
+
import { collectUsedTags } from "@jxsuite/schema/component-meta";
|
|
32
|
+
import { injectContext } from "@jxsuite/site/context";
|
|
33
|
+
import { documentUrlPattern } from "@jxsuite/site/routes";
|
|
24
34
|
import { prepareForEditMode } from "../utils/edit-display";
|
|
25
35
|
import {
|
|
26
36
|
paramBoundStateKeys,
|
|
@@ -29,9 +39,22 @@ import {
|
|
|
29
39
|
} from "../page-params";
|
|
30
40
|
import { isComponentDoc, substitutePreviewProps } from "../component-props";
|
|
31
41
|
import { assetContextFor, hostAssetDeclarations } from "./asset-refs";
|
|
42
|
+
import { collectionForFile } from "../content/collection-match";
|
|
43
|
+
import { writesEntryOnCanvas } from "../content/content-collections";
|
|
44
|
+
import { collectionPage, entryLayoutPath, entryLocale } from "../content/collection-pages";
|
|
45
|
+
import { pageContextFor } from "./canvas-page-context";
|
|
46
|
+
import { loadExtensions } from "../format/format-host";
|
|
47
|
+
import { bakeRepeaterSources, extensionClassKeys, repeaterSourceKeys } from "./repeater-sources";
|
|
32
48
|
|
|
33
49
|
import type { AssetContext } from "./asset-refs";
|
|
34
|
-
import type {
|
|
50
|
+
import type {
|
|
51
|
+
JsonValue,
|
|
52
|
+
JxDocument,
|
|
53
|
+
JxElement,
|
|
54
|
+
JxMutableNode,
|
|
55
|
+
JxPath,
|
|
56
|
+
JxStyle,
|
|
57
|
+
} from "@jxsuite/schema/types";
|
|
35
58
|
import type { ComponentEntry } from "../files/components.js";
|
|
36
59
|
import type { LayoutMarker } from "./path-mapping";
|
|
37
60
|
import type { Tab } from "../tabs/tab";
|
|
@@ -112,6 +135,115 @@ export function markLayoutNodes(node: JxMutableNode, file: string, path: JxPath
|
|
|
112
135
|
}
|
|
113
136
|
}
|
|
114
137
|
|
|
138
|
+
/**
|
|
139
|
+
* A layout as the canvas wraps a document in it: read, its nodes marked with the file they come
|
|
140
|
+
* from, and itself wrapped in the layout ITS `$layout` names, all the way up.
|
|
141
|
+
*
|
|
142
|
+
* A layout can sit in another layout (`layouts/post.json` → `layouts/base.json`), and the build
|
|
143
|
+
* resolves the whole chain (`@jxsuite/site` `resolveLayout`), so a page drawn in the inner layout
|
|
144
|
+
* alone lost the outer one's nav and footer on the canvas and nowhere else. Each level is merged
|
|
145
|
+
* the way the build merges it, and each node keeps the marker of the file it was authored in, so
|
|
146
|
+
* opening a locked node still opens the layout that holds it. A cycle stops at the first repeat
|
|
147
|
+
* rather than recursing forever, and a parent that cannot be read leaves the chain where it is.
|
|
148
|
+
*
|
|
149
|
+
* @param {string} layoutPath - The `$layout` reference, project-relative as authored
|
|
150
|
+
* @param {Set<string>} [seen] - Files already on the chain
|
|
151
|
+
* @returns {Promise<JxMutableNode | null>} The merged, marked layout, or null when unreadable
|
|
152
|
+
*/
|
|
153
|
+
export async function resolveCanvasLayout(
|
|
154
|
+
layoutPath: string,
|
|
155
|
+
seen = new Set<string>(),
|
|
156
|
+
): Promise<JxMutableNode | null> {
|
|
157
|
+
const file = layoutPath.replace(/^\.\//, "");
|
|
158
|
+
if (seen.has(file)) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
seen.add(file);
|
|
162
|
+
const layoutDoc = await resolveLayoutDoc(layoutPath);
|
|
163
|
+
if (!layoutDoc) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
// The SAME normalization resolveLayoutDoc reads the file with, so the marker's `file` is a path
|
|
167
|
+
// The editor can hand straight to navigateToComponent when the author asks to open it.
|
|
168
|
+
markLayoutNodes(layoutDoc, file);
|
|
169
|
+
const parentRef = layoutDoc.$layout;
|
|
170
|
+
if (!isString(parentRef) || !parentRef) {
|
|
171
|
+
return layoutDoc;
|
|
172
|
+
}
|
|
173
|
+
const parent = await resolveCanvasLayout(parentRef, seen);
|
|
174
|
+
if (!parent) {
|
|
175
|
+
return layoutDoc;
|
|
176
|
+
}
|
|
177
|
+
const merged = distributePageIntoLayout(parent, layoutDoc);
|
|
178
|
+
delete merged.$layout;
|
|
179
|
+
return merged;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Re-address a layout's `$elements` imports from the layout's file to the document being drawn.
|
|
184
|
+
*
|
|
185
|
+
* A layout's `{ $ref: "../components/site-nav.json" }` is relative to the LAYOUT, but once the
|
|
186
|
+
* layout is merged around a document the canvas resolves every `$ref` against the document's own
|
|
187
|
+
* base. A page in `pages/` sits as deep as `layouts/`, so the two answers agreed by coincidence; an
|
|
188
|
+
* entry in `content/menu/` or a page in `pages/blog/` resolved the same ref to
|
|
189
|
+
* `content/components/…`, which 404s and leaves the nav and footer unregistered. Each entry is
|
|
190
|
+
* re-addressed from the file its `$__layout` marker names, which is the file it was authored in at
|
|
191
|
+
* every level of a layout chain. Bare specifiers and URLs are left alone, and so is an entry with
|
|
192
|
+
* no marker (the document's own).
|
|
193
|
+
*
|
|
194
|
+
* @param {(JxElement | string)[] | undefined} elements - The merged document's `$elements`
|
|
195
|
+
* @param {string} documentPath - The project-relative path of the document being drawn
|
|
196
|
+
*/
|
|
197
|
+
export function rebaseLayoutElementRefs(
|
|
198
|
+
elements: readonly (JxElement | string | null)[] | undefined,
|
|
199
|
+
documentPath: string,
|
|
200
|
+
) {
|
|
201
|
+
for (const el of elements ?? []) {
|
|
202
|
+
if (!isNonNullObject(el) || !isString(el.$ref) || !/^\.\.?\//.test(el.$ref)) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
const marker = el["$__layout"];
|
|
206
|
+
if (!isJsonObject(marker) || !isString(marker.file)) {
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const target = new URL(el.$ref, `jx-project:/${marker.file}`).pathname.replace(/^\//, "");
|
|
210
|
+
el.$ref = computeRelativePath(documentPath, target);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* A document's own layout override: its root's `$layout`, or a Markdown document's frontmatter
|
|
216
|
+
* `$layout` (which the build reads, and which the Inspector's Page tab writes); `undefined` when it
|
|
217
|
+
* names none.
|
|
218
|
+
*/
|
|
219
|
+
export function pageLayout(doc: JxMutableNode, tab: Tab | null): string | false | undefined {
|
|
220
|
+
if (doc.$layout !== undefined) {
|
|
221
|
+
return doc.$layout;
|
|
222
|
+
}
|
|
223
|
+
const fromFrontmatter = tab?.doc.content.frontmatter.$layout;
|
|
224
|
+
return isString(fromFrontmatter) || fromFrontmatter === false ? fromFrontmatter : undefined;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* The layout a collection entry is drawn in (studio.md §22.5): the entry's own `$layout` (on its
|
|
229
|
+
* document, or in its frontmatter for a Markdown entry, {@link pageLayout}), else its collection's
|
|
230
|
+
* template page's `$layout`, else the project's `defaults.layout`. `null` when none applies.
|
|
231
|
+
*
|
|
232
|
+
* The template PAGE's own body is not spliced around the entry: a page that binds the entry into a
|
|
233
|
+
* wrapper of its own shows that wrapper only in Preview of the page itself, because the edit
|
|
234
|
+
* transforms cannot map the entry's paths through the page's bound node.
|
|
235
|
+
*/
|
|
236
|
+
export async function entryLayout(
|
|
237
|
+
doc: JxMutableNode,
|
|
238
|
+
tab: Tab | null,
|
|
239
|
+
path: string | null | undefined,
|
|
240
|
+
): Promise<string | null> {
|
|
241
|
+
const own = pageLayout(doc, tab);
|
|
242
|
+
const match = path ? collectionForFile(path) : null;
|
|
243
|
+
const page = match ? await collectionPage(match.name, entryLocale(path)) : null;
|
|
244
|
+
return entryLayoutPath(own, page);
|
|
245
|
+
}
|
|
246
|
+
|
|
115
247
|
/**
|
|
116
248
|
* Resolve a document into the form the iframe canvas renders: layout-distributed, edit-transformed,
|
|
117
249
|
* with components/imports/$media/$head merged in, plus the path-mapper context and site style. This
|
|
@@ -176,24 +308,35 @@ export async function resolveCanvasDocument(
|
|
|
176
308
|
S.documentPath &&
|
|
177
309
|
projectState?.isSiteProject &&
|
|
178
310
|
(S.documentPath.startsWith("pages/") || S.documentPath.startsWith("./pages/"));
|
|
311
|
+
/* A collection entry written on the canvas is drawn the way a page is: inside a layout, with the
|
|
312
|
+
layout's nodes locked and the entry's own tree the editable region (studio.md §22.5). */
|
|
313
|
+
const isEntry =
|
|
314
|
+
!isPage && Boolean(projectState?.isSiteProject) && writesEntryOnCanvas(S.documentPath);
|
|
179
315
|
let pageContentPrefix: (string | number)[] | null = null;
|
|
180
316
|
let pageContentOffset = 0;
|
|
181
317
|
|
|
182
318
|
// Layout wrapping obeys the tab-bar's "show layout elements" toggle (default on); with it off,
|
|
183
319
|
// The page renders alone — the unwrapped path is identical to a non-layout page.
|
|
184
|
-
if (isPage && tab?.session.ui.showLayout !== false) {
|
|
185
|
-
const layoutPath =
|
|
320
|
+
if ((isPage || isEntry) && tab?.session.ui.showLayout !== false) {
|
|
321
|
+
const layoutPath = isEntry
|
|
322
|
+
? await entryLayout(doc, tab, S.documentPath)
|
|
323
|
+
: getEffectiveLayoutPath(pageLayout(doc, tab));
|
|
186
324
|
if (layoutPath) {
|
|
187
|
-
const layoutDoc = await
|
|
325
|
+
const layoutDoc = await resolveCanvasLayout(layoutPath);
|
|
188
326
|
if (layoutDoc) {
|
|
189
|
-
// The SAME normalization resolveLayoutDoc reads the file with, so the marker's `file` is a
|
|
190
|
-
// Path the editor can hand straight to navigateToComponent when the author asks to open it.
|
|
191
|
-
markLayoutNodes(layoutDoc, layoutPath.replace(/^\.\//, ""));
|
|
192
327
|
const pageForSlots = canvasMode === "preview" ? structuredClone(toRaw(doc)) : renderDoc;
|
|
193
328
|
const merged = distributePageIntoLayout(layoutDoc, pageForSlots);
|
|
194
329
|
renderDoc =
|
|
195
330
|
canvasMode === "preview" ? merged : prepareForEditMode(stripEventHandlers(merged));
|
|
196
331
|
layoutWrapped = true;
|
|
332
|
+
if (S.documentPath) {
|
|
333
|
+
/* SAFETY: a document's `$elements` entries are tag-name strings, `{ $ref }` imports or
|
|
334
|
+
inline element definitions (a hand-edited null among them is skipped by the walk). */
|
|
335
|
+
rebaseLayoutElementRefs(
|
|
336
|
+
renderDoc.$elements as (JxElement | string | null)[] | undefined,
|
|
337
|
+
S.documentPath,
|
|
338
|
+
);
|
|
339
|
+
}
|
|
197
340
|
const pageContent = findPageContentPrefix(merged);
|
|
198
341
|
pageContentPrefix = pageContent?.prefix ?? null;
|
|
199
342
|
pageContentOffset = pageContent?.offset ?? 0;
|
|
@@ -201,6 +344,24 @@ export async function resolveCanvasDocument(
|
|
|
201
344
|
}
|
|
202
345
|
}
|
|
203
346
|
|
|
347
|
+
/* `$site` / `$page`, and the project's own state, exactly as the build injects them — a layout
|
|
348
|
+
that binds `${state.$page.url}` (a header marking its current link) threw on the canvas, and in
|
|
349
|
+
Preview, where templates are live, that one TypeError blanked the whole page. Onto COPIES of
|
|
350
|
+
`state` and `imports`: the edit-mode render doc shares both with the tab's source document,
|
|
351
|
+
which must not gain injected keys it would then save. */
|
|
352
|
+
const projectConfig = projectState?.projectConfig;
|
|
353
|
+
if (isPage && projectConfig) {
|
|
354
|
+
renderDoc = { ...renderDoc, state: { ...renderDoc.state } };
|
|
355
|
+
if (renderDoc.imports) {
|
|
356
|
+
renderDoc.imports = { ...renderDoc.imports };
|
|
357
|
+
}
|
|
358
|
+
/* SAFETY: a page render document is a JxDocument in all but its declared (mutable) type;
|
|
359
|
+
`injectContext` writes `state`, `$media` and `imports`, all of which the copy above owns. */
|
|
360
|
+
injectContext(renderDoc as JxDocument, projectConfig, {
|
|
361
|
+
urlPattern: documentUrlPattern(S.documentPath),
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
|
|
204
365
|
const fileBase = documentBase(projectState?.projectRoot);
|
|
205
366
|
const docBase = S.documentPath ? new URL(S.documentPath, fileBase).href : undefined;
|
|
206
367
|
/*
|
|
@@ -230,6 +391,40 @@ export async function resolveCanvasDocument(
|
|
|
230
391
|
}
|
|
231
392
|
}
|
|
232
393
|
|
|
394
|
+
// `$site` and `$page`, as the build injects them (canvas-page-context.ts), in every mode: Preview
|
|
395
|
+
// Draws the page as it ships, and edit mode evaluates a component's bound props live. For a page
|
|
396
|
+
// This refines the pair injected above with the chosen route params and the project's i18n, and
|
|
397
|
+
// It is the only injection a collection entry gets.
|
|
398
|
+
if ((isPage || isEntry) && S.documentPath) {
|
|
399
|
+
const context = await pageContextFor(
|
|
400
|
+
{
|
|
401
|
+
documentPath: S.documentPath,
|
|
402
|
+
fields: isEntry ? (tab?.doc.content.frontmatter ?? null) : null,
|
|
403
|
+
isEntry,
|
|
404
|
+
lang: doc.$lang,
|
|
405
|
+
params: tab?.session.ui.previewParams ?? {},
|
|
406
|
+
title: doc.title,
|
|
407
|
+
},
|
|
408
|
+
projectState?.projectConfig,
|
|
409
|
+
);
|
|
410
|
+
if (context) {
|
|
411
|
+
// A rebuild, not a write: the render doc shares nodes with the tab's source document.
|
|
412
|
+
renderDoc = { ...renderDoc, state: { ...renderDoc.state, ...context } };
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/* Class-backed state resolved before the render rather than by it (repeater-sources.ts): in every
|
|
417
|
+
mode, an entry naming an enabled extension's class by a bare `$prototype`, as the build
|
|
418
|
+
resolves it; in Edit and Design, also the collections a repeater reads, whose first item draws
|
|
419
|
+
the repeater's template. */
|
|
420
|
+
const extensions = await loadExtensions();
|
|
421
|
+
const classes = extensionClassPaths(extensions);
|
|
422
|
+
const bakeKeys = extensionClassKeys(renderDoc, classes);
|
|
423
|
+
if (canvasMode !== "preview") {
|
|
424
|
+
bakeKeys.push(...repeaterSourceKeys(doc));
|
|
425
|
+
}
|
|
426
|
+
renderDoc = await bakeRepeaterSources(renderDoc, [...new Set(bakeKeys)], docBase, classes);
|
|
427
|
+
|
|
233
428
|
// Component definition docs (non-page): seed chosen test-prop values into the render doc's state
|
|
234
429
|
// So a non-instantiated component previews with real data — templates, dataScope snapshots, and
|
|
235
430
|
// Live/snapshot expression previews all see the values (M6, the previewParams mirror). Pure
|
|
@@ -302,28 +497,25 @@ export async function resolveCanvasDocument(
|
|
|
302
497
|
// A null entry in a document's `$elements` names nothing, so it contributes no ref.
|
|
303
498
|
effectiveElements.map((e: JxElement | string) => (isNonNullObject(e) ? e.$ref : e)),
|
|
304
499
|
);
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}
|
|
321
|
-
}
|
|
500
|
+
/* Every tag the render can reach: the document's own, then — through the registry's `uses` —
|
|
501
|
+
each component's, transitively. Components address one another by bare `tagName` and declare
|
|
502
|
+
no `$elements` (the build finds them project-wide), so a tag that only appears INSIDE a
|
|
503
|
+
component (a card's panel, a header's theme toggle) was never registered here and rendered as
|
|
504
|
+
an empty, unstyled element. */
|
|
505
|
+
const byTag = new Map(componentRegistry.map((c: ComponentEntry) => [c.tagName, c]));
|
|
506
|
+
/* SAFETY: a render document is JSON by construction (it crosses into the canvas realm by
|
|
507
|
+
`postMessage`); the walk only reads `tagName`, `children`, `map` and `cases` off it. */
|
|
508
|
+
const reachable = collectUsedTags(renderDoc as JsonValue);
|
|
509
|
+
if (renderDoc.tagName) {
|
|
510
|
+
reachable.add(displayTagName(renderDoc.tagName));
|
|
511
|
+
}
|
|
512
|
+
for (const tag of reachable) {
|
|
513
|
+
for (const used of byTag.get(tag)?.uses ?? []) {
|
|
514
|
+
reachable.add(used);
|
|
322
515
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
const comp = componentRegistry.find((c: ComponentEntry) => c.tagName === tag);
|
|
516
|
+
}
|
|
517
|
+
for (const tag of reachable) {
|
|
518
|
+
const comp = byTag.get(tag);
|
|
327
519
|
if (comp && comp.source !== "npm" && comp.path) {
|
|
328
520
|
const relPath = computeRelativePath(S.documentPath ?? null, comp.path);
|
|
329
521
|
if (!existingRefs.has(relPath)) {
|
|
@@ -336,7 +528,7 @@ export async function resolveCanvasDocument(
|
|
|
336
528
|
if (effectiveElements.length > 0) {
|
|
337
529
|
renderDoc.$elements = effectiveElements;
|
|
338
530
|
}
|
|
339
|
-
renderDoc.imports = getEffectiveImports(renderDoc.imports);
|
|
531
|
+
renderDoc.imports = getEffectiveImports(renderDoc.imports, extensions);
|
|
340
532
|
// The effective-media/head getters always answer a value: the merge, or an empty one.
|
|
341
533
|
renderDoc.$media = getEffectiveMedia(renderDoc.$media);
|
|
342
534
|
renderDoc.$head = getEffectiveHead(renderDoc.$head);
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
/**
|
|
3
|
-
* Canvas origin derivation. The canvas iframe may load same-origin (dev server / chromium /
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* Canvas origin derivation. The canvas iframe may load same-origin (dev server / chromium / cloud,
|
|
4
|
+
* where the platform canvasUrl is a relative path) or cross-origin (a host whose canvasUrl is an
|
|
5
|
+
* absolute http://127.0.0.1:<port> URL).
|
|
6
6
|
*
|
|
7
7
|
* CanvasBaseOrigin() returns the origin the canvas document lives on, so callers that build
|
|
8
8
|
* absolute asset/doc URLs target the right server. For a relative canvasUrl this resolves to
|
|
9
|
-
* location.origin — IDENTITY for the same-origin paths, so dev/chromium/
|
|
10
|
-
*
|
|
9
|
+
* location.origin — IDENTITY for the same-origin paths, so dev/chromium/cloud are byte-identical to
|
|
10
|
+
* before.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { getPlatform, hasPlatform } from "../platform";
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* The origin serving the canvas document. When the platform registers an absolute canvasUrl
|
|
17
|
-
*
|
|
16
|
+
* The origin serving the canvas document. When the platform registers an absolute canvasUrl (an
|
|
17
|
+
* absolute loopback URL), this is that URL's origin; otherwise it falls back to the parent's own
|
|
18
18
|
* origin (a relative canvasUrl resolves against location.href to location.origin).
|
|
19
19
|
*/
|
|
20
20
|
export function canvasBaseOrigin(): string {
|
|
@@ -25,6 +25,31 @@ export function canvasBaseOrigin(): string {
|
|
|
25
25
|
return location.origin;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* The dev-proxy token for a render in the SHELL's own realm, or null when it has none to use.
|
|
30
|
+
*
|
|
31
|
+
* A desktop server gates `/__jx_resolve__` and `/__jx_server__` on its rpcToken, and the canvas
|
|
32
|
+
* iframe authenticates by reading it off its own URL (`?rpcToken=`). The shell renders documents
|
|
33
|
+
* too (the Library's previews, the assistant's render check) through its own copy of the runtime,
|
|
34
|
+
* and that copy was never told: every `$src` class on a previewed page posted without the token and
|
|
35
|
+
* drew a 403. The token is read off the same canvas URL rather than a second channel, so there is
|
|
36
|
+
* one place it is handed out.
|
|
37
|
+
*
|
|
38
|
+
* Same-origin only. A cross-origin canvas (an absolute loopback canvasUrl) is not where the shell's
|
|
39
|
+
* relative dev-proxy fetches go, so its token would authenticate nothing and is better not spread
|
|
40
|
+
* around.
|
|
41
|
+
*
|
|
42
|
+
* @returns {string | null} The token, or null on a host with no token or a cross-origin canvas.
|
|
43
|
+
*/
|
|
44
|
+
export function hostResolveToken(): string | null {
|
|
45
|
+
const canvasUrl = hasPlatform() ? getPlatform().canvasUrl : undefined;
|
|
46
|
+
if (!canvasUrl) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
const url = new URL(canvasUrl, location.href);
|
|
50
|
+
return url.origin === location.origin ? url.searchParams.get("rpcToken") : null;
|
|
51
|
+
}
|
|
52
|
+
|
|
28
53
|
/**
|
|
29
54
|
* The base the canvas fetches PROJECT FILES against — component `$ref`s, `$src` modules, images.
|
|
30
55
|
*
|
|
@@ -69,11 +94,11 @@ export function documentBase(projectRoot?: string): string {
|
|
|
69
94
|
* the desktop MutationObserver only rewrites asynchronously. Rendering the src loopback-absolute up
|
|
70
95
|
* front eliminates that race for direct-parent <img> sites.
|
|
71
96
|
*
|
|
72
|
-
* Guarded: this ONLY rewrites when a real cross-origin http(s) loopback is registered (
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
97
|
+
* Guarded: this ONLY rewrites when a real cross-origin http(s) loopback is registered (canvasUrl
|
|
98
|
+
* set to an absolute http URL) whose origin differs from location.origin. Otherwise — dev server,
|
|
99
|
+
* chromium, cloud, and the pre-activate window — it returns the ORIGINAL relative path unchanged,
|
|
100
|
+
* keeping those cases byte-identical (an absolute ${location.origin}/... on the shell would just
|
|
101
|
+
* reintroduce views://... — the exact bug).
|
|
77
102
|
*
|
|
78
103
|
* Only for PROJECT asset srcs; NEVER call it for shell-packaged views:// assets (sp-icons, bundled
|
|
79
104
|
* chrome). Already-absolute inputs (data:/blob:/http/views://) are returned untouched, so it is
|