{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "components-community-pin-list",
  "title": "Pin List",
  "description": "A playful list for pinning and unpinning items, with smooth animated transitions as items move between groups.",
  "dependencies": [
    "motion",
    "lucide-react"
  ],
  "files": [
    {
      "path": "registry/components/community/pin-list/index.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport { Pin } from 'lucide-react';\nimport {\n  motion,\n  LayoutGroup,\n  AnimatePresence,\n  type HTMLMotionProps,\n  type Transition,\n} from 'motion/react';\nimport { cn } from '@/lib/utils';\n\ntype PinListItem = {\n  id: number;\n  name: string;\n  info: string;\n  icon: React.ElementType;\n  pinned: boolean;\n};\n\ntype PinListProps = {\n  items: PinListItem[];\n  labels?: {\n    pinned?: string;\n    unpinned?: string;\n  };\n  transition?: Transition;\n  labelMotionProps?: HTMLMotionProps<'p'>;\n  className?: string;\n  labelClassName?: string;\n  pinnedSectionClassName?: string;\n  unpinnedSectionClassName?: string;\n  zIndexResetDelay?: number;\n} & HTMLMotionProps<'div'>;\n\nfunction PinList({\n  items,\n  labels = { pinned: 'Pinned Items', unpinned: 'All Items' },\n  transition = { stiffness: 320, damping: 20, mass: 0.8, type: 'spring' },\n  labelMotionProps = {\n    initial: { opacity: 0 },\n    animate: { opacity: 1 },\n    exit: { opacity: 0 },\n    transition: { duration: 0.22, ease: 'easeInOut' },\n  },\n  className,\n  labelClassName,\n  pinnedSectionClassName,\n  unpinnedSectionClassName,\n  zIndexResetDelay = 500,\n  ...props\n}: PinListProps) {\n  const [listItems, setListItems] = React.useState(items);\n  const [togglingGroup, setTogglingGroup] = React.useState<\n    'pinned' | 'unpinned' | null\n  >(null);\n\n  const pinned = listItems.filter((u) => u.pinned);\n  const unpinned = listItems.filter((u) => !u.pinned);\n\n  const toggleStatus = (id: number) => {\n    const item = listItems.find((u) => u.id === id);\n    if (!item) return;\n\n    setTogglingGroup(item.pinned ? 'pinned' : 'unpinned');\n    setListItems((prev) => {\n      const idx = prev.findIndex((u) => u.id === id);\n      if (idx === -1) return prev;\n      const updated = [...prev];\n      const [item] = updated.splice(idx, 1);\n      if (!item) return prev;\n      const toggled = { ...item, pinned: !item.pinned };\n      if (toggled.pinned) updated.push(toggled);\n      else updated.unshift(toggled);\n      return updated;\n    });\n    // Reset group z-index after the animation duration (keep in sync with animation timing)\n    setTimeout(() => setTogglingGroup(null), zIndexResetDelay);\n  };\n\n  return (\n    <motion.div className={cn('space-y-10', className)} {...props}>\n      <LayoutGroup>\n        <div>\n          {pinned.length > 0 && (\n            <div\n              className={cn(\n                'space-y-3 relative',\n                togglingGroup === 'pinned' ? 'z-5' : 'z-10',\n                pinnedSectionClassName,\n              )}\n            >\n              {pinned.map((item) => (\n                <motion.div\n                  key={item.id}\n                  layoutId={`item-${item.id}`}\n                  onClick={() => toggleStatus(item.id)}\n                  transition={transition}\n                  className=\"flex items-center justify-between gap-5 rounded-2xl bg-neutral-200 dark:bg-neutral-800 p-2\"\n                >\n                  <div className=\"flex items-center gap-2\">\n                    <div className=\"rounded-lg bg-background p-2\">\n                      <item.icon className=\"size-5 text-neutral-500 dark:text-neutral-400\" />\n                    </div>\n                    <div>\n                      <div className=\"text-sm font-semibold\">{item.name}</div>\n                      <div className=\"text-xs text-neutral-500 dark:text-neutral-400 font-medium\">\n                        {item.info}\n                      </div>\n                    </div>\n                  </div>\n                  <div className=\"flex items-center justify-center size-8 rounded-full bg-neutral-400 dark:bg-neutral-600\">\n                    <Pin className=\"size-4 text-white fill-white\" />\n                  </div>\n                </motion.div>\n              ))}\n            </div>\n          )}\n        </div>\n\n        <div>\n          <AnimatePresence>\n            {unpinned.length > 0 && (\n              <motion.p\n                layout\n                key=\"all-label\"\n                className={cn(\n                  'font-medium px-3 text-neutral-500 dark:text-neutral-300 text-sm mb-2',\n                  labelClassName,\n                )}\n                {...labelMotionProps}\n              >\n                {labels.unpinned}\n              </motion.p>\n            )}\n          </AnimatePresence>\n          {unpinned.length > 0 && (\n            <div\n              className={cn(\n                'space-y-3 relative',\n                togglingGroup === 'unpinned' ? 'z-5' : 'z-10',\n                unpinnedSectionClassName,\n              )}\n            >\n              {unpinned.map((item) => (\n                <motion.div\n                  key={item.id}\n                  layoutId={`item-${item.id}`}\n                  onClick={() => toggleStatus(item.id)}\n                  transition={transition}\n                  className=\"flex items-center justify-between gap-5 rounded-2xl bg-neutral-200 dark:bg-neutral-800 p-2 group\"\n                >\n                  <div className=\"flex items-center gap-2\">\n                    <div className=\"rounded-lg bg-background p-2\">\n                      <item.icon className=\"size-5 text-neutral-500 dark:text-neutral-400\" />\n                    </div>\n                    <div>\n                      <div className=\"text-sm font-semibold\">{item.name}</div>\n                      <div className=\"text-xs text-neutral-500 dark:text-neutral-400 font-medium\">\n                        {item.info}\n                      </div>\n                    </div>\n                  </div>\n                  <div className=\"flex items-center justify-center size-8 rounded-full bg-neutral-400 dark:bg-neutral-600 opacity-0 group-hover:opacity-100 transition-opacity duration-250\">\n                    <Pin className=\"size-4 text-white\" />\n                  </div>\n                </motion.div>\n              ))}\n            </div>\n          )}\n        </div>\n      </LayoutGroup>\n    </motion.div>\n  );\n}\n\nexport { PinList, type PinListProps, type PinListItem };\n",
      "type": "registry:ui",
      "target": "components/animate-ui/components/community/pin-list.tsx"
    }
  ],
  "type": "registry:ui"
}