fix(studio): respect GSAP transform ownership (#2986)

* fix(studio): respect GSAP transform ownership

* fix(studio): enforce GSAP edit ownership consistently
This commit is contained in:
Miguel Ángel
2026-08-04 19:08:02 +00:00
committed by GitHub
parent 532f06158b
commit cf45c98454
14 changed files with 916 additions and 224 deletions
@@ -1,6 +1,6 @@
// @vitest-environment happy-dom
import { describe, expect, it, beforeEach } from "vitest";
import { describe, expect, it, beforeEach, vi } from "vitest";
import type { GsapAnimation } from "@hyperframes/core/gsap-parser";
import type { DomEditSelection } from "../components/editor/domEditingTypes";
import { commitGsapPositionFromDrag } from "./gsapDragPositionCommit";
@@ -9,6 +9,7 @@ import {
commitStaticGsapRotation,
commitStaticGsapSize,
findExistingPositionWrite,
materializeIfDynamic,
parkPlayheadOnKeyframe,
type GsapDragCommitCallbacks,
} from "./gsapDragCommit";
@@ -27,6 +28,43 @@ const selection = (): DomEditSelection =>
},
}) as unknown as DomEditSelection;
function selectorlessSelection(): DomEditSelection {
return {
selector: ".shared",
element: document.createElement("div"),
} as unknown as DomEditSelection;
}
describe("lower GSAP commit helpers fail closed", () => {
it("rejects instead of silently dropping a static position write without a stable selector", async () => {
const commitMutation = vi.fn();
await expect(
commitStaticGsapPosition(
selectorlessSelection(),
{ x: 10, y: 20 },
{ x: 0, y: 0 },
".shared",
null,
{ commitMutation },
),
).rejects.toMatchObject({ name: "GsapEditBlockedError", reason: "no-selector" });
expect(commitMutation).not.toHaveBeenCalled();
});
it("rejects runtime-dynamic materialization instead of rewriting source during a gesture", async () => {
const commitMutation = vi.fn();
await expect(
materializeIfDynamic(
{ ...flatTween(), hasUnresolvedKeyframes: true },
null,
commitMutation,
selection(),
),
).rejects.toMatchObject({ name: "GsapEditBlockedError", reason: "source-uneditable" });
expect(commitMutation).not.toHaveBeenCalled();
});
});
const flatTween = (): GsapAnimation =>
({
id: "#puck-a-to",