Skip to content

Commit ef3924a

Browse files
committed
fix(studio): a first animation in a sub-composition file runs from inside its template
1 parent 132b990 commit ef3924a

2 files changed

Lines changed: 43 additions & 1 deletion

File tree

‎packages/studio-server/src/routes/files.test.ts‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1714,6 +1714,39 @@ const tl = gsap.timeline({ paused: true });
17141714
expect(html.indexOf('tl.set("#card"')).toBeGreaterThan(declaration);
17151715
});
17161716

1717+
it("a first animation in a sub-composition file lands inside its template", async () => {
1718+
const projectDir = createProjectDir();
1719+
const app = new Hono();
1720+
registerFileRoutes(app, createAdapter(projectDir));
1721+
const sub =
1722+
'<template id="sub-template"><div data-composition-id="sub"><div id="card"></div></div></template>\n';
1723+
mkdirSync(join(projectDir, "compositions"), { recursive: true });
1724+
writeHtml(projectDir, "compositions/sub.html", sub);
1725+
1726+
const res = await app.request(
1727+
"http://localhost/projects/demo/gsap-mutations/compositions/sub.html",
1728+
{
1729+
method: "POST",
1730+
headers: { "Content-Type": "application/json" },
1731+
body: JSON.stringify({
1732+
type: "add",
1733+
targetSelector: "#card",
1734+
method: "to",
1735+
position: 0,
1736+
properties: { opacity: 0 },
1737+
}),
1738+
},
1739+
);
1740+
1741+
expect(res.status).toBe(200);
1742+
const html = readFileSync(join(projectDir, "compositions/sub.html"), "utf-8");
1743+
const close = html.indexOf("</template>");
1744+
expect(html.indexOf('window.__timelines["sub"]')).toBeGreaterThan(-1);
1745+
expect(html.lastIndexOf("<script")).toBeLessThan(close);
1746+
expect(html.slice(close).trim()).toBe("</template>");
1747+
expect(html).not.toContain("<body");
1748+
});
1749+
17171750
it("consolidate-position-writes leaves exactly one position write per selector", async () => {
17181751
const projectDir = createProjectDir();
17191752
const CORRUPTED = `<!DOCTYPE html><html><body><script data-hyperframes-gsap>

‎packages/studio-server/src/routes/files.ts‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,12 @@ function containsRawGsapExpression(value: unknown): boolean {
12671267
return Object.values(value).some(containsRawGsapExpression);
12681268
}
12691269

1270+
/** A sub-composition file is only its `<template>`, and the loader runs the scripts inside it. */
1271+
function insertBeforeTemplateClose(html: string, markup: string): string | null {
1272+
const at = html.lastIndexOf("</template>");
1273+
return at === -1 ? null : `${html.slice(0, at)}${markup}\n${html.slice(at)}`;
1274+
}
1275+
12701276
async function prepareGsapMutationScript(
12711277
c: RouteContext,
12721278
res: ResolvedGsapFile,
@@ -1293,7 +1299,10 @@ async function prepareGsapMutationScript(
12931299
`window.__timelines["${compId}"] = tl;`,
12941300
"</script>",
12951301
].join("\n");
1296-
html = insertBeforeCloseTag(html, "body", `${bootstrap}\n`) ?? `${html}\n${bootstrap}`;
1302+
html =
1303+
insertBeforeCloseTag(html, "body", `${bootstrap}\n`) ??
1304+
insertBeforeTemplateClose(html, bootstrap) ??
1305+
`${html}\n${bootstrap}`;
12971306
block = extractGsapScriptBlock(html);
12981307
}
12991308
if (

0 commit comments

Comments
 (0)