{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "copy-button",
  "type": "registry:ui",
  "title": "CopyButton",
  "description": "دکمهٔ کپی در کلیپ‌بورد با بازخورد «کپی شد» برای چشم و صفحه‌خوان",
  "registryDependencies": [
    "https://kashi.sepantapouya.com/r/button.json",
    "https://kashi.sepantapouya.com/r/cx.json",
    "https://kashi.sepantapouya.com/r/kashi-provider.json"
  ],
  "files": [
    {
      "path": "registry/kashi/CopyButton.tsx",
      "type": "registry:ui",
      "target": "components/kashi/CopyButton.tsx",
      "content": "\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { Button, type ButtonProps } from \"./Button\";\nimport { useKashi } from \"./KashiProvider\";\n\nexport interface CopyButtonProps extends Omit<ButtonProps, \"onClick\" | \"children\" | \"onCopy\"> {\n  /** متنی که کپی می‌شود */\n  value: string;\n  /** پس از کپی موفق */\n  onCopy?: (value: string) => void;\n  /** فقط آیکون (نام دسترس‌پذیر از labels.copy) */\n  iconOnly?: boolean;\n  /** مدت نمایش «کپی شد» @default 2000 */\n  timeout?: number;\n  labels?: { copy?: string; copied?: string; failed?: string };\n}\n\nconst CopyIcon = () => (\n  <svg viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.7} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n    <rect x=\"7\" y=\"7\" width=\"10\" height=\"10\" rx=\"2\" /><path d=\"M13 7V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2\" />\n  </svg>\n);\nconst CheckIcon = () => (\n  <svg viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\"><path d=\"m5 10.5 3.2 3L15 7\" /></svg>\n);\n\n/** دکمهٔ کپی در کلیپ‌بورد با بازخورد «کپی شد» برای چشم و صفحه‌خوان */\nexport function CopyButton({ value, onCopy, iconOnly, timeout = 2000, labels = {}, variant = \"secondary\", size = \"sm\", ...rest }: CopyButtonProps) {\n  const { messages: M } = useKashi();\n  const { copy = M.copy.copy, copied = M.copy.copied, failed = M.copy.failed } = labels;\n  const [state, setState] = useState<\"idle\" | \"copied\" | \"failed\">(\"idle\");\n  const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n  useEffect(() => () => clearTimeout(timer.current), []);\n\n  const run = async () => {\n    try {\n      await navigator.clipboard.writeText(value);\n      setState(\"copied\");\n      onCopy?.(value);\n    } catch {\n      setState(\"failed\");\n    }\n    clearTimeout(timer.current);\n    timer.current = setTimeout(() => setState(\"idle\"), timeout);\n  };\n\n  const text = state === \"copied\" ? copied : state === \"failed\" ? failed : copy;\n  return (\n    <>\n      <Button\n        variant={variant}\n        size={size}\n        iconOnly={iconOnly}\n        aria-label={iconOnly ? text : undefined}\n        iconStart={iconOnly ? undefined : state === \"copied\" ? <CheckIcon /> : <CopyIcon />}\n        data-copied={state === \"copied\" ? \"\" : undefined}\n        onClick={run}\n        {...rest}\n      >\n        {iconOnly ? (state === \"copied\" ? <CheckIcon /> : <CopyIcon />) : text}\n      </Button>\n      <span className=\"k-sr-only\" aria-live=\"polite\">{state === \"idle\" ? \"\" : text}</span>\n    </>\n  );\n}\n"
    }
  ]
}