66 lines · 1.8 KB · TypeScript
RawDownload
import * as React from "react"; export function useCopyToClipboard<TContext = void>({  timeout = 2000,  onCopy,  onError,}: {  timeout?: number;  onCopy?: (ctx: TContext) => void;  onError?: (error: Error, ctx: TContext) => void;} = {}): { copyToClipboard: (value: string, ctx: TContext) => void; isCopied: boolean } {  const [isCopied, setIsCopied] = React.useState(false);  const timeoutIdRef = React.useRef<NodeJS.Timeout | null>(null);  const onCopyRef = React.useRef(onCopy);  const onErrorRef = React.useRef(onError);  const timeoutRef = React.useRef(timeout);   onCopyRef.current = onCopy;  onErrorRef.current = onError;  timeoutRef.current = timeout;   const copyToClipboard = React.useCallback((value: string, ctx: TContext): void => {    if (typeof window === "undefined" || !navigator.clipboard?.writeText) {      onErrorRef.current?.(new Error("Clipboard API unavailable."), ctx);      return;    }     if (!value) return;     navigator.clipboard.writeText(value).then(      () => {        if (timeoutIdRef.current) {          clearTimeout(timeoutIdRef.current);        }        setIsCopied(true);         onCopyRef.current?.(ctx);         if (timeoutRef.current !== 0) {          timeoutIdRef.current = setTimeout(() => {            setIsCopied(false);            timeoutIdRef.current = null;          }, timeoutRef.current);        }      },      (error) => {        if (onErrorRef.current) {          onErrorRef.current(error, ctx);        } else {          console.error(error);        }      },    );  }, []);   // Cleanup timeout on unmount  React.useEffect(() => {    return (): void => {      if (timeoutIdRef.current) {        clearTimeout(timeoutIdRef.current);      }    };  }, []);   return { copyToClipboard, isCopied };}