| 1 | // Adapted from Harness c291e7961a: async full-content loading and lifecycle fencing. |
| 2 | import { useCallback, useEffect, useRef, useState } from "react"; |
| 3 | import { writeClipboard } from "./clipboard"; |
| 4 | |
| 5 | export function useCopyFeedback(text: string, getText?: () => Promise<string>) { |
| 6 | const [copied, setCopied] = useState(false); |
| 7 | const active = useRef(true); |
| 8 | const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined); |
| 9 | useEffect(() => { active.current = true; return () => { active.current = false; clearTimeout(timer.current); }; }, []); |
| 10 | const onCopy = useCallback(() => { |
| 11 | if (copied) return; |
| 12 | void (getText ? getText() : Promise.resolve(text)).then(async value => { |
| 13 | if (!active.current || !await writeClipboard(value) || !active.current) return; |
| 14 | setCopied(true); |
| 15 | timer.current = setTimeout(() => { if (active.current) setCopied(false); }, 1000); |
| 16 | }).catch(() => { /* Full-content failures are surfaced by the content owner. */ }); |
| 17 | }, [copied, getText, text]); |
| 18 | return { copied, onCopy }; |
| 19 | } |
| 20 |