{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "confetti-button",
  "type": "registry:component",
  "title": "Confetti button",
  "description": "A React button that bursts confetti from itself on click, with gravity, drag and spin on a temporary canvas. No library, and skipped for reduced motion.",
  "dependencies": [
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/premium/confetti-button.tsx",
      "type": "registry:ui",
      "target": "components/ui/confetti-button.tsx",
      "content": "\"use client\"\nimport * as React from \"react\"\nimport { useReducedMotion } from \"motion/react\"\nimport { PartyPopperIcon } from \"lucide-react\"\nimport { cn } from \"@/lib/utils\"\n\n/**\n * A button that bursts confetti from itself on click: a few dozen paper\n * pieces with gravity, drag and spin, drawn on a throwaway canvas and\n * cleaned up when they land. No library. Reduced motion skips the burst.\n */\ntype ConfettiButtonProps = React.ComponentProps<\"button\"> & {\n  /** Number of pieces per burst. */\n  count?: number\n  colors?: string[]\n}\n\nfunction burst(el: HTMLElement, count: number, colors: string[]) {\n  const r = el.getBoundingClientRect()\n  const c = document.createElement(\"canvas\")\n  const dpr = window.devicePixelRatio || 1\n  c.width = innerWidth * dpr\n  c.height = innerHeight * dpr\n  Object.assign(c.style, { position: \"fixed\", inset: \"0\", width: \"100vw\", height: \"100vh\", pointerEvents: \"none\", zIndex: \"9999\" })\n  document.body.appendChild(c)\n  const ctx = c.getContext(\"2d\")!\n  ctx.scale(dpr, dpr)\n  const ox = r.left + r.width / 2\n  const oy = r.top + r.height / 2\n  const parts = Array.from({ length: count }, () => {\n    const a = -Math.PI / 2 + (Math.random() - 0.5) * 1.6\n    const v = 7 + Math.random() * 7\n    return { x: ox, y: oy, vx: Math.cos(a) * v, vy: Math.sin(a) * v, w: 6 + Math.random() * 5, h: 8 + Math.random() * 8, rot: Math.random() * 6, vr: (Math.random() - 0.5) * 0.4, color: colors[Math.floor(Math.random() * colors.length)], life: 0 }\n  })\n  let raf = 0\n  const tick = () => {\n    ctx.clearRect(0, 0, innerWidth, innerHeight)\n    let alive = 0\n    for (const p of parts) {\n      p.life++\n      p.vy += 0.28\n      p.vx *= 0.985\n      p.vy *= 0.985\n      p.x += p.vx\n      p.y += p.vy\n      p.rot += p.vr\n      if (p.y < innerHeight + 40 && p.life < 240) alive++\n      ctx.save()\n      ctx.translate(p.x, p.y)\n      ctx.rotate(p.rot)\n      ctx.globalAlpha = Math.max(0, 1 - p.life / 240)\n      ctx.fillStyle = p.color\n      ctx.fillRect(-p.w / 2, (-p.h / 2) * Math.abs(Math.cos(p.rot * 2)), p.w, p.h * Math.abs(Math.cos(p.rot * 2)) + 1)\n      ctx.restore()\n    }\n    if (alive) raf = requestAnimationFrame(tick)\n    else c.remove()\n  }\n  raf = requestAnimationFrame(tick)\n  return () => {\n    cancelAnimationFrame(raf)\n    c.remove()\n  }\n}\n\nfunction ConfettiButton({ children = <><PartyPopperIcon className=\"size-4\" /> Celebrate</>, count = 70, colors, className, onClick, ...props }: ConfettiButtonProps) {\n  const reduce = useReducedMotion()\n  const ref = React.useRef<HTMLButtonElement>(null)\n  return (\n    <button\n      ref={ref}\n      type=\"button\"\n      data-slot=\"confetti-button\"\n      onClick={(e) => {\n        onClick?.(e)\n        if (reduce || !ref.current) return\n        const css = getComputedStyle(ref.current)\n        const palette = colors ?? [css.getPropertyValue(\"--accent\"), css.getPropertyValue(\"--accent-2\"), css.getPropertyValue(\"--success\"), css.getPropertyValue(\"--warning\"), \"#ffffff\"].map((x) => x.trim() || \"#8b7cff\")\n        burst(ref.current, count, palette)\n      }}\n      className={cn(\n        \"inline-flex h-11 items-center gap-2 rounded-xl bg-ink px-5 text-[0.9375rem] font-medium text-on-ink shadow-ink outline-none transition-transform active:scale-[0.97] focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-bg\",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </button>\n  )\n}\n\nexport { ConfettiButton }\nexport type { ConfettiButtonProps }\n"
    }
  ]
}
