mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-10 22:20:14 +00:00
fix(core): scope sub-composition html/body styles to the composition box (#2089)
Sub-composition <head> styles targeting html/body/:root (width/height/ overflow/background) were injected into the parent document unscoped by both the Studio runtime mount (compositionLoader) and the render-time inliner (inlineSubCompositions/htmlBundler). scopeCssToComposition deliberately passed html/body/:root through unchanged, so a sub-composition smaller than the root clobbered the host <body> dimensions and its overflow:hidden clipped the composite to the last sub-comp's size. Only the top-left element painted; everything else (and framework-owned video positioned outside that box) was clipped away. Add a scopeRootSelectors option to scopeCssToComposition that remaps html/body/:root to the composition's own box, and enable it everywhere sub-composition styles are scoped. The universal selector stays untouched. Top-level composition scoping is unchanged (it legitimately owns the document). Covered by new compositionScoping tests.
This commit is contained in:
@@ -247,20 +247,26 @@ export function inlineSubCompositions(
|
||||
}
|
||||
}
|
||||
|
||||
// Scope one sub-composition <style> body. scopeRootSelectors keeps the
|
||||
// sub-comp's html/body/:root rules from clobbering the host document (they
|
||||
// are remapped to the composition box); see compositionScoping.
|
||||
const scopeSubStyle = (raw: string): string => {
|
||||
const css = rewriteCssAssetUrls(raw, src);
|
||||
return scopeCompId
|
||||
? scopeCssToComposition(css, scopeCompId, runtimeScope || undefined, authoredRootId, {
|
||||
compoundAuthoredRoot: compoundAuthoredRoot === true,
|
||||
scopeRootSelectors: true,
|
||||
})
|
||||
: css;
|
||||
};
|
||||
|
||||
// When a sub-composition is a full HTML document (no <template>), styles
|
||||
// and scripts in <head> are not part of contentDoc (which only has body
|
||||
// content). Extract them so backgrounds, positioning, fonts, and library
|
||||
// scripts (e.g. GSAP CDN) are not silently dropped.
|
||||
if (!contentRoot && compDoc.head) {
|
||||
for (const s of [...compDoc.head.querySelectorAll("style")]) {
|
||||
const css = rewriteCssAssetUrls(s.textContent || "", src);
|
||||
styles.push(
|
||||
scopeCompId
|
||||
? scopeCssToComposition(css, scopeCompId, runtimeScope || undefined, authoredRootId, {
|
||||
compoundAuthoredRoot: compoundAuthoredRoot === true,
|
||||
})
|
||||
: css,
|
||||
);
|
||||
styles.push(scopeSubStyle(s.textContent || ""));
|
||||
}
|
||||
for (const s of [...compDoc.head.querySelectorAll("script")]) {
|
||||
const externalSrc = (s.getAttribute("src") || "").trim();
|
||||
@@ -288,14 +294,7 @@ export function inlineSubCompositions(
|
||||
|
||||
// Extract styles from content
|
||||
for (const s of [...contentDoc.querySelectorAll("style")]) {
|
||||
const css = rewriteCssAssetUrls(s.textContent || "", src);
|
||||
styles.push(
|
||||
scopeCompId
|
||||
? scopeCssToComposition(css, scopeCompId, runtimeScope || undefined, authoredRootId, {
|
||||
compoundAuthoredRoot: compoundAuthoredRoot === true,
|
||||
})
|
||||
: css,
|
||||
);
|
||||
styles.push(scopeSubStyle(s.textContent || ""));
|
||||
s.remove();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user