From 69ace3514ef221ef8a097717eb965409eec5d976 Mon Sep 17 00:00:00 2001 From: Lann Martin Date: Mon, 7 Sep 2026 19:58:30 -0400 Subject: [PATCH] Visor: the drawer opens above the strip, in flow The strip always separates visor content from app content, so whatever the visor opens goes on its side of that line and pushes the strip down rather than covering the app. The "strip geometry immobile" gate that justified the overlay in #171 is struck: from design.md M1, the page comment, and the two e2e equality assertions (the 56px height check stays). --- docs/design.md | 4 +-- e2e/run.ts | 24 ++++--------- visor/src/style.rs | 20 +++++------ visor/src/ui.rs | 87 +++++++++++++++++++++++----------------------- web/index.html | 4 +-- 5 files changed, 62 insertions(+), 77 deletions(-) diff --git a/docs/design.md b/docs/design.md index ca4e2e43..77b0a187 100644 --- a/docs/design.md +++ b/docs/design.md @@ -448,8 +448,8 @@ native tests, so browser gates are mandatory for every visor change. - **M0** archive, skeleton, this record, both WIT packages, CI. - **M1** three realms, one TodoMVC: stub kernel with in-memory `tasks`; visor strip + settings sheet; frame loader under policy; ports. - Gates: app renders in the opaque frame; strip geometry immobile with - the app mounted; zero network requests from the frame; `jspi: false`; + Gates: app renders in the opaque frame; zero network requests from + the frame; `jspi: false`; the frame policy's unit tests. (The frame-teardown integration test waits for a hostile fixture component — M2. The path was exercised anyway: the policy caught the TodoMVC example's outbound `href`.) diff --git a/e2e/run.ts b/e2e/run.ts index fd9bfe61..e4adc756 100644 --- a/e2e/run.ts +++ b/e2e/run.ts @@ -1,7 +1,7 @@ // The M1 gates on real Chromium (docs/design.md "Delivery": "Playwright on // real Chromium for every claim about pixels or realms", and "M1": "app -// renders in the opaque frame; strip geometry immobile with the app mounted; -// zero network requests from the frame; no JSPI"). +// renders in the opaque frame; zero network requests from the frame; no +// JSPI"). // // The server sets neither COOP nor COEP: a SharedWorker needs none, and // setting them would make this harness diverge from what a home origin @@ -938,7 +938,6 @@ const scenarios: Scenario[] = [ const page = await open(ctx, origin); await visorReady(page); const strip = page.locator("#visor-strip"); - const before = await strip.boundingBox(); await launchTodoMvc(page); @@ -957,14 +956,10 @@ const scenarios: Scenario[] = [ }); check(!reachable, "the app frame's document was reachable from the page"); - // Wait for the app to have actually painted before measuring: the - // claim is that a MOUNTED app does not move the strip. + // Wait for the app to have actually painted before measuring. await page.frameLocator("#app-zone iframe").locator("input").first() .waitFor({ timeout: 30_000 }); - const after = await strip.boundingBox(); - eq(after, before, "#visor-strip geometry moved when the app mounted"); - const plated = await strip.locator("q").first().textContent(); eq(plated, "TodoMVC", "the strip's left half should plate the app title"); }, @@ -1011,7 +1006,6 @@ const scenarios: Scenario[] = [ async run(ctx, origin) { const page = await open(ctx, origin); await visorReady(page); - const before = await strip(page).boundingBox(); // `apps/hostile` renders one `