mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 09:16:55 +00:00
fix(studio): dragging an audio clip's edge trims it instead of moving it (#4645)
* fix(studio): dragging an audio clip's edge trims it instead of moving it The clip picture layer (waveform, filmstrip, stills) paints above the trim handles and swallowed the press, so an edge drag started a move. The picture layer now takes no input. * docs(studio): say clip content takes no pointer input
This commit is contained in:
@@ -13,9 +13,9 @@ export interface TimelineClipRenderContext {
|
||||
export interface TimelineProps extends TimelineDropCallbacks, TimelineEditOverrides {
|
||||
/** Project-scoped reset boundary; soft source refreshes retain the same epoch. */
|
||||
sessionEpoch?: number;
|
||||
/** keepPlaying: true preserves the current play state across the seek. */
|
||||
onSeek?: (time: number, options?: { keepPlaying?: boolean }) => void;
|
||||
onDrillDown?: (element: TimelineElement) => void;
|
||||
/** Picture only: takes no pointer input. Interactive content goes in renderClipOverlay. */
|
||||
renderClipContent?: (
|
||||
element: TimelineElement,
|
||||
style: { clip: string; label: string },
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { act, createElement } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveClipRenderContext } from "./timelineClipChildren";
|
||||
import { renderClipChildren, resolveClipRenderContext } from "./timelineClipChildren";
|
||||
import { getTrackStyle } from "./timelineIcons";
|
||||
import type { TimelineElement } from "../store/playerStore";
|
||||
|
||||
Object.defineProperty(globalThis, "IS_REACT_ACT_ENVIRONMENT", {
|
||||
configurable: true,
|
||||
value: true,
|
||||
});
|
||||
|
||||
const clip: TimelineElement = {
|
||||
id: "clip",
|
||||
tag: "video",
|
||||
@@ -29,3 +39,26 @@ describe("resolveClipRenderContext", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("renderClipChildren", () => {
|
||||
// happy-dom cannot hit-test, so this pins what decides the hit: the picture takes no input.
|
||||
it("lets a press on a picture stacked above the trim handles fall through to them", () => {
|
||||
const host = document.createElement("div");
|
||||
document.body.append(host);
|
||||
const root = createRoot(host);
|
||||
const picture = () =>
|
||||
createElement("div", { "data-picture": "", style: { position: "absolute", zIndex: 10 } });
|
||||
|
||||
act(() => {
|
||||
root.render(renderClipChildren(clip, getTrackStyle("video"), picture, undefined));
|
||||
});
|
||||
|
||||
// happy-dom does not inherit pointer-events, so walk up to the layer that turns input off.
|
||||
let node = host.querySelector<HTMLElement>("[data-picture]");
|
||||
expect(node).not.toBeNull();
|
||||
while (node && node !== host && node.style.pointerEvents !== "none") node = node.parentElement;
|
||||
expect(node?.style.pointerEvents).toBe("none");
|
||||
act(() => root.unmount());
|
||||
host.remove();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -57,10 +57,13 @@ export function renderClipChildren(
|
||||
{renderClipOverlay?.(element)}
|
||||
{!renderClipContent && <ClipLintDot element={element} />}
|
||||
{renderClipContent && (
|
||||
// borderRadius: inherit — the clip itself is overflow-visible (keyframe
|
||||
// diamonds hang outside its bounds), so the thumbnail layer must clip
|
||||
// itself to the clip's rounded corners or sharp corners poke out.
|
||||
<div className="absolute inset-0 overflow-hidden" style={{ borderRadius: "inherit" }}>
|
||||
// The picture can paint above the trim handles, so it takes no input and presses reach them.
|
||||
// borderRadius: inherit clips it to the clip's rounded corners; the clip itself is
|
||||
// overflow-visible because keyframe diamonds hang outside its bounds.
|
||||
<div
|
||||
className="absolute inset-0 overflow-hidden"
|
||||
style={{ borderRadius: "inherit", pointerEvents: "none" }}
|
||||
>
|
||||
{renderClipContent(element, clipStyle, context)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user