import { memo, type CSSProperties, type ReactNode } from "react"; import type { TimelineElement } from "../store/playerStore"; import { defaultTimelineTheme, getClipHandleOpacity, type TimelineTheme } from "./timelineTheme"; import type { TimelineEditCapabilities } from "./timelineEditing"; import { isAudioTimelineElement } from "../../utils/timelineInspector"; interface TimelineClipProps { el: TimelineElement; pps: number; clipY: number; isSelected: boolean; isHovered: boolean; isDragging?: boolean; hasCustomContent: boolean; capabilities: TimelineEditCapabilities; theme?: TimelineTheme; isComposition: boolean; onHoverStart: () => void; onHoverEnd: () => void; onPointerDown?: (e: React.PointerEvent) => void; onResizeStart?: (edge: "start" | "end", e: React.PointerEvent) => void; onClick: (e: React.MouseEvent) => void; onDoubleClick: (e: React.MouseEvent) => void; onContextMenu?: (e: React.MouseEvent) => void; children?: ReactNode; } // fallow-ignore-next-line complexity export const TimelineClip = memo(function TimelineClip({ el, pps, clipY, isSelected, isHovered, isDragging = false, hasCustomContent, capabilities, theme = defaultTimelineTheme, isComposition, onHoverStart, onHoverEnd, onPointerDown, onResizeStart, onClick, onDoubleClick, onContextMenu, children, }: TimelineClipProps) { const leftPx = el.start * pps; const widthPx = Math.max(el.duration * pps, 4); const handleOpacity = getClipHandleOpacity({ isHovered, isSelected, isDragging }); const displayLabel = el.label || el.id || el.tag; const showHandles = handleOpacity > 0.01 && (widthPx >= 32 || isSelected); const showLabel = widthPx >= 40 || isSelected; const showDefaultText = !hasCustomContent && (widthPx >= 40 || isSelected); const startLabel = el.start.toFixed(1); const endLabel = (el.start + el.duration).toFixed(1); const clipClassName = [ "timeline-clip", "absolute", hasCustomContent ? "overflow-visible" : "overflow-hidden", isSelected ? "is-selected" : "", isHovered ? "is-hovered" : "", isDragging ? "is-dragging" : "", showDefaultText ? "" : "is-micro", isAudioTimelineElement(el) ? "is-audio" : "", ] .filter((className) => className.length > 0) .join(" "); const style: CSSProperties = { left: leftPx, width: widthPx, top: clipY, bottom: clipY, borderRadius: theme.clipRadius, zIndex: isDragging ? 20 : isSelected ? 10 : isHovered ? 5 : 1, // Regular cursor over clips (CapCut-style, user preference) — no grab hand. cursor: "default", transform: isDragging ? "translateY(-1px)" : undefined, }; return (