()
| 37 | }; |
| 38 | |
| 39 | const commit = () => { |
| 40 | if (!inputValue.trim()) { |
| 41 | setIsEditing(false); |
| 42 | return; |
| 43 | } |
| 44 | |
| 45 | let targetFrame = frame; |
| 46 | |
| 47 | try { |
| 48 | if (inputValue.includes(':')) { |
| 49 | // Parse as timecode |
| 50 | targetFrame = timecodeToFrames(inputValue, fps); |
| 51 | } else { |
| 52 | // Parse as frame number |
| 53 | const parsed = parseInt(inputValue, 10); |
| 54 | if (!isNaN(parsed)) { |
| 55 | targetFrame = parsed; |
| 56 | } |
| 57 | } |
| 58 | } catch (e) { |
| 59 | console.warn('Invalid timecode input:', inputValue); |
| 60 | // Revert on error |
| 61 | setIsEditing(false); |
| 62 | return; |
| 63 | } |
| 64 | |
| 65 | // Clamp |
| 66 | targetFrame = Math.max(0, Math.min(targetFrame, totalFrames)); |
| 67 | |
| 68 | if (targetFrame !== frame) { |
| 69 | onChange(targetFrame); |
| 70 | } |
| 71 | setIsEditing(false); |
| 72 | }; |
| 73 | |
| 74 | const handleKeyDown = (e: React.KeyboardEvent) => { |
| 75 | if (e.key === 'Enter') { |
no test coverage detected