"use client"
import * as React from "react"
import { IconCheck as Check, IconCopy as Copy } from "@tabler/icons-react"
import { SwapButton, type SwapButtonProps } from "@/registry/ui/swap-button"
type CopyLabelButtonProps = Omit<SwapButtonProps, "states" | "state" | "onClick" | "loading"> & {
/** What lands on the clipboard. Pass a function when the text is built at
* click time, so the copy is never a stale render. */
text: string | (() => string)
/** The resting label. */
label?: React.ReactNode
/** The label while the check shows. */
copiedLabel?: React.ReactNode
/** Called after a successful copy, e.g. to show a toast. Not called when the
* clipboard refuses, so the button never claims a copy that did not happen. */
onCopied?: () => void
/** How long the copied state holds, in ms. */
resetAfter?: number
}
/**
* A labelled button that copies text and confirms in place: the copy glyph
* becomes a check and the label becomes `copiedLabel`, then both return. It is
* a `SwapButton` with two faces, so the width never changes and the content
* stays centred.
*/
// @use-when a labelled button that copies text and confirms in place, swapping its icon and label without changing width. For the icon-only affordance on a code sample, use `CopyButton`.
function CopyLabelButton({
text,
label = "Copy",
copiedLabel = "Copied",
onCopied,
resetAfter = 1500,
...props
}: CopyLabelButtonProps) {
const [copied, setCopied] = React.useState(false)
const timerRef = React.useRef<ReturnType<typeof setTimeout> | null>(null)
React.useEffect(() => {
return () => {
if (timerRef.current) clearTimeout(timerRef.current)
}
}, [])
const handleClick = React.useCallback(async () => {
try {
await navigator.clipboard.writeText(typeof text === "function" ? text() : text)
} catch {
return
}
setCopied(true)
onCopied?.()
if (timerRef.current) clearTimeout(timerRef.current)
timerRef.current = setTimeout(() => setCopied(false), resetAfter)
}, [text, onCopied, resetAfter])
return (
<SwapButton
data-slot="copy-label-button"
state={copied ? "copied" : "copy"}
states={{
copy: { icon: <Copy />, label },
copied: { icon: <Check />, label: copiedLabel },
}}
onClick={handleClick}
{...props}
/>
)
}
export { CopyLabelButton }
export type { CopyLabelButtonProps }