mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
Merge pull request #792 from func25/fix/layer-range-seek
This commit is contained in:
@@ -8,7 +8,10 @@ import {
|
||||
import { useStudioContext } from "../../contexts/StudioContext";
|
||||
import { useDomEditContext } from "../../contexts/DomEditContext";
|
||||
import { usePlayerStore } from "../../player";
|
||||
import { findMatchingTimelineElementId } from "../../utils/studioHelpers";
|
||||
import {
|
||||
findMatchingTimelineElementId,
|
||||
resolveTimelineSelectionSeekTime,
|
||||
} from "../../utils/studioHelpers";
|
||||
import { Layers } from "../../icons/SystemIcons";
|
||||
|
||||
const TAG_ICONS: Record<string, string> = {
|
||||
@@ -49,8 +52,14 @@ interface CollapsedState {
|
||||
}
|
||||
|
||||
export const LayersPanel = memo(function LayersPanel() {
|
||||
const { previewIframeRef, activeCompPath, refreshKey, compositionLoading, timelineElements } =
|
||||
useStudioContext();
|
||||
const {
|
||||
previewIframeRef,
|
||||
activeCompPath,
|
||||
refreshKey,
|
||||
compositionLoading,
|
||||
timelineElements,
|
||||
currentTime,
|
||||
} = useStudioContext();
|
||||
const { domEditSelection, applyDomSelection, updateDomEditHoverSelection } = useDomEditContext();
|
||||
|
||||
const [layers, setLayers] = useState<DomEditLayerItem[]>([]);
|
||||
@@ -140,11 +149,12 @@ export const LayersPanel = memo(function LayersPanel() {
|
||||
if (matchedId) {
|
||||
const el = timelineElements.find((e) => (e.key ?? e.id) === matchedId);
|
||||
if (el) {
|
||||
usePlayerStore.getState().requestSeek(el.start + el.duration / 2);
|
||||
const nextTime = resolveTimelineSelectionSeekTime(currentTime, el);
|
||||
if (nextTime != null) usePlayerStore.getState().requestSeek(nextTime);
|
||||
}
|
||||
}
|
||||
},
|
||||
[resolveSelection, timelineElements],
|
||||
[currentTime, resolveSelection, timelineElements],
|
||||
);
|
||||
|
||||
const handleSelectLayer = useCallback(
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveTimelineSelectionSeekTime } from "./studioHelpers";
|
||||
|
||||
describe("resolveTimelineSelectionSeekTime", () => {
|
||||
it("keeps the current time when it is already inside the clip range", () => {
|
||||
expect(resolveTimelineSelectionSeekTime(3, { start: 0, duration: 5 })).toBe(3);
|
||||
});
|
||||
|
||||
it("clamps to the clip start when current time is before the clip", () => {
|
||||
expect(resolveTimelineSelectionSeekTime(1, { start: 4, duration: 3 })).toBe(4);
|
||||
});
|
||||
|
||||
it("clamps to the clip end when current time is after the clip", () => {
|
||||
expect(resolveTimelineSelectionSeekTime(10, { start: 4, duration: 3 })).toBe(7);
|
||||
});
|
||||
|
||||
it("falls back to the clip start for invalid current time", () => {
|
||||
expect(resolveTimelineSelectionSeekTime(Number.NaN, { start: 2, duration: 5 })).toBe(2);
|
||||
});
|
||||
});
|
||||
@@ -158,6 +158,20 @@ export function findMatchingTimelineElementId(
|
||||
return null;
|
||||
}
|
||||
|
||||
export function resolveTimelineSelectionSeekTime(
|
||||
currentTime: number,
|
||||
element: Pick<TimelineElement, "start" | "duration"> | null | undefined,
|
||||
): number | null {
|
||||
if (!element) return null;
|
||||
if (!Number.isFinite(element.start) || !Number.isFinite(element.duration)) return null;
|
||||
|
||||
const start = Math.max(0, element.start);
|
||||
const end = Math.max(start, start + Math.max(0, element.duration));
|
||||
const time = Number.isFinite(currentTime) ? currentTime : start;
|
||||
|
||||
return clampNumber(time, start, end);
|
||||
}
|
||||
|
||||
export function clampNumber(value: number, min: number, max: number): number {
|
||||
if (max < min) return min;
|
||||
return Math.min(Math.max(value, min), max);
|
||||
|
||||
Reference in New Issue
Block a user