mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 17:27:09 +00:00
fix(studio): a timeline at 00:00 stays at 00:00 when the window resizes or the zoom is set (#4411)
The centre-anchor step ran on every scale change, including a window resize and a zoom set by a host, and from scroll 0 it always moved the view right, hiding 00:00 under the track header. A view at the start now stays there; a scrolled view still keeps its centre time.
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { act, createRef } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { useTimelinePlayhead } from "./useTimelinePlayhead";
|
||||
|
||||
Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true });
|
||||
|
||||
function scrollBox(scrollLeft: number) {
|
||||
const el = document.createElement("div");
|
||||
let left = scrollLeft;
|
||||
Object.defineProperties(el, {
|
||||
clientWidth: { value: 800 },
|
||||
scrollWidth: { value: 20_000 },
|
||||
scrollLeft: { get: () => left, set: (v: number) => (left = v) },
|
||||
});
|
||||
return el;
|
||||
}
|
||||
|
||||
function Harness({ pps, scroll }: { pps: number; scroll: HTMLDivElement }) {
|
||||
useTimelinePlayhead({
|
||||
playheadRef: createRef(),
|
||||
scrollRef: { current: scroll },
|
||||
ppsRef: { current: pps },
|
||||
durationRef: { current: 60 },
|
||||
isDragging: { current: false },
|
||||
currentTime: 0,
|
||||
zoomMode: "manual",
|
||||
manualZoomPercent: 100,
|
||||
zoomModeRef: { current: "manual" },
|
||||
manualZoomPercentRef: { current: 100 },
|
||||
fitPps: pps,
|
||||
fitPpsRef: { current: pps },
|
||||
effectiveDuration: 60,
|
||||
pps,
|
||||
timelineReady: true,
|
||||
elementsLength: 1,
|
||||
setZoomMode: () => {},
|
||||
setManualZoomPercent: () => {},
|
||||
contentOrigin: 32,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
function zoom(scrollLeft: number, fromPps: number, toPps: number) {
|
||||
const scroll = scrollBox(scrollLeft);
|
||||
const host = document.createElement("div");
|
||||
const root = createRoot(host);
|
||||
act(() => root.render(<Harness pps={fromPps} scroll={scroll} />));
|
||||
act(() => root.render(<Harness pps={toPps} scroll={scroll} />));
|
||||
act(() => root.unmount());
|
||||
return scroll.scrollLeft;
|
||||
}
|
||||
|
||||
describe("useTimelinePlayhead centre anchor", () => {
|
||||
it("keeps a view at the start at the start when the scale changes", () => {
|
||||
expect(zoom(0, 100, 114)).toBe(0);
|
||||
});
|
||||
|
||||
it("keeps the time at the viewport centre when the view is scrolled", () => {
|
||||
// Centre time (400 + 400 - 32) / 100 = 7.68s lands at 32 + 7.68 * 200 - 400.
|
||||
expect(zoom(400, 100, 200)).toBe(1168);
|
||||
});
|
||||
});
|
||||
@@ -75,7 +75,8 @@ export function useTimelinePlayhead({
|
||||
// it true and the next toolbar zoom would wrongly skip center-anchoring.
|
||||
const skip = skipCenterAnchorRef.current;
|
||||
skipCenterAnchorRef.current = false;
|
||||
if (!scroll || pps === prevPps || skip) return;
|
||||
// A view at the start stays there: a resize or a host zoom must not hide 00:00.
|
||||
if (!scroll || pps === prevPps || skip || scroll.scrollLeft < 1) return;
|
||||
const nextScrollLeft = getTimelineScrollLeftForZoomAnchor({
|
||||
pointerX: scroll.clientWidth / 2,
|
||||
currentScrollLeft: scroll.scrollLeft,
|
||||
|
||||
Reference in New Issue
Block a user