{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "animated-list",
  "type": "registry:component",
  "title": "Animated list",
  "description": "A live feed where new items drop in at the top with a spring and older ones slide down. Ideal for activity streams, notifications and happening now sections.",
  "dependencies": [
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/premium/animated-list.tsx",
      "type": "registry:ui",
      "target": "components/ui/animated-list.tsx",
      "content": "\"use client\"\nimport * as React from \"react\"\nimport { AnimatePresence, motion, useInView, useReducedMotion } from \"motion/react\"\nimport { BellIcon, CircleDollarSignIcon, GitPullRequestIcon, UserPlusIcon, type LucideIcon } from \"lucide-react\"\nimport { cn } from \"@/lib/utils\"\n\n/**\n * A live feed where new items drop in at the top with a spring and older\n * ones slide down, for activity streams and \"happening now\" sections.\n * Items arrive on a timer while visible; the list is announced politely.\n */\ntype ListItem = { id?: string; icon?: LucideIcon; title: string; detail?: string; time?: string }\n\ntype AnimatedListProps = {\n  items?: ListItem[]\n  /** Milliseconds between arrivals. */\n  interval?: number\n  /** How many items to keep on screen. */\n  max?: number\n  className?: string\n}\n\nconst DEFAULT: ListItem[] = [\n  { icon: CircleDollarSignIcon, title: \"Payment received\", detail: \"Acme paid invoice #1042 · $2,400\", time: \"now\" },\n  { icon: UserPlusIcon, title: \"New signup\", detail: \"maya@northwind.io joined the Pro trial\", time: \"1m\" },\n  { icon: GitPullRequestIcon, title: \"Deploy finished\", detail: \"main → production in 42s\", time: \"3m\" },\n  { icon: BellIcon, title: \"Usage alert\", detail: \"API calls at 80% of the monthly quota\", time: \"5m\" },\n  { icon: CircleDollarSignIcon, title: \"Plan upgraded\", detail: \"Globex moved to Team · +$96/mo\", time: \"8m\" },\n]\n\nfunction AnimatedList({ items = DEFAULT, interval = 1800, max = 4, className }: AnimatedListProps) {\n  const reduce = useReducedMotion()\n  const ref = React.useRef<HTMLUListElement>(null)\n  const inView = useInView(ref, { amount: 0.4 })\n  const [count, setCount] = React.useState(reduce ? max : 1)\n  React.useEffect(() => {\n    if (reduce || !inView) return\n    const id = window.setInterval(() => setCount((c) => c + 1), interval)\n    return () => window.clearInterval(id)\n  }, [interval, reduce, inView])\n  const shown = Array.from({ length: Math.min(count, max) }, (_, k) => {\n    const n = count - 1 - k\n    const it = items[n % items.length]\n    return { ...it, key: `${it.id ?? it.title}-${n}` }\n  })\n  return (\n    <ul ref={ref} data-slot=\"animated-list\" aria-live=\"polite\" className={cn(\"flex w-full max-w-sm flex-col gap-2.5\", className)}>\n      <AnimatePresence initial={false}>\n        {shown.map((it) => {\n          const Icon = it.icon ?? BellIcon\n          return (\n            <motion.li\n              key={it.key}\n              layout={!reduce}\n              initial={{ opacity: 0, scale: 0.92, y: -12 }}\n              animate={{ opacity: 1, scale: 1, y: 0 }}\n              exit={{ opacity: 0, scale: 0.96 }}\n              transition={{ type: \"spring\", bounce: 0.25, duration: 0.5 }}\n              className=\"flex items-center gap-3 rounded-2xl border border-border bg-surface p-3.5 shadow-raised\"\n            >\n              <span className=\"grid size-9 shrink-0 place-items-center rounded-xl bg-accent-soft text-accent-fg\">\n                <Icon className=\"size-[18px]\" strokeWidth={1.75} />\n              </span>\n              <span className=\"min-w-0 flex-1\">\n                <span className=\"flex items-baseline justify-between gap-2\">\n                  <span className=\"truncate text-sm font-medium text-fg\">{it.title}</span>\n                  {it.time ? <span className=\"shrink-0 text-[11px] text-fg-subtle\">{it.time}</span> : null}\n                </span>\n                {it.detail ? <span className=\"block truncate text-[12.5px] text-fg-muted\">{it.detail}</span> : null}\n              </span>\n            </motion.li>\n          )\n        })}\n      </AnimatePresence>\n    </ul>\n  )\n}\n\nexport { AnimatedList }\nexport type { AnimatedListProps }\n"
    }
  ]
}
