57 lines
1.4 KiB
TypeScript
57 lines
1.4 KiB
TypeScript
import { useState } from 'react';
|
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
import { faCheck, faCopy } from "@fortawesome/free-solid-svg-icons";
|
|
|
|
interface CopyButtonProps {
|
|
value: string;
|
|
label?: string;
|
|
className?: string;
|
|
}
|
|
|
|
export function CopyButton({ value, label = 'Copy', className = '' }: CopyButtonProps) {
|
|
const [copied, setCopied] = useState(false);
|
|
|
|
const onClick = async () => {
|
|
try {
|
|
await navigator.clipboard.writeText(value);
|
|
} catch {
|
|
// Fallback: use a hidden textarea + execCommand for older browsers.
|
|
const ta = document.createElement('textarea');
|
|
ta.value = value;
|
|
ta.style.position = 'fixed';
|
|
ta.style.opacity = '0';
|
|
document.body.appendChild(ta);
|
|
ta.select();
|
|
try {
|
|
document.execCommand('copy');
|
|
} catch {
|
|
/* swallow */
|
|
}
|
|
document.body.removeChild(ta);
|
|
}
|
|
setCopied(true);
|
|
window.setTimeout(() => setCopied(false), 1500);
|
|
};
|
|
|
|
return (
|
|
<button
|
|
type="button"
|
|
onClick={onClick}
|
|
className={`btn-ghost ${className}`}
|
|
aria-label={copied ? 'Copied' : label}
|
|
>
|
|
{copied ? (
|
|
<>
|
|
<FontAwesomeIcon icon={faCheck} className="w-4 h-4 text-emerald-400" />
|
|
<span>Copied!</span>
|
|
</>
|
|
) : (
|
|
<>
|
|
<FontAwesomeIcon icon={faCopy} className="w-4 h-4" />
|
|
<span>{label}</span>
|
|
</>
|
|
)}
|
|
</button>
|
|
);
|
|
}
|