mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 17:27:09 +00:00
fix(studio): an audio clip's name pill draws over its waveform (#5013)
* fix(studio): an audio clip's name pill draws over its waveform * fix(studio): the out-of-sync badge stays over the audio pill; one owner for the waveform layer * test(studio): the filmstrip tests reset the timeline in afterEach
This commit is contained in:
@@ -26,6 +26,7 @@ const BAR_STEP = 3;
|
||||
|
||||
export const rendersWaveform = (el: { tag: string }) => el.tag === "audio";
|
||||
const FADE_GHOST_OPACITY = 0.27;
|
||||
export const WAVEFORM_LAYER_Z = 10;
|
||||
|
||||
type BarGeometry = { x: number; width: number; height: number; gain: number };
|
||||
|
||||
@@ -236,7 +237,7 @@ export const AudioWaveform = memo(function AudioWaveform({
|
||||
|
||||
return (
|
||||
<div ref={rootRef} className="absolute inset-0">
|
||||
<div className="absolute inset-0 overflow-hidden" style={{ zIndex: 10 }}>
|
||||
<div className="absolute inset-0 overflow-hidden" style={{ zIndex: WAVEFORM_LAYER_Z }}>
|
||||
<canvas
|
||||
ref={setCanvasRef}
|
||||
className="absolute inset-x-0 bottom-0 w-full"
|
||||
|
||||
@@ -105,7 +105,7 @@ export const OutOfSyncBadge = memo(function OutOfSyncBadge({ el }: { el: Timelin
|
||||
aria-label={`Out of sync with ${partnerName} by ${label} frames`}
|
||||
title={`Out of sync with ${partnerName} by ${label} — click for Move or Slip into Sync`}
|
||||
data-testid="out-of-sync-badge"
|
||||
className="absolute bottom-0.5 left-1 z-[7] cursor-pointer rounded-[3px] bg-red-600 px-1 font-mono text-[9px] leading-[14px] text-white tabular-nums"
|
||||
className="absolute bottom-0.5 left-1 z-[12] cursor-pointer rounded-[3px] bg-red-600 px-1 font-mono text-[9px] leading-[14px] text-white tabular-nums"
|
||||
onPointerDown={stop}
|
||||
onDoubleClick={stop}
|
||||
onClick={open}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
import { loadStylesheet, STYLES_DIR } from "../../styles/styleSources";
|
||||
import { cleanupMounted, trackedRoot } from "../../components/ui/mountHost.testHelpers";
|
||||
import { TimelineClip } from "./TimelineClip";
|
||||
import { WAVEFORM_LAYER_Z } from "./AudioWaveform";
|
||||
import { renderClipChildren } from "./timelineClipChildren";
|
||||
import { usePlayerStore, type TimelineElement } from "../store/playerStore";
|
||||
|
||||
@@ -23,6 +24,7 @@ beforeAll(async () => {
|
||||
afterEach(() => {
|
||||
cleanupMounted();
|
||||
usePlayerStore.getState().setLintFindingsByElement(new Map());
|
||||
usePlayerStore.getState().setElements([]);
|
||||
document.body.innerHTML = "";
|
||||
});
|
||||
|
||||
@@ -153,4 +155,29 @@ describe("Filmstrip clips", () => {
|
||||
);
|
||||
expect(css).toMatch(/\.timeline-clip:not\(\.is-audio\)\s*\{\s*border-width:\s*0;/);
|
||||
});
|
||||
|
||||
const audioPillZ = () =>
|
||||
Number(
|
||||
css.match(/\.timeline-clip\.is-audio \.timeline-clip__label\s*\{[^}]*z-index:\s*(\d+)/)?.[1],
|
||||
);
|
||||
|
||||
it("draws an audio clip's name pill over its waveform", () => {
|
||||
expect(audioPillZ()).toBeGreaterThan(WAVEFORM_LAYER_Z);
|
||||
});
|
||||
|
||||
it("keeps the out-of-sync badge over the audio name pill", () => {
|
||||
const audio = {
|
||||
id: "clip",
|
||||
domId: "clip",
|
||||
label: "City",
|
||||
tag: "audio",
|
||||
start: 1.7,
|
||||
duration: 4,
|
||||
};
|
||||
const synced = { ...audio, track: 1, playbackStart: 0, syncOrigin: "lk-1" };
|
||||
const video = { ...synced, id: "talk", domId: "talk", tag: "video", start: 1, track: 0 };
|
||||
usePlayerStore.getState().setElements([video, synced]);
|
||||
const badge = render("audio", synced, false).querySelector('[data-testid="out-of-sync-badge"]');
|
||||
expect(Number(badge?.className.match(/\bz-\[(\d+)\]/)?.[1])).toBeGreaterThan(audioPillZ());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import React, { act } from "react";
|
||||
import { createRoot, type Root } from "react-dom/client";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { WAVEFORM_LAYER_Z } from "./AudioWaveform";
|
||||
import { usePlayerStore, type TimelineElement } from "../store/playerStore";
|
||||
import { TimelineClipFades, useClipFadeDraft } from "./TimelineClipFades";
|
||||
import { TimelineEditProvider } from "../../contexts/TimelineEditContext";
|
||||
@@ -298,7 +299,7 @@ describe("TimelineClipFades", () => {
|
||||
it("paints the handles above the clip's waveform and thumbnail layers", () => {
|
||||
const { host } = render(clip);
|
||||
const layer = host.querySelector<HTMLElement>('[data-testid="clip"]')?.firstElementChild;
|
||||
expect(Number((layer as HTMLElement).style.zIndex)).toBeGreaterThan(10);
|
||||
expect(Number((layer as HTMLElement).style.zIndex)).toBeGreaterThan(WAVEFORM_LAYER_Z);
|
||||
});
|
||||
|
||||
it("splits a clip narrower than two targets between the handles", () => {
|
||||
|
||||
@@ -350,7 +350,6 @@
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 6px;
|
||||
z-index: 6;
|
||||
width: fit-content;
|
||||
max-width: calc(100% - 22px);
|
||||
overflow: hidden;
|
||||
@@ -411,6 +410,7 @@
|
||||
.timeline-clip.is-audio .timeline-clip__label {
|
||||
top: 11px;
|
||||
left: 9px;
|
||||
z-index: 11;
|
||||
background: var(--timeline-clip-chip-audio-bg);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user