docusaurus/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/index.tsx
2024-12-06 18:03:04 +01:00

71 lines
2 KiB
TypeScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import React, {
useCallback,
useState,
useRef,
useEffect,
type ReactNode,
} from 'react';
import clsx from 'clsx';
import copy from 'copy-text-to-clipboard';
import {translate} from '@docusaurus/Translate';
import type {Props} from '@theme/CodeBlock/CopyButton';
import IconCopy from '@theme/Icon/Copy';
import IconSuccess from '@theme/Icon/Success';
import styles from './styles.module.css';
export default function CopyButton({code, className}: Props): ReactNode {
const [isCopied, setIsCopied] = useState(false);
const copyTimeout = useRef<number | undefined>(undefined);
const handleCopyCode = useCallback(() => {
copy(code);
setIsCopied(true);
copyTimeout.current = window.setTimeout(() => {
setIsCopied(false);
}, 1000);
}, [code]);
useEffect(() => () => window.clearTimeout(copyTimeout.current), []);
return (
<button
type="button"
aria-label={
isCopied
? translate({
id: 'theme.CodeBlock.copied',
message: 'Copied',
description: 'The copied button label on code blocks',
})
: translate({
id: 'theme.CodeBlock.copyButtonAriaLabel',
message: 'Copy code to clipboard',
description: 'The ARIA label for copy code blocks button',
})
}
title={translate({
id: 'theme.CodeBlock.copy',
message: 'Copy',
description: 'The copy button label on code blocks',
})}
className={clsx(
'clean-btn',
className,
styles.copyButton,
isCopied && styles.copyButtonCopied,
)}
onClick={handleCopyCode}>
<span className={styles.copyButtonIcons} aria-hidden="true">
<IconCopy className={styles.copyButtonIcon} />
<IconSuccess className={styles.copyButtonSuccessIcon} />
</span>
</button>
);
}