"use client"; import { useEffect, useRef, useState } from "react"; import { formatTimecode, type FrameRate, type TimeCodeFormat, } from "opencut-wasm"; import { cn } from "@/utils/ui"; import { parseMediaTimecode, snapSeekMediaTime, type MediaTime, } from "@/wasm"; interface EditableTimecodeProps { time: MediaTime; duration: MediaTime; format?: TimeCodeFormat; fps: FrameRate; onTimeChange?: ({ time }: { time: MediaTime }) => void; className?: string; disabled?: boolean; } export function EditableTimecode({ time, duration, format = "HH:MM:SS:FF", fps, onTimeChange, className, disabled = false, }: EditableTimecodeProps) { const [isEditing, setIsEditing] = useState(false); const [inputValue, setInputValue] = useState(""); const [hasError, setHasError] = useState(false); const inputRef = useRef(null); const enterPressedRef = useRef(false); const formattedTime = formatTimecode({ time, format, rate: fps }) ?? ""; const startEditing = () => { if (disabled) return; setIsEditing(true); setInputValue(formattedTime); setHasError(false); enterPressedRef.current = false; }; const cancelEditing = () => { setIsEditing(false); setInputValue(""); setHasError(false); enterPressedRef.current = false; }; const applyEdit = () => { const parsedTime = parseMediaTimecode({ timeCode: inputValue, format, fps, }); if (parsedTime == null) { setHasError(true); return; } const clampedTime = duration ? snapSeekMediaTime({ time: parsedTime, duration, fps }) : parsedTime; onTimeChange?.({ time: clampedTime }); setIsEditing(false); setInputValue(""); setHasError(false); enterPressedRef.current = false; }; const handleKeyDown = (event: React.KeyboardEvent) => { if (event.key === "Enter") { event.preventDefault(); enterPressedRef.current = true; applyEdit(); } else if (event.key === "Escape") { event.preventDefault(); cancelEditing(); } }; const handleInputChange = ({ target, }: React.ChangeEvent) => { setInputValue(target.value); setHasError(false); }; const handleBlur = () => { if (!enterPressedRef.current && isEditing) { applyEdit(); } }; const handleDisplayKeyDown = ( event: React.KeyboardEvent, ) => { if (disabled) return; if (event.key === "Enter" || event.key === " ") { event.preventDefault(); startEditing(); } }; useEffect(() => { if (isEditing && inputRef.current) { inputRef.current.focus(); inputRef.current.select(); } }, [isEditing]); if (isEditing) { return ( ); } return ( ); }