# 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 copyPromise = useRef<Promise<void> | null>(null);

        useEffect(() => {
          setCopied(false);
          return () => {
            // Clear any potential ongoing promise on changing value or unmounting
            copyPromise.current = null;
          };
        }, [textToCopy]);

        const handleClick = useCallback(() => {
          const p = navigator.clipboard
            .writeText(textToCopy)
            .then(() => {
              Eif (copyPromise.current === p) {
                // Display copied for 10 seconds
                setCopied(true);
                onCopy?.(textToCopy);
                return sleep(10000);
              }
              return null;
            })
            .then(() => {
              if (copyPromise.current === p) {
                setCopied(false);
              }
            });
          copyPromise.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;