mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-12 07:09:59 +00:00
fix: producer render diverges from preview for sub-composition root styling (#1886)
Fixes #1847 The producer's render path stripped a sub-composition's authored root element and inlined only its children, so any CSS anchored on that root (its id or classes) matched nothing in the compiled HTML even though it resolved fine in Studio preview. Changes: - Wire flattenInnerRoot into the producer's sub-composition inliner (packages/producer/src/services/htmlCompiler.ts) so its render-time DOM shape matches the preview bundler's. - Rewrite a bare root [data-composition-id="X"] box selector to a :has()/:not() pair that lands on exactly one of the host or the flattened wrapper (packages/core/src/compiler/compositionScoping.ts), avoiding double-applying additive properties like padding. - Restore the composition's own id onto the flattened wrapper when the host has no id of its own, an "anonymous" host (packages/core/src/compiler/inlineSubCompositions.ts). - Fix the runtime's startResolver to find a composition's start time through the post-inlining data-composition-file marker, not just data-composition-src or data-composition-id (packages/core/src/runtime/startResolver.ts). Also adds regression coverage for the literal issue #1847 repro (a class, not just an id, on the authored root, styled via a descendant selector), a test proving the runtime compositionLoader's anonymous-host path doesn't share this bug, and fixes stale test documentation and a misattributed code comment surfaced during review. Verified: 29-fixture Docker regression sweep on linux/amd64 (matching CI) run 3x clean, 967/967 core unit tests, full CI green.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import postcss, { type AtRule, type Node, type Rule } from "postcss";
|
||||
|
||||
const AUTHORED_ROOT_ID_ATTR = "data-hf-authored-id";
|
||||
const INNER_ROOT_ATTR = "data-hf-inner-root";
|
||||
|
||||
function escapeRegExp(value: string): string {
|
||||
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
@@ -117,6 +118,18 @@ function scopeSelector(
|
||||
"g",
|
||||
);
|
||||
if (compositionIdPattern.test(trimmed)) {
|
||||
const isRootBoxSelector = trimmed.replace(compositionIdPattern, "").trim() === "";
|
||||
if (isRootBoxSelector) {
|
||||
// A bare root selector styles the composition's own box (flex/grid/
|
||||
// position/padding). When flattenInnerRoot preserves the authored root
|
||||
// as a wrapper below `scope` (see prepareFlattenedInnerRoot), that
|
||||
// wrapper is the element real children are laid out in, not `scope`
|
||||
// itself, so the box styling must land there instead. It must land on
|
||||
// exactly one of the two: applying it to both compounds any additive
|
||||
// property (padding, margin, non-zero transform) since the wrapper
|
||||
// sits nested inside the host and would inherit the effect twice.
|
||||
return `${scope}:not(:has([${INNER_ROOT_ATTR}])), ${scope} > [${INNER_ROOT_ATTR}]`;
|
||||
}
|
||||
return selectorWithoutRootTiming.replace(compositionIdPattern, scope);
|
||||
}
|
||||
const leading = selectorWithoutRootTiming.match(/^\s*/)?.[0] ?? "";
|
||||
|
||||
Reference in New Issue
Block a user