diff --git a/packages/core/src/compiler/inlineSubCompositions.test.ts b/packages/core/src/compiler/inlineSubCompositions.test.ts index c86583199..0b1b87898 100644 --- a/packages/core/src/compiler/inlineSubCompositions.test.ts +++ b/packages/core/src/compiler/inlineSubCompositions.test.ts @@ -37,6 +37,16 @@ function makeHostDocument(compId: string) { return document; } +function makeAnonymousHostDocument() { + const { document } = parseHTML(` + +
+
+
+`); + return document; +} + describe("inlineSubCompositions – #ID selector scoping divergence", () => { it.each([ { label: "empty", html: "" }, @@ -154,6 +164,31 @@ describe("inlineSubCompositions – #ID selector scoping divergence", () => { expect(scopedCss).toContain('[data-hf-authored-id="intro"]'); }); + it("preserves the inferred composition boundary for anonymous hosts", () => { + const document = makeAnonymousHostDocument(); + const host = document.querySelector('[data-composition-src="intro.html"]')!; + + function flattenInnerRoot(innerRoot: Element): Element { + const clone = innerRoot.cloneNode(true) as Element; + clone.removeAttribute("id"); + clone.removeAttribute("data-composition-id"); + clone.setAttribute("data-hf-inner-root", "true"); + return clone; + } + + inlineSubCompositions(document, [host], { + resolveHtml: () => SUB_COMP_HTML, + parseHtml: (html) => parseHTML(html).document, + flattenInnerRoot, + }); + + expect(host.getAttribute("data-composition-id")).toBeNull(); + const inferredRoot = host.querySelector('[data-composition-id="intro"]'); + expect(inferredRoot?.getAttribute("data-hf-inner-root")).toBe("true"); + expect(inferredRoot?.getAttribute("id")).toBeNull(); + expect(inferredRoot?.querySelector(".title")?.textContent).toBe("HELLO WORLD"); + }); + it("extracts elements from sub-composition with original rel and crossorigin", () => { const subCompWithLinks = ` diff --git a/packages/core/src/compiler/inlineSubCompositions.ts b/packages/core/src/compiler/inlineSubCompositions.ts index 14e8341dd..24193a0a6 100644 --- a/packages/core/src/compiler/inlineSubCompositions.ts +++ b/packages/core/src/compiler/inlineSubCompositions.ts @@ -357,6 +357,11 @@ export function inlineSubCompositions( for (const child of [...innerRoot.querySelectorAll("style, script")]) child.remove(); if (flattenInnerRoot) { const prepared = flattenInnerRoot(innerRoot); + if (!compId && inferredCompId) { + // Anonymous hosts have no outer composition id, so keep the inferred + // boundary on the preserved inner root after flattenInnerRoot strips it. + prepared.setAttribute("data-composition-id", inferredCompId); + } hostEl.innerHTML = prepared.outerHTML || ""; } else { hostEl.innerHTML = compId ? innerRoot.innerHTML || "" : innerRoot.outerHTML || ""; diff --git a/packages/producer/src/services/htmlCompiler.test.ts b/packages/producer/src/services/htmlCompiler.test.ts index 7f5ed8c31..cf3fdf38b 100644 --- a/packages/producer/src/services/htmlCompiler.test.ts +++ b/packages/producer/src/services/htmlCompiler.test.ts @@ -593,13 +593,15 @@ describe("template-wrapped sub-composition media offsets", () => { join(compositionsDir, "scene.html"), `