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:
Miguel Ángel
2026-05-20 01:55:17 -04:00
parent 6d9670fd58
commit 471b4efb4b
23 changed files with 98 additions and 17 deletions
+13
View File
@@ -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 };
}