({ rangeStart, rangeEnd, anchorX, anchorY, onClose }: EditPopoverProps)
| 14 | } |
| 15 | |
| 16 | export function EditPopover({ rangeStart, rangeEnd, anchorX, anchorY, onClose }: EditPopoverProps) { |
| 17 | const elements = usePlayerStore((s) => s.elements); |
| 18 | const [prompt, setPrompt] = useState(""); |
| 19 | const [copiedAgentPrompt, setCopiedAgentPrompt] = useState(false); |
| 20 | const [copiedPromptOnly, setCopiedPromptOnly] = useState(false); |
| 21 | const popoverRef = useRef<HTMLDivElement>(null); |
| 22 | const textareaRef = useRef<HTMLTextAreaElement>(null); |
| 23 | |
| 24 | const start = Math.min(rangeStart, rangeEnd); |
| 25 | const end = Math.max(rangeStart, rangeEnd); |
| 26 | |
| 27 | const elementsInRange = useMemo(() => { |
| 28 | return elements.filter((el) => { |
| 29 | const elEnd = el.start + el.duration; |
| 30 | return el.start < end && elEnd > start; |
| 31 | }); |
| 32 | }, [elements, start, end]); |
| 33 | |
| 34 | useMountEffect(() => { |
| 35 | setTimeout(() => textareaRef.current?.focus(), 50); |
| 36 | }); |
| 37 | |
| 38 | useMountEffect(() => { |
| 39 | const handleKey = (e: KeyboardEvent) => { |
| 40 | if (e.key === "Escape") onClose(); |
| 41 | }; |
| 42 | window.addEventListener("keydown", handleKey); |
| 43 | return () => window.removeEventListener("keydown", handleKey); |
| 44 | }); |
| 45 | |
| 46 | useMountEffect(() => { |
| 47 | const handleClick = (e: MouseEvent) => { |
| 48 | if (popoverRef.current && !popoverRef.current.contains(e.target as Node)) { |
| 49 | onClose(); |
| 50 | } |
| 51 | }; |
| 52 | setTimeout(() => window.addEventListener("mousedown", handleClick), 100); |
| 53 | return () => window.removeEventListener("mousedown", handleClick); |
| 54 | }); |
| 55 | |
| 56 | const buildClipboardText = useCallback(() => { |
| 57 | return buildTimelineAgentPrompt({ |
| 58 | rangeStart: start, |
| 59 | rangeEnd: end, |
| 60 | elements: elementsInRange, |
| 61 | prompt, |
| 62 | }); |
| 63 | }, [start, end, elementsInRange, prompt]); |
| 64 | |
| 65 | const handleCopy = useCallback(async () => { |
| 66 | const copied = await copyTextToClipboard(buildClipboardText()); |
| 67 | if (!copied) return; |
| 68 | setCopiedAgentPrompt(true); |
| 69 | setTimeout(() => { |
| 70 | setCopiedAgentPrompt(false); |
| 71 | onClose(); |
| 72 | }, 800); |
| 73 | }, [buildClipboardText, onClose]); |
nothing calls this directly
no test coverage detected