CopyButton.tsx 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import { Check, Copy } from 'lucide-react'
  2. import { ComponentProps, forwardRef, useEffect, useState } from 'react'
  3. import { Button, cn, copyToClipboard } from 'ui'
  4. type CopyButtonBaseProps = {
  5. iconOnly?: boolean
  6. copyLabel?: string
  7. copiedLabel?: string
  8. }
  9. type CopyButtonWithText = CopyButtonBaseProps & {
  10. text: string
  11. asyncText?: never
  12. }
  13. type CopyButtonWithAsyncText = CopyButtonBaseProps & {
  14. text?: never
  15. asyncText: () => Promise<string> | string
  16. }
  17. export type CopyButtonProps = (CopyButtonWithText | CopyButtonWithAsyncText) &
  18. ComponentProps<typeof Button>
  19. const CopyButton = forwardRef<HTMLButtonElement, CopyButtonProps>(
  20. (
  21. {
  22. text,
  23. asyncText,
  24. iconOnly = false,
  25. children,
  26. onClick,
  27. copyLabel = 'Copy',
  28. copiedLabel = 'Copied',
  29. type = 'primary',
  30. icon,
  31. className,
  32. ...props
  33. },
  34. ref
  35. ) => {
  36. const [showCopied, setShowCopied] = useState(false)
  37. useEffect(() => {
  38. if (!showCopied) return
  39. const timer = setTimeout(() => setShowCopied(false), 2000)
  40. return () => clearTimeout(timer)
  41. }, [showCopied])
  42. return (
  43. <Button
  44. ref={ref}
  45. onClick={(e) => {
  46. const textToCopy = asyncText ? asyncText() : text
  47. setShowCopied(true)
  48. copyToClipboard(textToCopy)
  49. onClick?.(e)
  50. }}
  51. {...props}
  52. type={type}
  53. className={cn({ 'px-1': iconOnly }, className)}
  54. icon={
  55. showCopied ? (
  56. <Check
  57. strokeWidth={2}
  58. className={cn(type === 'primary' ? 'text-inherit' : 'text-brand')}
  59. />
  60. ) : (
  61. (icon ?? <Copy />)
  62. )
  63. }
  64. >
  65. {!iconOnly && <>{children ?? (showCopied ? copiedLabel : copyLabel)}</>}
  66. </Button>
  67. )
  68. }
  69. )
  70. CopyButton.displayName = 'CopyButton'
  71. export default CopyButton