import * as React from "react"; import { buildMachineShareUrl, type ProductionShareState, } from "../../utils/productionShareState"; export interface ShareLinkButtonProps { getShareState: () => ProductionShareState; className?: string; label?: string; copiedLabel?: string; onCopied?: (url: string) => void; } async function copyText(text: string): Promise { if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) { await navigator.clipboard.writeText(text); return; } if (typeof document === "undefined") { throw new Error("Clipboard is not available in this environment."); } const textarea = document.createElement("textarea"); textarea.value = text; textarea.setAttribute("readonly", "true"); textarea.style.position = "fixed"; textarea.style.left = "-9999px"; textarea.style.top = "0"; document.body.appendChild(textarea); textarea.select(); const successful = document.execCommand("copy"); document.body.removeChild(textarea); if (!successful) { throw new Error("The browser rejected the fallback copy command."); } } export function ShareLinkButton({ getShareState, className = "", label = "Copy link", copiedLabel = "Copied", onCopied, }: ShareLinkButtonProps): JSX.Element { const [status, setStatus] = React.useState<"idle" | "copying" | "copied" | "error">("idle"); const [error, setError] = React.useState(null); const resetTimerRef = React.useRef(null); React.useEffect(() => { return () => { if (resetTimerRef.current !== null) { window.clearTimeout(resetTimerRef.current); } }; }, []); const handleCopy = async () => { setStatus("copying"); setError(null); try { const shareUrl = buildMachineShareUrl(getShareState()); await copyText(shareUrl); onCopied?.(shareUrl); setStatus("copied"); if (resetTimerRef.current !== null) { window.clearTimeout(resetTimerRef.current); } resetTimerRef.current = window.setTimeout(() => setStatus("idle"), 1800); } catch (copyError) { setStatus("error"); setError(copyError instanceof Error ? copyError.message : "Copy failed."); } }; return ( {error ? ( {error} ) : null} ); }