Dev server: Plugin Studio and the leaf pages own the address too

The dev pages passed no urlOwner, so on the dev server a shell read ?tab=
but never wrote it: a clicked tab was lost on reload and a copied link
opened the first tab. The root page, every /__leaf/ page and the Studio
staging page now own the address, as the built leaves do. A framed leaf
(Studio iframes its map rows) stays unowned, so it never adds entries
to the top page's Back stack.
This commit is contained in:
Doxa Maps 2026-10-03 05:39:23 +00:00
parent 4241609572
commit fba3187cd4
2 changed files with 17 additions and 2 deletions

View file

@ -197,6 +197,16 @@ export function leafRewrite(path, treeName = TREE_NAME) {
return '/__leaf/' + segs.join('/')
}
// urlOwner 'app' (library/composables/useViewAddress.js) for a dev page that is OURS, the rule generate-tree bakes
// into the built leaf: its shell writes ?tab=, so a clicked tab survives a reload and a copied link opens it. A
// FRAMED page drops it: Plugin Studio iframes its map rows from /__leaf/, and a history push from an iframe lands
// in the top page's Back stack. Write the element unowned and put this classic script right after it; it runs
// before the deferred module script upgrades the element. `<` is escaped: profile/instance come from the URL.
export function ownIfTopScript(cfg = {}) {
const owned = JSON.stringify(JSON.stringify({ ...cfg, urlOwner: 'app' })).replace(/</g, '\\u003c')
return `<script>try{if(window.self===window.top)document.currentScript.previousElementSibling.setAttribute('profile-config',${owned})}catch(e){}</script>`
}
export function autoSpaDevPlugin(token = '') {
// One generator for both galleries (internal/generate-gallery.mjs), driven by the same build
// config the built page bakes. What dev changes: the model comes from discovery, the live
@ -365,7 +375,8 @@ export function autoSpaDevPlugin(token = '') {
// renders the SAME view here as in production rather than the bundle's default.
// assetsBase too, as the built leaf's BASE_CONFIG carries it ("../../assets" there; root-absolute
// here, because a /__leaf/ URL's depth differs from the tree's and the pool is served at /assets).
const pc = JSON.stringify(instance ? { profile, instanceId: instance, assetsBase: '/assets' } : { profile, assetsBase: '/assets' })
const leafPc = instance ? { profile, instanceId: instance, assetsBase: '/assets' } : { profile, assetsBase: '/assets' }
const pc = JSON.stringify(leafPc)
// The composition tier of THIS profile, read from the same discovery the gallery uses.
// `nested-elements-mfe` (cap-4) is the StackLayout scroll-stack tier — see the style note
// below. An unknown profile falls through to the fixed-viewport leaf, the safe default.
@ -430,6 +441,7 @@ export function autoSpaDevPlugin(token = '') {
// live 19-bundle tree. Passing the base makes a nested shell see exactly what the top
// level sees. Elements that ignore tree-base simply drop an unknown attribute.
`<${tag} tree-base="/__plugin-gallery" profile-config='${pc}'></${tag}>`,
ownIfTopScript(leafPc),
`<script type="module" src="/plugin-designs/${bundle}/index.js"></script>`,
'</body></html>',
].filter(Boolean).join('\n'))
@ -499,6 +511,7 @@ export function autoSpaDevPlugin(token = '') {
// manifest-shaped model the built tree bakes (19 bundles / 30 profiles), so pointing the
// studio at it gives dev the same tab list production has.
'<plugin-studio tree-base="/__plugin-gallery"></plugin-studio>',
ownIfTopScript(),
'<script type="module" src="/plugin-designs/plugin-studio/index.js"></script>',
'</body></html>',
].filter(Boolean).join('\n'))

View file

@ -35,7 +35,9 @@
real tag; map elements nest as their own SPA. Switch with no page reload.</p>
</div>
<div class="frame">
<plugin-studio id="ps" title="Plugin Studio"></plugin-studio>
<!-- This page is the app, so Studio owns the address: a clicked tab is written to ?tab=,
a reload keeps it and a sent link opens it. The built leaf page bakes the same key. -->
<plugin-studio id="ps" title="Plugin Studio" profile-config='{"urlOwner":"app"}'></plugin-studio>
</div>
</div>