{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "rating",
  "title": "Rating",
  "description": "Star rating input with hover preview and a pop cascade.",
  "dependencies": [],
  "registryDependencies": [
    "utils",
    "https://ui.cuelark.com/r/theme.json",
    "https://ui.cuelark.com/r/motion.json"
  ],
  "files": [
    {
      "path": "src/registry/cuelark/ui/rating.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport { gsap, motionScale } from \"@/lib/motion\";\nimport { cn } from \"@/lib/utils\";\n\ntype RatingProps = Omit<React.ComponentProps<\"div\">, \"onChange\" | \"defaultValue\"> & {\n  value?: number;\n  defaultValue?: number;\n  onValueChange?: (value: number) => void;\n  max?: number;\n  readOnly?: boolean;\n  size?: \"sm\" | \"md\" | \"lg\";\n  /** Accessible name of the group, e.g. \"Rate this template\". */\n  label?: string;\n};\n\nconst sizes = { sm: \"size-4\", md: \"size-5\", lg: \"size-7\" };\n\n/**\n * Star rating as a radio group (arrow keys, Home/End). Hover previews the score; choosing one pops the\n * stars up to it in a quick cascade.\n */\nfunction Rating({ className, value, defaultValue = 0, onValueChange, max = 5, readOnly = false, size = \"md\", label = \"Rating\", ...props }: RatingProps) {\n  const [internal, setInternal] = React.useState(defaultValue);\n  const current = value ?? internal;\n  const [hover, setHover] = React.useState<number | null>(null);\n  const rootRef = React.useRef<HTMLDivElement>(null);\n  const shown = hover ?? current;\n\n  const choose = (n: number) => {\n    if (readOnly) return;\n    setInternal(n);\n    onValueChange?.(n);\n    const root = rootRef.current;\n    const scale = root ? motionScale(root) : 0;\n    if (!root || !scale) return;\n    const stars = Array.from(root.querySelectorAll(\"svg\")).slice(0, n);\n    gsap.fromTo(stars, { scale: 1 + 0.35 * scale, rotate: -12 * scale }, { scale: 1, rotate: 0, duration: 0.5, ease: \"cue-snap\", stagger: 0.04 });\n    rootRef.current?.querySelector<HTMLButtonElement>(`[data-value=\"${n}\"]`)?.focus();\n  };\n\n  return (\n    <div\n      ref={rootRef}\n      role={readOnly ? \"img\" : \"radiogroup\"}\n      aria-label={readOnly ? `${label}: ${current} out of ${max}` : label}\n      data-slot=\"rating\"\n      className={cn(\"inline-flex items-center gap-0.5\", className)}\n      onPointerLeave={() => setHover(null)}\n      {...props}\n    >\n      {Array.from({ length: max }, (_, i) => {\n        const n = i + 1;\n        const filled = n <= shown;\n        const star = (\n          <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" className={cn(sizes[size], \"transition-colors duration-150\", filled ? \"fill-warning text-warning\" : \"fill-muted text-border\")}>\n            <path\n              stroke=\"currentColor\"\n              strokeWidth=\"1.5\"\n              strokeLinejoin=\"round\"\n              d=\"M12 3.5l2.6 5.3 5.9.9-4.25 4.1 1 5.8L12 16.9l-5.25 2.7 1-5.8L3.5 9.7l5.9-.9L12 3.5z\"\n            />\n          </svg>\n        );\n        if (readOnly) return <span key={n}>{star}</span>;\n        return (\n          <button\n            key={n}\n            type=\"button\"\n            role=\"radio\"\n            aria-checked={n === current}\n            aria-label={`${n} of ${max}`}\n            data-value={n}\n            tabIndex={n === (current || 1) ? 0 : -1}\n            onPointerEnter={() => setHover(n)}\n            onClick={() => choose(n)}\n            onKeyDown={(e) => {\n              const next = { ArrowRight: n + 1, ArrowUp: n + 1, ArrowLeft: n - 1, ArrowDown: n - 1, Home: 1, End: max }[e.key];\n              if (next === undefined) return;\n              e.preventDefault();\n              choose(Math.min(max, Math.max(1, next)));\n            }}\n            className=\"rounded-sm outline-none focus-visible:ring-3 focus-visible:ring-ring/50\"\n          >\n            {star}\n          </button>\n        );\n      })}\n    </div>\n  );\n}\n\nexport { Rating };\nexport type { RatingProps };\n",
      "type": "registry:ui"
    }
  ],
  "docs": "Docs and examples: https://ui.cuelark.com/components/rating",
  "categories": [
    "forms"
  ],
  "type": "registry:ui"
}