({
text,
alwaysVisible: _alwaysVisible = false,
isCopied: isCopiedProp,
setIsCopied: setIsCopiedProp,
className,
...props
}: CopyButtonProps)
| 17 | } |
| 18 | |
| 19 | export function CopyButton({ |
| 20 | text, |
| 21 | alwaysVisible: _alwaysVisible = false, |
| 22 | isCopied: isCopiedProp, |
| 23 | setIsCopied: setIsCopiedProp, |
| 24 | className, |
| 25 | ...props |
| 26 | }: CopyButtonProps) { |
| 27 | const { copy } = useClipboard() |
| 28 | const [isCopiedState, setIsCopiedState] = useState(false) |
| 29 | |
| 30 | const isControlled = isCopiedProp !== undefined |
| 31 | const isCopied = isControlled ? isCopiedProp : isCopiedState |
| 32 | const setIsCopied = isControlled ? setIsCopiedProp || (() => {}) : setIsCopiedState |
| 33 | |
| 34 | useEffect(() => { |
| 35 | if (isCopied) { |
| 36 | const timeout = setTimeout(() => setIsCopied(false), 2000) |
| 37 | return () => clearTimeout(timeout) |
| 38 | } |
| 39 | }, [isCopied, setIsCopied]) |
| 40 | |
| 41 | const onPressHandler = async () => { |
| 42 | if (text) { |
| 43 | const didCopy = await copy(text) |
| 44 | if (didCopy) setIsCopied(true) |
| 45 | } |
| 46 | } |
| 47 | |
| 48 | return ( |
| 49 | <Button |
| 50 | aria-label="Copy to clipboard" |
| 51 | onPress={props.onPress || onPressHandler} |
| 52 | className={cx( |
| 53 | twJoin( |
| 54 | 'relative h-8 w-14 overflow-hidden p-1.5 font-medium pressed:text-fg text-muted-fg text-sm/6 hover:text-fg', |
| 55 | isCopied && 'text-fg' |
| 56 | ), |
| 57 | className |
| 58 | )} |
| 59 | {...props} |
| 60 | > |
| 61 | {isCopied ? <CheckIcon className="size-4" /> : <DuplicateIcon className="size-4" />} |
| 62 | </Button> |
| 63 | ) |
| 64 | } |
nothing calls this directly
no test coverage detected