{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "input-copy", "title": "Input Copy", "description": "Read-only input with a copy-to-clipboard button and animated check feedback. Supports optional label and shape context.", "dependencies": [ "framer-motion" ], "registryDependencies": [ "https://zeron-ui.vercel.app/r/surfaces.json", "utils", "https://zeron-ui.vercel.app/r/springs.json", "https://zeron-ui.vercel.app/r/shape-context.json", "https://zeron-ui.vercel.app/r/icon-context.json" ], "files": [ { "path": "src/components/ui/input-copy.tsx", "content": "\"use client\";\n\nimport { forwardRef, useState, useCallback, useRef, useEffect, useId, type HTMLAttributes } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport { cn } from \"@/lib/utils\";\nimport { useIcon } from \"@/lib/icon-context\";\nimport { useShape } from \"@/lib/shape-context\";\nimport { spring } from \"@/lib/springs\";\nimport { Tooltip } from \"@/components/ui/tooltip\";\n\ntype InputCopyVariant = \"icon\" | \"button\";\ntype InputCopyAlign = \"right\" | \"left\";\n\ninterface InputCopyProps extends Omit, \"children\"> {\n /** The value to display and copy to clipboard. */\n value: string;\n /** Optional label displayed above the input. */\n label?: string;\n /** Callback fired after the value is copied. */\n onCopy?: () => void;\n /** Whether the component is disabled. */\n disabled?: boolean;\n /** Display variant: icon-only with tooltip, or button with label. */\n variant?: InputCopyVariant;\n /** Position of the copy action relative to the value. */\n align?: InputCopyAlign;\n}\n\nconst InputCopy = forwardRef(\n ({ value, label, onCopy, disabled, variant = \"icon\", align = \"right\", className, ...props }, ref) => {\n const CopyIcon = useIcon(\"copy\");\n // \"copied\" and \"error\" both occupy the same animation slot on the button\n const [status, setStatus] = useState<\"idle\" | \"copied\" | \"error\">(\"idle\");\n const [copyCount, setCopyCount] = useState(0);\n // \"idle\" = normal tooltip behavior, \"copied\" = force open, \"suppressed\" = force closed\n const [tooltipState, setTooltipState] = useState<\"idle\" | \"copied\" | \"suppressed\">(\"idle\");\n const timeoutRef = useRef>(null);\n const tooltipVisibleRef = useRef(false);\n const tooltipWasVisibleRef = useRef(false);\n const shape = useShape();\n\n // Associate the visible label with the button: the button's accessible\n // name reads \"Copy