Find Element Call's root by attribute, not by being the body

Six selectors named `body` directly — the gradient backdrop and the
platform font overrides in index.css, and the iOS adjustments in
AppBar.module.css and Modal.module.css — so they only applied when Element
Call owned the page. A host mounting it into a container would have got an
interface decorated correctly and styled incorrectly, with nothing to show
that anything was wrong.

Mark the root element with data-element-call-root and match on that
instead. Scoping this way keeps the selectors more specific than they were,
rather than less: widening them to a bare [data-platform=…] would have
dropped specificity from (0,1,1) to (0,1,0) and changed which rules win.

The platform attribute moves with them, from the initializer's write onto
document.body to a layout effect on the root, alongside the theme — so it
still lands before anything is painted.

No visual change while Element Call owns the page: the root is the body,
which now carries the attribute, so every rewritten selector matches the
element it always did.
This commit is contained in:
Valere
2026-09-03 12:55:52 +02:00
parent 1bfb018d90
commit 856e055d30
7 changed files with 40 additions and 19 deletions
+15
View File
@@ -19,6 +19,7 @@ import {
} from "vitest";
import { useTheme } from "./useTheme";
import { platform } from "./Platform";
import { useUrlParams } from "./UrlParams";
import {
type HostBridge,
@@ -88,6 +89,20 @@ describe("useTheme", () => {
expect(originalClassList.add).not.toHaveBeenCalled();
});
test("marks the element as Element Call's root, for the stylesheets", () => {
renderHook(() => useTheme(), { wrapper });
// The stylesheets find the root by this rather than by naming `body`, so
// that they still apply when Element Call is mounted into a container
expect(document.body.hasAttribute("data-element-call-root")).toBe(true);
});
test("records the platform on the root, for the stylesheets", () => {
renderHook(() => useTheme(), { wrapper });
expect(document.body.getAttribute("data-platform")).toBe(platform);
});
test("theme changes in response to host requests", () => {
renderHook(() => useTheme(), { wrapper });