{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "copy-button",
"title": "Copy Button",
"description": "Outline icon button that copies text to the clipboard and confirms with a check for 1.5s. Optional label swaps to \"Copied\".",
"dependencies": [
"lucide-react"
],
"registryDependencies": [
"https://ds.formance.com/r/button.json"
],
"files": [
{
"path": "registry/default/ui-fragments/copy-button.tsx",
"content": "'use client';\n\n/**\n * CopyButton — outline icon button that copies text to the clipboard and\n * confirms with a check for 1.5s.\n *\n * icon only\n * icon + label, swaps to \"Copied\"\n *\n * Used by ApiSnippet and LedgerSchema so copy / play actions read consistently\n * across fragments. Clicks are stopped from propagating, so the button is safe\n * inside a clickable row or card header.\n */\n\nimport { Check, Copy } from 'lucide-react';\nimport { useEffect, useRef, useState } from 'react';\n\nimport { cn } from '@/lib/utils';\nimport { Button } from '@/registry/default/ui/button';\n\nexport type TCopyButtonProps = {\n text: string;\n label?: string;\n className?: string;\n};\n\nexport function CopyButton({ text, label, className }: TCopyButtonProps) {\n const [copied, setCopied] = useState(false);\n const resetTimer = useRef>(undefined);\n\n // The timer outlives the click that started it: a second click within 1.5s\n // would otherwise let the first one reset the state while the button still\n // reads \"Copied\", and an unmount would leave it pending.\n useEffect(() => () => clearTimeout(resetTimer.current), []);\n\n return (\n \n );\n}\n",
"type": "registry:component",
"target": "components/ui-fragments/copy-button.tsx"
}
],
"type": "registry:component"
}