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;
|