import { memo } from "react"; import type { KeyframeCacheEntry } from "../store/playerStore"; import { KF_MIN_PCT, KF_MAX_PCT } from "./TimelineClipDiamonds"; const SUB_TRACK_H = 24; const DIAMOND_SIZE = 6; const HALF = DIAMOND_SIZE / 2; interface TimelinePropertyRowsProps { keyframesData: KeyframeCacheEntry; clipWidthPx: number; clipLeftPx: number; accentColor: string; isSelected: boolean; currentPercentage: number; elementId: string; selectedKeyframes: Set; onClickKeyframe?: (percentage: number) => void; } function extractProperties(data: KeyframeCacheEntry): string[] { const props = new Set(); for (const kf of data.keyframes) { for (const key of Object.keys(kf.properties)) { props.add(key); } } return Array.from(props).sort(); } export const TimelinePropertyRows = memo(function TimelinePropertyRows({ keyframesData, clipWidthPx, clipLeftPx, accentColor, isSelected, currentPercentage, elementId, selectedKeyframes, onClickKeyframe, }: TimelinePropertyRowsProps) { const properties = extractProperties(keyframesData); if (properties.length === 0 || clipWidthPx < 20) return null; return (
{properties.map((prop) => { const propKeyframes = keyframesData.keyframes .filter((kf) => prop in kf.properties) .filter((kf) => kf.percentage >= KF_MIN_PCT && kf.percentage <= KF_MAX_PCT); if (propKeyframes.length === 0) return null; return (
{prop} {propKeyframes.map((kf) => { const x = Math.max( HALF, Math.min(clipWidthPx - HALF, (kf.percentage / 100) * clipWidthPx), ); const y = SUB_TRACK_H / 2; const key = `${elementId}:${kf.percentage}`; const isKfSelected = selectedKeyframes.has(key); const isHold = kf.ease === "steps(1)"; const fillColor = isKfSelected || (isSelected && Math.abs(kf.percentage - currentPercentage) < 0.5) ? accentColor : isSelected ? `${accentColor}80` : "#737373"; return ( { e.stopPropagation(); onClickKeyframe?.(kf.percentage); }} style={{ cursor: "pointer" }} > {isHold ? ( ) : ( )} ); })}
); })}
); }); export { SUB_TRACK_H };