{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "vote-control",
  "title": "Vote Control",
  "author": "Ben Hofstetter <ben.hofstetter@gmail.com>",
  "description": "A Reddit-style upvote/downvote control with score display and vote retraction. Self-contained with internal state.",
  "type": "registry:component",
  "categories": [
    "snax"
  ],
  "dependencies": [
    "lucide-react"
  ],
  "files": [
    {
      "path": "src/registry/components/vote-control/vote-control.tsx",
      "content": "\"use client\"\n\nimport { cn } from \"@/lib/utils\"\nimport { ArrowUp, ArrowDown } from \"lucide-react\"\nimport { useState } from \"react\"\n\nexport function VoteControl({\n  initialVotes = 0,\n  onVote,\n  className,\n}: React.ComponentProps<\"div\"> & {\n  initialVotes?: number\n  onVote?: (direction: \"up\" | \"down\", newScore: number) => void\n}) {\n  const [score, setScore] = useState(initialVotes)\n  const [voted, setVoted] = useState<\"up\" | \"down\" | null>(null)\n\n  const handleVote = (direction: \"up\" | \"down\") => {\n    if (voted === direction) {\n      // Retract vote\n      const delta = direction === \"up\" ? -1 : 1\n      const newScore = score + delta\n      setScore(newScore)\n      setVoted(null)\n      onVote?.(direction, newScore)\n    } else {\n      // Change or new vote\n      const delta = voted === null\n        ? (direction === \"up\" ? 1 : -1)\n        : (direction === \"up\" ? 2 : -2)\n      const newScore = score + delta\n      setScore(newScore)\n      setVoted(direction)\n      onVote?.(direction, newScore)\n    }\n  }\n\n  return (\n    <div className={cn(\"flex items-center gap-1\", className)}>\n      <button\n        onClick={() => handleVote(\"up\")}\n        className={cn(\n          \"flex size-7 items-center justify-center rounded-md border transition-all\",\n          voted === \"up\" ? \"border-foreground bg-foreground text-background\" : \"border-border hover:border-foreground\",\n        )}\n        aria-label=\"Upvote\"\n      >\n        <ArrowUp className=\"size-3.5\" />\n      </button>\n      <span className=\"min-w-[2rem] text-center font-mono text-sm font-medium\">{score}</span>\n      <button\n        onClick={() => handleVote(\"down\")}\n        className={cn(\n          \"flex size-7 items-center justify-center rounded-md border transition-all\",\n          voted === \"down\" ? \"border-foreground bg-foreground text-background\" : \"border-border hover:border-foreground\",\n        )}\n        aria-label=\"Downvote\"\n      >\n        <ArrowDown className=\"size-3.5\" />\n      </button>\n    </div>\n  )\n}",
      "type": "registry:component",
      "target": "@components/vote-control.tsx"
    }
  ]
}