mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
feat: data-timeline-locked + fix font loss in sub-compositions
Timeline locking: - Add data-timeline-locked attribute support — fully disables move, trim-start, and trim-end in Studio for clips that carry this attr - Runtime propagates the attribute from inner composition root to host element so component authors control it from their HTML - All 15 caption components in the registry now carry the attribute Font fix: - Extract <link rel="stylesheet"> and <link rel="preconnect"> from sub-composition <head> alongside existing <style>/<script> extraction - Fixes caption components (and any sub-comp using Google Fonts via <link> tags) losing their font-family when loaded as sub-compositions - Applied in both runtime (compositionLoader) and compiler (inlineSubCompositions) paths
This commit is contained in:
@@ -685,6 +685,7 @@ export async function bundleToSingleHtml(
|
||||
const compStyleChunks: string[] = [...subCompResult.styles];
|
||||
const compScriptChunks: string[] = [...subCompResult.scripts];
|
||||
const compExternalScriptSrcs: string[] = [...subCompResult.externalScriptSrcs];
|
||||
const compExternalLinkHrefs: string[] = [...subCompResult.externalLinkHrefs];
|
||||
const compVariablesByComp: Record<string, Record<string, unknown>> = {
|
||||
...subCompResult.variablesByComp,
|
||||
};
|
||||
@@ -811,6 +812,18 @@ export async function bundleToSingleHtml(
|
||||
}
|
||||
}
|
||||
|
||||
for (const href of compExternalLinkHrefs) {
|
||||
if (!document.querySelector(`link[href="${href}"]`)) {
|
||||
const linkEl = document.createElement("link");
|
||||
linkEl.setAttribute(
|
||||
"rel",
|
||||
href.includes(".css") || href.includes("css2?") ? "stylesheet" : "preconnect",
|
||||
);
|
||||
linkEl.setAttribute("href", href);
|
||||
document.head.appendChild(linkEl);
|
||||
}
|
||||
}
|
||||
|
||||
if (compStyleChunks.length) {
|
||||
const style = document.createElement("style");
|
||||
style.textContent = compStyleChunks.join("\n\n");
|
||||
|
||||
@@ -97,6 +97,7 @@ export interface InlineSubCompositionsResult {
|
||||
styles: string[];
|
||||
scripts: string[];
|
||||
externalScriptSrcs: string[];
|
||||
externalLinkHrefs: string[];
|
||||
variablesByComp: Record<string, Record<string, unknown>>;
|
||||
}
|
||||
|
||||
@@ -149,6 +150,7 @@ export function inlineSubCompositions(
|
||||
const styles: string[] = [];
|
||||
const scripts: string[] = [];
|
||||
const externalScriptSrcs: string[] = [];
|
||||
const externalLinkHrefs: string[] = [];
|
||||
const variablesByComp: Record<string, Record<string, unknown>> = {};
|
||||
|
||||
for (const hostEl of hosts) {
|
||||
@@ -221,6 +223,14 @@ export function inlineSubCompositions(
|
||||
externalScriptSrcs.push(externalSrc);
|
||||
}
|
||||
}
|
||||
for (const link of [
|
||||
...compDoc.head.querySelectorAll('link[rel="stylesheet"], link[rel="preconnect"]'),
|
||||
]) {
|
||||
const href = (link.getAttribute("href") || "").trim();
|
||||
if (href && !externalLinkHrefs.includes(href)) {
|
||||
externalLinkHrefs.push(href);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract styles from content
|
||||
@@ -325,5 +335,5 @@ export function inlineSubCompositions(
|
||||
hostEl.removeAttribute("data-composition-src");
|
||||
}
|
||||
|
||||
return { styles, scripts, externalScriptSrcs, variablesByComp };
|
||||
return { styles, scripts, externalScriptSrcs, externalLinkHrefs, variablesByComp };
|
||||
}
|
||||
|
||||
@@ -262,6 +262,8 @@ async function mountCompositionContent(params: {
|
||||
headStyles?: HTMLStyleElement[];
|
||||
/** Extra <script> elements from the parsed document <head> (non-template sub-compositions). */
|
||||
headScripts?: HTMLScriptElement[];
|
||||
/** Extra <link> elements from the parsed document <head> (font stylesheets, preconnects). */
|
||||
headLinks?: HTMLLinkElement[];
|
||||
/**
|
||||
* Defaults extracted from the sub-composition's own
|
||||
* `<html data-composition-variables="...">` attribute. Layered under the
|
||||
@@ -297,6 +299,15 @@ async function mountCompositionContent(params: {
|
||||
? `[data-composition-id="${CSS.escape(runtimeScopeCompositionId)}"]`
|
||||
: undefined;
|
||||
|
||||
if (params.headLinks) {
|
||||
for (const link of params.headLinks) {
|
||||
const href = link.getAttribute("href") || "";
|
||||
if (!href) continue;
|
||||
if (document.head.querySelector(`link[href="${CSS.escape(href)}"]`)) continue;
|
||||
document.head.appendChild(link.cloneNode(true));
|
||||
}
|
||||
}
|
||||
|
||||
// Inject <head> styles from non-template sub-compositions first (they define
|
||||
// element styles like backgrounds and positioning that the composition needs).
|
||||
if (params.headStyles) {
|
||||
@@ -395,6 +406,9 @@ async function mountCompositionContent(params: {
|
||||
if (heightRaw) params.host.setAttribute("data-height", heightRaw);
|
||||
if (widthPx && params.host instanceof HTMLElement) params.host.style.width = widthPx;
|
||||
if (heightPx && params.host instanceof HTMLElement) params.host.style.height = heightPx;
|
||||
if (innerRoot.hasAttribute("data-timeline-locked")) {
|
||||
params.host.setAttribute("data-timeline-locked", "");
|
||||
}
|
||||
params.host.appendChild(prepareFlattenedInnerRoot(innerRoot));
|
||||
} else if (params.hasTemplate) {
|
||||
params.host.appendChild(document.importNode(contentNode, true));
|
||||
@@ -581,6 +595,13 @@ export async function loadExternalCompositions(
|
||||
const headScripts = !template
|
||||
? Array.from(doc.head.querySelectorAll<HTMLScriptElement>("script"))
|
||||
: undefined;
|
||||
const headLinks = !template
|
||||
? Array.from(
|
||||
doc.head.querySelectorAll<HTMLLinkElement>(
|
||||
'link[rel="stylesheet"], link[rel="preconnect"]',
|
||||
),
|
||||
)
|
||||
: undefined;
|
||||
await mountCompositionContent({
|
||||
host,
|
||||
authoredCompositionId,
|
||||
@@ -595,6 +616,7 @@ export async function loadExternalCompositions(
|
||||
parseDimensionPx: params.parseDimensionPx,
|
||||
headStyles,
|
||||
headScripts,
|
||||
headLinks,
|
||||
declaredVariableDefaults: readDeclaredDefaults(doc.documentElement),
|
||||
onDiagnostic: params.onDiagnostic,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user