'use client'; import * as React from 'react'; import { useEffect, useRef, useState, type CSSProperties } from 'react'; import { PrimitiveArrowIcon } from '@repo/ui'; import { Pause, Play, Repeat, Repeat1 } from 'lucide-react'; import { clampToolcraftTimelineTime } from '../../state/timeline-values'; import { TimelineIconButton } from './timeline-icon-button'; type TimelinePanelHeaderProps = { canExpand: boolean; currentTimeSeconds: number; durationSeconds: number; isExpanded: boolean; isLooping: boolean; isPlaying: boolean; isScrubbing: boolean; playbackReady: boolean; onDurationCommit: (value: string) => void; onScrubKeyDown: (event: React.KeyboardEvent) => void; onScrubLostPointerCapture: () => void; onScrubPointerDown: (event: React.PointerEvent) => void; onScrubPointerMove: (event: React.PointerEvent) => void; onScrubPointerUp: (event: React.PointerEvent) => void; onToggleExpanded: () => void; onToggleLoop: () => void; onTogglePlayback: () => void; stripRef: React.RefObject; variant: 'compact' | 'extended'; }; type TimelinePanelMaskProps = { currentTimeSeconds: number; durationSeconds: number; isHandleVisible: boolean; }; function cn(...classNames: Array): string { return classNames.filter(Boolean).join(' '); } function formatTimelineSeconds(value: number): string { return value.toFixed(2); } function formatTimelineDisplaySeconds(value: number): string { if (!Number.isFinite(value)) { return '0'; } return String(Number.parseFloat(value.toFixed(2))); } function formatDurationValueLabel(value: number): string { return `${Number.parseFloat(value.toFixed(2))}s`; } function formatTimelineHeaderTimeLabel({ currentTimeSeconds, durationSeconds, }: { currentTimeSeconds: number; durationSeconds: number; }): string { return `${formatTimelineSeconds(currentTimeSeconds)} / ${formatTimelineDisplaySeconds( durationSeconds, )}s`; } function getTimelineProgressRatio(currentTimeSeconds: number, durationSeconds: number): number { if (durationSeconds <= 0) { return 0; } return clampToolcraftTimelineTime(currentTimeSeconds, durationSeconds) / durationSeconds; } function getTimelineProgressPercent(currentTimeSeconds: number, durationSeconds: number): string { return `${getTimelineProgressRatio(currentTimeSeconds, durationSeconds) * 100}%`; } function getTimelineHandlePosition(currentTimeSeconds: number, durationSeconds: number): string { const progressPercent = getTimelineProgressPercent(currentTimeSeconds, durationSeconds); const progressRatio = getTimelineProgressRatio(currentTimeSeconds, durationSeconds); const offsetPx = Number((5 - progressRatio * 10).toFixed(4)); if (offsetPx < 0) { return `calc(${progressPercent} - ${Math.abs(offsetPx)}px)`; } if (offsetPx > 0) { return `calc(${progressPercent} + ${offsetPx}px)`; } return progressPercent; } function TimelinePanelDivider(): React.JSX.Element { return (