Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions packages/core/src/parsers/__goldens__/fromto.parsed.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"animations": [
{
"targetSelector": "#hero",
"method": "fromTo",
"position": 0.1,
"properties": {
"x": 0,
"opacity": 1
},
"fromProperties": {
"x": -200,
"opacity": 0
},
"duration": 0.6,
"ease": "power3.out",
"id": "#hero-fromTo-100"
},
{
"targetSelector": "#caption",
"method": "fromTo",
"position": 0.5,
"properties": {
"y": 0,
"opacity": 1
},
"fromProperties": {
"y": -30,
"opacity": 0
},
"duration": 0.45,
"id": "#caption-fromTo-500"
}
],
"timelineVar": "tl",
"preamble": "var tl = gsap.timeline({ paused: true });",
"postamble": "window.__timelines[\"hero-reveal\"] = tl;"
}
6 changes: 6 additions & 0 deletions packages/core/src/parsers/__goldens__/fromto.serialized.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

var tl = gsap.timeline({ paused: true });
tl.fromTo("#hero", { x: -200, opacity: 0 }, { x: 0, opacity: 1, duration: 0.6, ease: "power3.out" }, 0.1);
tl.fromTo("#caption", { y: -30, opacity: 0 }, { y: 0, opacity: 1, duration: 0.45 }, 0.5);
window.__timelines["hero-reveal"] = tl;

27 changes: 26 additions & 1 deletion packages/core/src/parsers/gsapParser.golden.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,22 @@ const COMPLEX_SCRIPT = `\
window.__timelines = window.__timelines || {};
gsap.defaults({ force3D: true });
const tl = gsap.timeline({ paused: true, defaults: { duration: 0.45, ease: "power3.out" } });
const breatheRepeats = Math.ceil(7 / 2.4) - 1;
tl.from(".headline span", { y: 46, opacity: 0, stagger: 0.055, duration: 0.38, ease: "back.out(1.35)" }, 0.05)
.from(".headline .sub", { y: 20, opacity: 0, duration: 0.28 }, 0.2)
.from(".ambient-word", { scale: 0.92, opacity: 0, duration: 0.5 }, 0.08)
.from(".ambient-line", { scaleX: 0, opacity: 0, stagger: 0.08, duration: 0.42 }, 0.16);
window.__timelines["vpn-youtube-spot"] = tl;`;

// fromTo: exercises the three-argument (fromArg, toArg, position) AST path and
// negative numeric literals (UnaryExpression arm in resolveNode).
const FROMTO_SCRIPT = `\
var tl = gsap.timeline({ paused: true });
var hero = document.getElementById("hero");
var caption = document.getElementById("caption");
tl.fromTo(hero, { x: -200, opacity: 0 }, { x: 0, opacity: 1, duration: 0.6, ease: "power3.out" }, 0.1);
tl.fromTo(caption, { y: -30, opacity: 0 }, { y: 0, opacity: 1, duration: 0.45 }, 0.5);
window.__timelines["hero-reveal"] = tl;`;

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -123,4 +132,20 @@ describe("T6a — GSAP parser golden tests (Recast/Babel baseline)", () => {
await expect(serialized).toMatchFileSnapshot(g("complex.serialized.js"));
});
});

describe("fromTo — two tl.fromTo calls with negative positions (hero-reveal)", () => {
let parsed: string;
let serialized: string;
beforeAll(() => {
({ parsed, serialized } = parseAndSerialize(FROMTO_SCRIPT));
});

it("parseGsapScript output matches golden", async () => {
await expect(parsed).toMatchFileSnapshot(g("fromto.parsed.json"));
});

it("serializeGsapAnimations output matches golden", async () => {
await expect(serialized).toMatchFileSnapshot(g("fromto.serialized.js"));
});
});
});
26 changes: 25 additions & 1 deletion packages/core/src/studio-api/helpers/previewAdapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,33 @@ describe("T10 — PreviewAdapter contract (spec for R7)", () => {
describe("applyDraft / revertDraft", () => {
it.todo("applyDraft writes --hf-studio-* CSS props and sets the gesture marker");

it.todo("applyDraft accepts both move (dx/dy) and resize (w/h) payloads");
it.todo("applyDraft accepts a move payload (dx/dy) and writes the translate draft");

it.todo("applyDraft accepts a resize payload (w/h) and writes the size draft");

it.todo("revertDraft removes draft props and clears the gesture marker");

it.todo("revertDraft restores original translate when an original was recorded");
});

describe("applyDraft edge cases (R7 implementation contract)", () => {
it.todo(
"second applyDraft before revert/commit overwrites first draft — does not accumulate (dx/dy)",
);

it.todo(
"revertDraft is safe to call when no gesture is in progress (idempotent / no-op on empty marker)",
);

it.todo(
"elementAtPoint filtering is stable when playhead changes mid-drag — opacity re-evaluated per call",
);

it.todo(
"stage-root exclusion applies only to the outermost data-hf-root; nested sub-composition roots count as targets",
);
});

describe("commitPreview", () => {
it.todo("returns null when no gesture marker is present");

Expand All @@ -47,5 +67,9 @@ describe("T10 — PreviewAdapter contract (spec for R7)", () => {
it.todo("reads authored absolute times from data-start / data-end");

it.todo("ignores elements without data-hf-id");

it.todo(
"returns a defined timing entry when data-hf-id is present but data-start / data-end are missing",
);
});
});
10 changes: 9 additions & 1 deletion packages/core/src/studio-api/helpers/sourceMutation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -365,8 +365,16 @@ describe("probeElementInSource", () => {
// T7 — data-hf-id targeting (spec for R1).
// R1 adds `hfId?: string` to SourceMutationTarget and a `[data-hf-id="…"]` branch
// in findTargetElement (sourceMutation.ts:34). Convert from it.todo in the R1 PR.
// Covers the same surface as T3 (Studio sourcePatcher) — Core sourceMutation supports
// all patch types (inline-style, attribute, text-content) via patchElementInHtml.
describe("T7 — data-hf-id targeting (spec for R1)", () => {
it.todo("patches element by data-hf-id when no HTML id attribute is present");
it.todo("updates inline style by data-hf-id when no HTML id attribute is present");

it.todo("updates text content by data-hf-id");

it.todo("updates attribute by data-hf-id");

it.todo("data-hf-id attribute survives the patch (can be targeted again)");

it.todo("hfId lookup falls through to selector when hfId is not found in the document");
});
Loading