import { useEffect, useRef, useState, type KeyboardEvent, type ReactNode } from "react"; import { useTranslation } from "react-i18next"; import { Check, Copy } from "lucide-react"; import { cn } from "@/lib/cn"; const VARIANT_HOVER = { default: "group-hover/copy:[&_*]:text-nb-gray-300", bright: "group-hover/copy:[&_*]:text-nb-gray-200", } as const; type CopyToClipboardVariant = keyof typeof VARIANT_HOVER; type CopyToClipboardProps = { children: ReactNode; message?: string; size?: number; iconAlignment?: "left" | "right"; className?: string; iconClassName?: string; alwaysShowIcon?: boolean; variant?: CopyToClipboardVariant; "aria-label"?: string; tabIndex?: number; onKeyDown?: (e: KeyboardEvent) => void; }; export const CopyToClipboard = ({ children, message, size = 10, iconAlignment = "right", className, iconClassName, alwaysShowIcon = false, variant = "default", "aria-label": ariaLabel, tabIndex = 0, onKeyDown, }: CopyToClipboardProps) => { const { t } = useTranslation(); const wrapperRef = useRef(null); const [copied, setCopied] = useState(false); const copyTimer = useRef | null>(null); useEffect( () => () => { if (copyTimer.current) clearTimeout(copyTimer.current); }, [], ); const handleClick = async (e: React.MouseEvent) => { e.stopPropagation(); e.preventDefault(); const text = message ?? wrapperRef.current?.innerText ?? ""; if (!text) return; try { await navigator.clipboard.writeText(text); setCopied(true); if (copyTimer.current) clearTimeout(copyTimer.current); copyTimer.current = setTimeout(() => setCopied(false), 500); } catch (e) { console.warn("copy to clipboard failed", e); } }; const resolvedLabel = ariaLabel ?? (message ? `${t("common.copy")} ${message}` : t("common.copy")); return ( ); };