{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "stacked-list",
  "title": "Stacked List",
  "description": "An expandable list widget with a stacked layout and smooth morphing transitions.",
  "dependencies": [
    "motion",
    "@hugeicons/core-free-icons",
    "@hugeicons/react",
    "clsx",
    "tailwind-merge"
  ],
  "registryDependencies": [
    "input",
    "button"
  ],
  "files": [
    {
      "path": "registry/default/example/stacked-list.tsx",
      "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport { motion, AnimatePresence } from \"motion/react\";\nimport { useState, useMemo } from \"react\";\nimport { Input } from \"@/components/ui/input\";\nimport { Button } from \"@/components/ui/button\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport {\n  ProfileIcon,\n  Search01Icon,\n  Cancel01Icon,\n  Add01Icon,\n  Briefcase01Icon,\n  PaintBoardIcon,\n  Database01Icon,\n  QuillWrite01Icon,\n} from \"@hugeicons/core-free-icons\";\n\ninterface Member {\n  id: string;\n  name: string;\n  status: string;\n  online: boolean;\n  role: string;\n  roleType: \"pm\" | \"designer\" | \"data\" | \"creator\";\n  avatar: string;\n}\n\nconst ALL_MEMBERS: Member[] = [\n  {\n    id: \"01\",\n    name: \"Oliver Smith\",\n    status: \"Online\",\n    online: true,\n    role: \"Project Manager\",\n    roleType: \"pm\",\n    avatar: \"https://tapback.co/api/avatar/Oliver.webp\",\n  },\n  {\n    id: \"02\",\n    name: \"Sophie Chen\",\n    status: \"17m ago\",\n    online: false,\n    role: \"Designer\",\n    roleType: \"designer\",\n    avatar: \"https://tapback.co/api/avatar/Sophie.webp\",\n  },\n  {\n    id: \"03\",\n    name: \"Noah Wilson\",\n    status: \"29m ago\",\n    online: false,\n    role: \"Data Specialist\",\n    roleType: \"data\",\n    avatar: \"https://tapback.co/api/avatar/Noah.webp\",\n  },\n  {\n    id: \"04\",\n    name: \"Emma Davis\",\n    status: \"48m ago\",\n    online: false,\n    role: \"Creator\",\n    roleType: \"creator\",\n    avatar: \"https://tapback.co/api/avatar/Emma.webp\",\n  },\n  {\n    id: \"05\",\n    name: \"Leo Garcia\",\n    status: \"Online\",\n    online: true,\n    role: \"Designer\",\n    roleType: \"designer\",\n    avatar: \"https://tapback.co/api/avatar/Leo.webp\",\n  },\n  {\n    id: \"06\",\n    name: \"Mia Thompson\",\n    status: \"Online\",\n    online: true,\n    role: \"Project Manager\",\n    roleType: \"pm\",\n    avatar: \"https://tapback.co/api/avatar/Mia.webp\",\n  },\n  {\n    id: \"07\",\n    name: \"Ethan Wright\",\n    status: \"5h ago\",\n    online: false,\n    role: \"Data Specialist\",\n    roleType: \"data\",\n    avatar: \"https://tapback.co/api/avatar/Ethan.webp\",\n  },\n];\n\nconst ACTIVE_MEMBERS = ALL_MEMBERS.filter((m) => m.online);\n\nconst sweepSpring = {\n  type: \"spring\" as const,\n  stiffness: 400,\n  damping: 35,\n  mass: 0.5,\n};\n\nconst RoleBadge = ({\n  type,\n  label,\n}: {\n  type: Member[\"roleType\"];\n  label: string;\n}) => {\n  const styles = {\n    pm: {\n      bg: \"bg-[#FFFCEB]\",\n      text: \"text-[#856404]\",\n      border: \"border-[#FFEBA5]\",\n      icon: Briefcase01Icon,\n    },\n    designer: {\n      bg: \"bg-[#F0F7FF]\",\n      text: \"text-[#004085]\",\n      border: \"border-[#B8DAFF]\",\n      icon: PaintBoardIcon,\n    },\n    data: {\n      bg: \"bg-[#F3FAF4]\",\n      text: \"text-[#155724]\",\n      border: \"border-[#C3E6CB]\",\n      icon: Database01Icon,\n    },\n    creator: {\n      bg: \"bg-[#FCF5FF]\",\n      text: \"text-[#522785]\",\n      border: \"border-[#E8D1FF]\",\n      icon: QuillWrite01Icon,\n    },\n  };\n\n  const style = styles[type];\n  const Icon = style.icon;\n\n  return (\n    <div\n      className={`flex items-center gap-1.5 px-2.5 py-1 rounded-full border ${style.bg} ${style.text} ${style.border} shrink-0`}\n    >\n      <HugeiconsIcon icon={Icon} size={12} strokeWidth={1.8} />\n      <span className=\"text-xs font-regular tracking-tight uppercase whitespace-nowrap truncate max-w-[60px] sm:max-w-none\">\n        {label}\n      </span>\n    </div>\n  );\n};\n\nconst MemberItem = ({ member }: { member: Member }) => (\n  <motion.div\n    variants={{\n      hidden: { opacity: 0, x: 10, y: 15, rotate: 1 },\n      visible: { opacity: 1, x: 0, y: 0, rotate: 0 },\n    }}\n    transition={sweepSpring}\n    style={{ originX: 1, originY: 1 }}\n    className=\"flex items-center group py-4 first:pt-0 border-b border-border/40 last:border-0\"\n  >\n    <div className=\"relative mr-4 shrink-0\">\n      <img\n        src={member.avatar}\n        alt={member.name}\n        className=\"w-12 h-12 rounded-full ring-2 ring-background shadow-sm grayscale-[0.1] group-hover:grayscale-0 transition-all duration-300\"\n      />\n      {member.online && (\n        <div className=\"absolute bottom-0 right-0 w-3.5 h-3.5 bg-background rounded-full flex items-center justify-center shadow-sm\">\n          <div className=\"w-2 h-2 bg-green-500 rounded-full\" />\n        </div>\n      )}\n    </div>\n    <div className=\"flex-1 min-w-0\">\n      <h3 className=\"text-base font-semibold text-foreground tracking-tight leading-none mb-1.5 truncate\">\n        {member.name}\n      </h3>\n      <div className=\"flex items-center gap-1.5 opacity-80\">\n        {member.online && (\n          <div className=\"w-1.5 h-1.5 bg-green-500 rounded-full\" />\n        )}\n        <p\n          className={`text-sm font-medium leading-none ${\n            member.online ? \"text-green-600\" : \"text-muted-foreground\"\n          }`}\n        >\n          {member.status}\n        </p>\n      </div>\n    </div>\n    <div className=\" shrink-0\">\n      <RoleBadge type={member.roleType} label={member.role} />\n    </div>\n  </motion.div>\n);\n\nexport default function StackedList() {\n  const [isExpanded, setIsExpanded] = useState(false);\n  const [searchQuery, setSearchQuery] = useState(\"\");\n\n  const filteredAllMembers = useMemo(\n    () =>\n      ALL_MEMBERS.filter(\n        (m) =>\n          m.name.toLowerCase().includes(searchQuery.toLowerCase()) ||\n          m.role.toLowerCase().includes(searchQuery.toLowerCase())\n      ),\n    [searchQuery]\n  );\n\n  return (\n    <div className=\"flex items-center justify-center min-h-screen w-full bg-muted/50 p-6 font-sans not-prose\">\n      <div className=\"relative w-full max-w-[440px] pb-6 bg-background rounded-[40px] border border-border flex flex-col overflow-hidden shadow-none\">\n        <div className=\"flex flex-col h-full bg-background\">\n          <div className=\"p-8 pb-3\">\n            <div className=\"flex items-center justify-between mb-5\">\n              <h2 className=\"text-lg font-semibold text-foreground tracking-tight flex items-center gap-2\">\n                Active Members\n                <span className=\"text-xs bg-muted px-2 py-1 mt-0.5 rounded-full text-muted-foreground leading-none font-normal\">\n                  {ACTIVE_MEMBERS.length}\n                </span>\n              </h2>\n              <Button\n                variant=\"outline\"\n                size=\"icon\"\n                className=\"h-9 w-9 rounded-full border-border/50 text-muted-foreground hover:bg-muted/50\"\n              >\n                <HugeiconsIcon icon={Add01Icon} size={18} strokeWidth={2.5} />\n              </Button>\n            </div>\n\n            <div className=\"relative mb-4\">\n              <HugeiconsIcon\n                icon={Search01Icon}\n                className=\"absolute left-4 top-1/2 -translate-y-1/2 text-muted-foreground/60 z-10\"\n                size={16}\n              />\n              <Input\n                placeholder=\"Search teammates...\"\n                value={searchQuery}\n                onChange={(e) => setSearchQuery(e.target.value)}\n                className=\"h-11 pl-11 pr-4 bg-muted/40 border-none focus-visible:ring-1 focus-visible:ring-border rounded-2xl text-base text-foreground placeholder:text-muted-foreground/50 transition-all w-full box-border\"\n              />\n            </div>\n          </div>\n\n          <div className=\"flex-1 overflow-y-auto px-8 pb-20 custom-scrollbar scroll-visible\">\n            <motion.div\n              initial={false}\n              animate=\"visible\"\n              variants={{ visible: { transition: { staggerChildren: 0.04 } } }}\n              className=\"space-y-0.5\"\n            >\n              {ACTIVE_MEMBERS.map((member) => (\n                <MemberItem key={`active-${member.id}`} member={member} />\n              ))}\n            </motion.div>\n          </div>\n        </div>\n\n        <motion.div\n          layout\n          initial={false}\n          animate={{\n            height: isExpanded ? \"calc(100% - 20px)\" : \"68px\",\n            width: isExpanded ? \"calc(100% - 20px)\" : \"calc(100% - 40px)\",\n            bottom: isExpanded ? \"10px\" : \"20px\",\n            left: isExpanded ? \"10px\" : \"20px\",\n            borderRadius: isExpanded ? \"32px\" : \"24px\",\n          }}\n          transition={{\n            type: \"spring\",\n            stiffness: 240,\n            damping: 30,\n            mass: 0.8,\n            ease: \"easeInOut\",\n          }}\n          className=\"absolute z-50 overflow-hidden border border-border shadow-none flex flex-col group/bar bg-card\"\n          style={{ cursor: isExpanded ? \"default\" : \"pointer\" }}\n          onClick={() => !isExpanded && setIsExpanded(true)}\n        >\n          <div\n            className={`flex items-center justify-between px-3 h-[68px] shrink-0 transition-colors ${\n              isExpanded ? \"border-b border-border/40\" : \"hover:bg-muted/20\"\n            }`}\n          >\n            <div className=\"flex items-center gap-3\">\n              <div\n                className={`w-11 h-11 rounded-xl bg-background border border-border flex items-center justify-center text-muted-foreground/80 shadow-[0_1px_2px_rgba(0,0,0,0.02)] transition-transform group-hover/bar:scale-105`}\n              >\n                <HugeiconsIcon icon={ProfileIcon} size={20} strokeWidth={2} />\n              </div>\n              <motion.div layout=\"position\">\n                <h4 className=\"text-base font-medium text-foreground tracking-tight leading-none  \">\n                  Member Directory\n                </h4>\n                <p className=\"text-xs font-regular leading-none text-muted-foreground  mt-1\">\n                  8 Members Registered\n                </p>\n              </motion.div>\n            </div>\n\n            <div className=\"flex items-center gap-3\">\n              {!isExpanded && (\n                <div className=\"flex items-center gap-0\">\n                  <div className=\"flex -space-x-3\">\n                    {ALL_MEMBERS.slice(0, 3).map((m) => (\n                      <motion.img\n                        key={`sum-${m.id}`}\n                        layoutId={`avatar-${m.id}`}\n                        src={m.avatar}\n                        className=\"w-10 h-10 rounded-full ring-1 ring-background shadow-sm z-1\"\n                        alt=\"avatar\"\n                      />\n                    ))}\n                    <div className=\"w-10 h-10 rounded-full ring-1 ring-background bg-muted flex items-center justify-center shadow-sm relative z-0\">\n                      <span className=\"text-sm font-regular leading-none text-muted-foreground\">\n                        +{ALL_MEMBERS.length - 3}\n                      </span>\n                    </div>\n                  </div>\n                </div>\n              )}\n\n              {isExpanded && (\n                <button\n                  className=\"h-9 w-9 rounded-xl text-muted-foreground hover:text-foreground transition-all flex items-center justify-center bg-muted/60 active:scale-90\"\n                  onClick={(e) => {\n                    e.stopPropagation();\n                    setIsExpanded(false);\n                  }}\n                >\n                  <HugeiconsIcon\n                    icon={Cancel01Icon}\n                    size={18}\n                    strokeWidth={2.5}\n                  />\n                </button>\n              )}\n            </div>\n          </div>\n\n          <div className=\"flex-1 overflow-hidden flex flex-col\">\n            <AnimatePresence>\n              {isExpanded && (\n                <motion.div\n                  initial={{ opacity: 0, y: -8 }}\n                  animate={{ opacity: 1, y: 0 }}\n                  exit={{ opacity: 0, y: -8 }}\n                  className=\"px-6 py-4\"\n                >\n                  <div className=\"relative\">\n                    <HugeiconsIcon\n                      icon={Search01Icon}\n                      className=\"absolute left-4 top-1/2 -translate-y-1/2 text-muted-foreground/50 z-10\"\n                      size={15}\n                    />\n                    <Input\n                      placeholder=\"Search members...\"\n                      value={searchQuery}\n                      onChange={(e) => setSearchQuery(e.target.value)}\n                      className=\"h-10 bg-muted/30 border-none focus-visible:ring-1 focus-visible:ring-border rounded-xl text-sm text-foreground placeholder:text-muted-foreground/40 transition-all w-full box-border pl-10\"\n                    />\n                  </div>\n                </motion.div>\n              )}\n            </AnimatePresence>\n\n            <div className=\"flex-1 overflow-y-auto px-6 py-2 custom-scrollbar scroll-visible\">\n              <motion.div\n                initial=\"hidden\"\n                animate={isExpanded ? \"visible\" : \"hidden\"}\n                variants={{\n                  visible: {\n                    transition: { staggerChildren: 0.03, delayChildren: 0.1 },\n                  },\n                  hidden: {\n                    transition: { staggerChildren: 0.02, staggerDirection: -1 },\n                  },\n                }}\n                className=\"space-y-0.5\"\n              >\n                {filteredAllMembers.map((member) => (\n                  <MemberItem key={`list-${member.id}`} member={member} />\n                ))}\n              </motion.div>\n            </div>\n          </div>\n        </motion.div>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}