mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-08 02:36:10 +00:00
* perf(studio): schedule adaptive timeline thumbnails * perf(studio): bound thumbnail decoding resources * perf(studio): virtualize timeline thumbnail media * perf(studio): prioritize timeline thumbnail work * perf(studio-server): coordinate cancelable thumbnail generation --------- Co-authored-by: Codex <codex@local>
101 lines
4.3 KiB
TypeScript
101 lines
4.3 KiB
TypeScript
import { type ReactNode } from "react";
|
|
import type { GsapAnimation } from "@hyperframes/core/gsap-parser";
|
|
import type { MusicBeatAnalysis } from "@hyperframes/core/beats";
|
|
import type { TimelineElement, KeyframeCacheEntry } from "../store/playerStore";
|
|
import type { TimelineKeyframeTarget } from "./timelineKeyframeIdentity";
|
|
import type { TimelineTheme } from "./timelineTheme";
|
|
import type { TrackVisualStyle } from "./timelineIcons";
|
|
import type { DraggedClipState, ResizingClipState, BlockedClipState } from "./useTimelineClipDrag";
|
|
import type { TimelineClipIndex, TimelineTimeRange } from "../lib/timelineClipIndex";
|
|
import type { TimelineRowGeometry } from "./timelineLayout";
|
|
import type { TimelineVirtualRow } from "./useTimelineVirtualRows";
|
|
import type { TimelineLogicalRow } from "./timelineKeyboardNavigation";
|
|
import type { TimelineClipRenderContext } from "./TimelineTypes";
|
|
|
|
/**
|
|
* Props shared by the scroll container ({@link import("./TimelineCanvas")}) and
|
|
* the lane renderer ({@link import("./TimelineLanes")}). TimelineCanvas passes
|
|
* these straight through via spread, so they are declared once here and both
|
|
* prop types compose from this base — no duplicated prop list. Kept in its own
|
|
* module so neither side has to import the other just to name the contract.
|
|
*/
|
|
export interface TimelineLaneBaseProps {
|
|
pps: number;
|
|
contentOrigin: number;
|
|
contentGutter: number;
|
|
trackContentWidth: number;
|
|
theme: TimelineTheme;
|
|
displayTrackOrder: number[];
|
|
rowHeights: readonly number[];
|
|
rowGeometry: TimelineRowGeometry;
|
|
virtualRows: readonly TimelineVirtualRow[];
|
|
logicalRows: readonly TimelineLogicalRow[];
|
|
focusedTargetId: string | null;
|
|
rowsVirtualized: boolean;
|
|
clipIndex: TimelineClipIndex;
|
|
renderTimeRange: TimelineTimeRange;
|
|
visibleTimeRange: TimelineTimeRange;
|
|
pinnedClipIdentities: ReadonlySet<string>;
|
|
trackOrder: number[];
|
|
tracks: [number, TimelineElement[]][];
|
|
trackStyles: Map<number, TrackVisualStyle>;
|
|
laneCounts: ReadonlyMap<string, number>;
|
|
selectedElementId: string | null;
|
|
selectedElementIds: Set<string>;
|
|
hoveredClip: string | null;
|
|
draggedClip: DraggedClipState | null;
|
|
blockedClipRef: React.RefObject<BlockedClipState | null>;
|
|
suppressClickRef: React.RefObject<boolean>;
|
|
scrollRef: React.RefObject<HTMLDivElement | null>;
|
|
renderClipContent?: (
|
|
element: TimelineElement,
|
|
style: { clip: string; label: string },
|
|
context: TimelineClipRenderContext,
|
|
) => ReactNode;
|
|
renderClipOverlay?: (element: TimelineElement) => ReactNode;
|
|
onDrillDown?: (element: TimelineElement) => void;
|
|
onSelectElement?: (element: TimelineElement | null) => void;
|
|
setHoveredClip: (key: string | null) => void;
|
|
setShowPopover: (v: boolean) => void;
|
|
setRangeSelection: (v: null) => void;
|
|
setResizingClip: (v: ResizingClipState | null) => void;
|
|
setDraggedClip: (v: DraggedClipState | null) => void;
|
|
setSelectedElementId: (id: string | null) => void;
|
|
shiftClickClipRef: React.RefObject<{
|
|
element: TimelineElement;
|
|
anchorX: number;
|
|
anchorY: number;
|
|
} | null>;
|
|
getPreviewElement: (element: TimelineElement) => TimelineElement;
|
|
getTrackStyle: (tag: string) => TrackVisualStyle;
|
|
keyframeCache?: Map<string, KeyframeCacheEntry>;
|
|
gsapAnimations: Map<string, GsapAnimation[]>;
|
|
selectedKeyframes: Set<string>;
|
|
currentTime: number;
|
|
onSeek?: (time: number) => void;
|
|
onSelectSegment?: (elementId: string, target: TimelineKeyframeTarget) => void;
|
|
onClickKeyframe?: (element: TimelineElement, target: TimelineKeyframeTarget) => void;
|
|
onShiftClickKeyframe?: (elementId: string, target: TimelineKeyframeTarget) => void;
|
|
onContextMenuKeyframe?: (
|
|
e: React.MouseEvent,
|
|
elementId: string,
|
|
target: TimelineKeyframeTarget,
|
|
) => void;
|
|
onMoveKeyframe?: (
|
|
elementId: string,
|
|
keyframe: TimelineKeyframeTarget,
|
|
toClipPercentage: number,
|
|
propertyGroup?: string,
|
|
tweenPercentage?: number,
|
|
animationId?: string,
|
|
) => Promise<boolean>;
|
|
onContextMenuClip?: (e: React.MouseEvent, element: TimelineElement) => void;
|
|
/**
|
|
* Right-click on EMPTY lane space (not on a clip — those preventDefault
|
|
* before this fires — not the gutter/ruler, not below the lanes). `time` is
|
|
* the timeline time (seconds) under the pointer on that lane.
|
|
*/
|
|
onContextMenuLane?: (e: React.MouseEvent, track: number, time: number) => void;
|
|
beatAnalysis?: MusicBeatAnalysis | null;
|
|
}
|