mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-11-04 04:46:59 +00:00
fix(studio): a resize leaves a box to GSAP when GSAP tweens anything the CSS box writer sets
gsapWritesBox now reads its channels from BOX_SIZE_STYLE_PROPS, the writer's own property set, instead of width and height alone. A host-level test pins the GSAP-free resize route through useDomGeometryCommit.
This commit is contained in:
@@ -118,7 +118,7 @@ export function buildClearPathOffsetPatches(element: HTMLElement): PatchOperatio
|
||||
|
||||
/* ── Box size patches ────────────────────────────────────────────── */
|
||||
|
||||
const BOX_SIZE_STYLE_PROPS = [
|
||||
export const BOX_SIZE_STYLE_PROPS = [
|
||||
"width",
|
||||
"height",
|
||||
"min-width",
|
||||
|
||||
@@ -686,7 +686,10 @@ describe("a resize's anchor member", () => {
|
||||
expect(member.element.style.getPropertyValue("translate")).toBe("-10.25px 3.5px");
|
||||
});
|
||||
|
||||
it("leaves a box whose size GSAP tweens to the GSAP writer", () => {
|
||||
expect(anchorMember({ width: 300 }).plainTranslate).toBe(false);
|
||||
});
|
||||
it.each(["width", "maxWidth", "minHeight", "flexBasis", "scale"])(
|
||||
"leaves a box whose %s GSAP tweens, which the CSS box writer also sets, to the GSAP writer",
|
||||
(channel) => {
|
||||
expect(anchorMember({ [channel]: 300 }).plainTranslate).toBe(false);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
import { buildArcPath, type ArcPathConfig } from "@hyperframes/core/gsap-parser-acorn";
|
||||
import { parsePercentageKeyframes, toAbsoluteTime } from "./gsapShared";
|
||||
import { roundTo3 } from "../utils/rounding";
|
||||
import { BOX_SIZE_STYLE_PROPS } from "../components/editor/manualEditsDomPatches";
|
||||
|
||||
/**
|
||||
* A GSAP tween's `vars` object — intentionally open: it mixes channel values
|
||||
@@ -446,9 +447,13 @@ export function gsapWritesPosition(el: Element): boolean {
|
||||
return !!cache?.renderTransform || gsapWritesChannels(el, MOVE_CHANNELS);
|
||||
}
|
||||
|
||||
/** GSAP owns this element's box: its position, or its width or height. Else a resize writes CSS. */
|
||||
const BOX_CHANNELS = BOX_SIZE_STYLE_PROPS.map((prop) =>
|
||||
prop.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase()),
|
||||
);
|
||||
|
||||
/** GSAP owns this element's box: its position, or any property the CSS box writer sets. Else a resize writes CSS. */
|
||||
export function gsapWritesBox(el: Element): boolean {
|
||||
return gsapWritesPosition(el) || gsapWritesChannels(el, ["width", "height"]);
|
||||
return gsapWritesPosition(el) || gsapWritesChannels(el, BOX_CHANNELS);
|
||||
}
|
||||
|
||||
/** `hasNonHoldTweenForElement` for an element in hand, read from its own window's timelines. */
|
||||
|
||||
@@ -176,6 +176,28 @@ describe("useDomGeometryCommit, from the package entry", () => {
|
||||
unmount();
|
||||
});
|
||||
|
||||
it("saves a GSAP-free resize as its inline size, with no GSAP script and no animation read", async () => {
|
||||
const calls = stubPatchServer();
|
||||
const { element, recordEdit, hook, unmount } = renderHost();
|
||||
|
||||
await expect(
|
||||
hook().commitBoxSize(makeSelection("card", element), { width: 300, height: 90 }),
|
||||
).resolves.toEqual({ ok: true });
|
||||
|
||||
expect(element.style.getPropertyValue("width")).toBe("300px");
|
||||
expect(calls.patches).toEqual([
|
||||
expect.objectContaining({
|
||||
operations: expect.arrayContaining([
|
||||
{ type: "inline-style", property: "width", value: "300px" },
|
||||
{ type: "inline-style", property: "height", value: "90px" },
|
||||
]),
|
||||
}),
|
||||
]);
|
||||
expect(calls.urls.filter((url) => url.includes("gsap"))).toEqual([]);
|
||||
expect(recordEdit).toHaveBeenCalledTimes(1);
|
||||
unmount();
|
||||
});
|
||||
|
||||
it("puts a GSAP-free element's translate back when its move cannot be saved", async () => {
|
||||
stubPatchServer(500);
|
||||
const { element, hook, unmount } = renderHost();
|
||||
|
||||
Reference in New Issue
Block a user