All files / src/components copy-to-clipboard.tsx

85% Statements 17/20
58.33% Branches 7/12
83.33% Functions 5/6
85% Lines 17/20

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74                                          9x               8x 8x   8x 6x 6x   6x       8x 2x     2x   2x 2x 2x                 2x     8x 3x     5x                  
import { useState, useCallback, useRef, useEffect, memo } from 'react';
import { sleep } from 'timing-functions';
 
import ButtonComponent, { type ButtonProps } from './button';
 
type Props = {
  /**
   * The text to place into the copy buffer
   */
  textToCopy: string;
  /**
   * The text placed in the button before copy event
   */
  beforeCopy?: string;
  /**
   * The text placed in the button after copy event
   */
  afterCopy?: string;
  onCopy?: (copied: string) => void;
};
 
const CopyToClipboard = memo(
  ({
    textToCopy,
    beforeCopy = 'Copy',
    afterCopy = 'Copied',
    onCopy,
    ...props
  }: Props & Omit<ButtonProps, 'onCopy'>) => {
    const [copied, setCopied] = useState(false);
    const copyPromiseRef = useRef<Promise<void> | null>(null);
 
    useEffect(() => {
      setCopied(false);
      return () => {
        // Clear any potential ongoing promise on changing value or unmounting
        copyPromiseRef.current = null;
      };
    }, [textToCopy]);
 
    const handleClick = useCallback(() => {
      const p = navigator.clipboard
        .writeText(textToCopy)
        .then(() => {
          Eif (copyPromiseRef.current === p) {
            // Display copied for 10 seconds
            setCopied(true);
            onCopy?.(textToCopy);
            return sleep(10000);
          }
          return null;
        })
        .then(() => {
          if (copyPromiseRef.current === p) {
            setCopied(false);
          }
        });
      copyPromiseRef.current = p;
    }, [onCopy, textToCopy]);
 
    if (!('clipboard' in navigator) || !('writeText' in navigator.clipboard)) {
      return null;
    }
 
    return (
      <ButtonComponent {...props} onClick={handleClick}>
        {copied ? afterCopy : beforeCopy}
      </ButtonComponent>
    );
  }
);
 
export default CopyToClipboard;