mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 14:50:02 +00:00
feat(studio): add a global toggle to stop manual edits from auto-recording keyframes
Adds a control-bar toggle (next to the Add Keyframe diamond) that, when off, makes a manual drag/resize/rotate/panel edit on an already-keyframed element shift the whole tween by the edit's delta instead of inserting or updating a keyframe at the playhead. The animation's shape is preserved, just moved. Wired into every path that can auto-record a keyframe: - canvas drag-to-move (tryGsapDragIntercept, reuses the existing Alt-drag "shift whole path" behavior) - canvas resize/rotate (tryGsapResizeIntercept, tryGsapRotationIntercept) - design-panel property edits (useAnimatedPropertyCommit) - motion-path keyframe-node dragging (MotionPathOverlay), the path a plain click-drag on a keyframed element's canvas shape actually takes, since the element renders exactly at its current keyframe's position The shared shift helper reuses synthesizeFlatTweenKeyframes for materializing a flat tween instead of hand-rolling it, and lives in its own file (gsapWholePropertyOffsetCommit.ts) to keep gsapDragCommit.ts under the 600-line cap, mirroring the existing gsapDragPositionCommit.ts split. Fixes #1808
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import React, { act } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { usePlayerStore } from "../player/store/playerStore";
|
||||
import { TimelineToolbar } from "./TimelineToolbar";
|
||||
|
||||
(globalThis as unknown as { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
|
||||
|
||||
afterEach(() => {
|
||||
document.body.innerHTML = "";
|
||||
usePlayerStore.setState({ autoKeyframeEnabled: true });
|
||||
});
|
||||
|
||||
function renderToolbar() {
|
||||
const host = document.createElement("div");
|
||||
document.body.append(host);
|
||||
const root = createRoot(host);
|
||||
act(() => {
|
||||
root.render(<TimelineToolbar toggleTimelineVisibility={vi.fn()} />);
|
||||
});
|
||||
return { host, root };
|
||||
}
|
||||
|
||||
// Regression (#1808): the auto-keyframe toggle is a GLOBAL setting (unlike the
|
||||
// diamond "Add keyframe" button, which needs a selection to mean anything), so
|
||||
// it must stay visible and usable with nothing selected — it must not be
|
||||
// gated behind `domEditSession`/`onToggleKeyframe`.
|
||||
describe("TimelineToolbar — auto-keyframe toggle (#1808)", () => {
|
||||
it("renders enabled (pressed) by default with no selection", () => {
|
||||
const { host, root } = renderToolbar();
|
||||
const btn = host.querySelector<HTMLButtonElement>('button[aria-pressed="true"]');
|
||||
expect(btn).not.toBeNull();
|
||||
act(() => root.unmount());
|
||||
});
|
||||
|
||||
it("flips autoKeyframeEnabled in the store when clicked", () => {
|
||||
const { host, root } = renderToolbar();
|
||||
const btn = host.querySelector<HTMLButtonElement>('button[aria-pressed="true"]')!;
|
||||
|
||||
act(() => {
|
||||
btn.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
});
|
||||
|
||||
expect(usePlayerStore.getState().autoKeyframeEnabled).toBe(false);
|
||||
expect(host.querySelector('button[aria-pressed="false"]')).not.toBeNull();
|
||||
act(() => root.unmount());
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user