mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-08 02:36:10 +00:00
fix(render): surface structured outcomes (#2153)
This commit is contained in:
@@ -582,7 +582,7 @@ window.__utilsMarker = gsap.utils.marker;
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("reads remapped timeline registry accessors with the original target receiver", () => {
|
||||
it("reads and dual-publishes remapped timelines without replacing the registry", () => {
|
||||
let timeline = "initial";
|
||||
const timelineRegistry = {
|
||||
get host() {
|
||||
@@ -633,6 +633,8 @@ window.__afterTimeline = window.__timelines.scene;
|
||||
|
||||
expect(fakeWindow.__beforeTimeline).toBe("initial");
|
||||
expect(fakeWindow.__afterTimeline).toBe("updated");
|
||||
expect(Reflect.get(timelineRegistry, "scene")).toBe("updated");
|
||||
expect(fakeWindow.__timelines).toBe(timelineRegistry);
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
@@ -408,10 +408,25 @@ export function wrapScopedCompositionScript(
|
||||
if (!__hfTimelineRegistryProxy) {
|
||||
__hfTimelineRegistryProxy = new Proxy(window.__timelines, {
|
||||
get: function(target, prop, receiver) {
|
||||
return Reflect.get(target, prop === __hfCompId ? __hfTimelineCompId : prop, target);
|
||||
if (prop !== __hfCompId) {
|
||||
return Reflect.get(target, prop, target);
|
||||
}
|
||||
var authoredValue = Reflect.get(target, prop, target);
|
||||
return authoredValue === undefined
|
||||
? Reflect.get(target, __hfTimelineCompId, target)
|
||||
: authoredValue;
|
||||
},
|
||||
set: function(target, prop, value, receiver) {
|
||||
return Reflect.set(target, prop === __hfCompId ? __hfTimelineCompId : prop, value, target);
|
||||
if (prop !== __hfCompId) {
|
||||
return Reflect.set(target, prop, value, target);
|
||||
}
|
||||
// The authored node remains in the compiled DOM when its local id
|
||||
// differs from the runtime mount id, so readiness legitimately sees
|
||||
// both compositions. Publish the same timeline under both identities
|
||||
// instead of replacing one with the other.
|
||||
var authoredSet = Reflect.set(target, __hfCompId, value, target);
|
||||
var runtimeSet = Reflect.set(target, __hfTimelineCompId, value, target);
|
||||
return authoredSet && runtimeSet;
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -435,6 +450,11 @@ export function wrapScopedCompositionScript(
|
||||
},
|
||||
set: function(target, prop, value, receiver) {
|
||||
if (prop === "__timelines") {
|
||||
// Common authoring boilerplate assigns the registry back to
|
||||
// itself (window.__timelines = window.__timelines || {}). The
|
||||
// getter above returns our proxy; do not replace the canonical
|
||||
// registry with that proxy or later wrappers will stack proxies.
|
||||
if (value === __hfTimelineRegistryProxy) return true;
|
||||
target.__timelines = value || {};
|
||||
__hfTimelineRegistryProxy = null;
|
||||
return true;
|
||||
|
||||
@@ -142,6 +142,32 @@ describe("inlineSubCompositions – #ID selector scoping divergence", () => {
|
||||
expect(wrappedScript).toContain('"intro"');
|
||||
});
|
||||
|
||||
it("maps a template-local timeline id onto a differently named mount", () => {
|
||||
const document = makeHostDocument("captions-comp");
|
||||
const host = document.querySelector('[data-composition-src="intro.html"]')!;
|
||||
const captionsHtml = `<template id="captions-template">
|
||||
<div data-composition-id="captions" data-width="1920" data-height="1080">
|
||||
<style>[data-composition-id="captions"] { opacity: 1; }</style>
|
||||
<script>
|
||||
window.__timelines = window.__timelines || {};
|
||||
window.__timelines["captions"] = { duration: 4 };
|
||||
</script>
|
||||
</div>
|
||||
</template>`;
|
||||
|
||||
const result = inlineSubCompositions(document, [host], {
|
||||
resolveHtml: () => captionsHtml,
|
||||
parseHtml: (html) => parseHTML(html).document,
|
||||
});
|
||||
|
||||
expect(host.getAttribute("data-composition-id")).toBe("captions-comp");
|
||||
expect(host.querySelector('[data-composition-id="captions"]')).not.toBeNull();
|
||||
expect(result.styles.join("\n")).toContain('[data-composition-id="captions-comp"]');
|
||||
const wrappedScript = result.scripts.join("\n");
|
||||
expect(wrappedScript).toContain('var __hfCompId = "captions"');
|
||||
expect(wrappedScript).toContain('var __hfTimelineCompId = "captions-comp"');
|
||||
});
|
||||
|
||||
it("bundler path (with flattenInnerRoot): preserves inner root as a child element", () => {
|
||||
const document = makeHostDocument("intro");
|
||||
const host = document.querySelector('[data-composition-src="intro.html"]')!;
|
||||
|
||||
@@ -228,13 +228,21 @@ export function inlineSubCompositions(
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the inner composition root
|
||||
// Keep structural flattening tied to an exact mount-id match. A template
|
||||
// may intentionally use a different local id (for example, a
|
||||
// `captions-comp` host mounting a `captions` template); flattening that
|
||||
// fallback root changes the compiled DOM and can invalidate selectors and
|
||||
// regression goldens. Discover it separately so script timeline
|
||||
// registration can still map the authored id onto the runtime mount id.
|
||||
const innerRoot = compId
|
||||
? queryByAttr(contentDoc, "data-composition-id", compId)
|
||||
: contentDoc.querySelector("[data-composition-id]");
|
||||
const inferredCompId = innerRoot?.getAttribute("data-composition-id")?.trim() || "";
|
||||
const authoredCompositionRoot = innerRoot ?? contentDoc.querySelector("[data-composition-id]");
|
||||
const inferredCompId =
|
||||
authoredCompositionRoot?.getAttribute("data-composition-id")?.trim() || "";
|
||||
const authoredRootId = innerRoot?.getAttribute("id")?.trim() || null;
|
||||
const scopeCompId = compId || inferredCompId;
|
||||
const scriptCompositionId = inferredCompId || scopeCompId;
|
||||
const runtimeScope = runtimeCompId ? buildScopeSelector(runtimeCompId) : "";
|
||||
|
||||
// Variable merging (bundler feature). Read declared defaults from the
|
||||
@@ -312,13 +320,13 @@ export function inlineSubCompositions(
|
||||
}
|
||||
scriptItems.push({ kind: "external", src: externalSrc });
|
||||
} else {
|
||||
const wrappedScript = scopeCompId
|
||||
const wrappedScript = scriptCompositionId
|
||||
? wrapScopedCompositionScript(
|
||||
s.textContent || "",
|
||||
scopeCompId,
|
||||
scriptCompositionId,
|
||||
scriptErrorLabel,
|
||||
runtimeScope || undefined,
|
||||
runtimeCompId || scopeCompId,
|
||||
runtimeCompId || scopeCompId || scriptCompositionId,
|
||||
authoredRootId,
|
||||
)
|
||||
: wrapInlineScriptWithErrorBoundary(s.textContent || "", scriptErrorLabel);
|
||||
|
||||
Reference in New Issue
Block a user