{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "collection-grid-disclosure",
  "type": "registry:component",
  "title": "Collection Grid Disclosure",
  "description": "An animated collection grid that smoothly expands to reveal additional content on interaction.",
  "dependencies": [
    "lucide-react",
    "motion",
    "react-icons",
    "react-use-measure"
  ],
  "files": [
    {
      "path": "components/watermelon/collection-grid-disclosure.tsx",
      "type": "registry:component",
      "content": "'use client';\n\nimport { useState, type FC } from 'react';\nimport {\n  motion,\n  AnimatePresence,\n  MotionConfig,\n  type Transition,\n} from 'motion/react';\nimport { ChevronRight, X, Coffee } from 'lucide-react';\nimport { FaCarrot, FaGraduationCap, FaPills, FaPlug } from 'react-icons/fa';\nimport { TbHomeFilled, TbPlayerPlayFilled } from 'react-icons/tb';\nimport { FaBottleWater } from 'react-icons/fa6';\nimport { MdWifi } from 'react-icons/md';\nimport { BsFillMouse2Fill } from 'react-icons/bs';\nimport { IoGameController } from 'react-icons/io5';\nimport useMeasure from 'react-use-measure';\nimport type { IconType } from 'react-icons';\n\nexport interface CollectionItem {\n  id: string;\n  name: string;\n  price: number;\n  icon: IconType;\n}\n\nexport interface Collection {\n  id: string;\n  name: string;\n  items: CollectionItem[];\n}\n\ninterface DisclosureCardProps {\n  collections?: Collection[];\n}\n\nconst DEFAULT_COLLECTIONS: Collection[] = [\n  {\n    id: 'utilities',\n    name: 'Utilities',\n    items: [\n      {\n        id: 'u-1',\n        name: 'Electricity',\n        price: 150,\n        icon: FaPlug,\n      },\n      {\n        id: 'u-2',\n        name: 'Water',\n        price: 50,\n        icon: FaBottleWater,\n      },\n      {\n        id: 'u-3',\n        name: 'Internet',\n        price: 100,\n        icon: MdWifi,\n      },\n    ],\n  },\n  {\n    id: 'subscriptions',\n    name: 'Subscriptions',\n    items: [\n      {\n        id: 's-1',\n        name: 'Streaming',\n        price: 80,\n        icon: TbPlayerPlayFilled,\n      },\n      {\n        id: 's-2',\n        name: 'Courses',\n        price: 100,\n        icon: FaGraduationCap,\n      },\n      {\n        id: 's-3',\n        name: 'Software & Apps',\n        price: 120,\n        icon: BsFillMouse2Fill,\n      },\n      {\n        id: 's-4',\n        name: 'Games',\n        price: 50,\n        icon: IoGameController,\n      },\n    ],\n  },\n  {\n    id: 'daily-needs',\n    name: 'Daily Needs',\n    items: [\n      {\n        id: 'dn-1',\n        name: 'Groceries',\n        price: 500.56,\n        icon: FaCarrot,\n      },\n      {\n        id: 'dn-2',\n        name: 'Snacks',\n        price: 45.2,\n        icon: Coffee,\n      },\n      {\n        id: 'dn-3',\n        name: 'Essentials',\n        price: 120.34,\n        icon: TbHomeFilled,\n      },\n      {\n        id: 'dn-4',\n        name: 'Health',\n        price: 75.8,\n        icon: FaPills,\n      },\n    ],\n  },\n];\n\nconst springConfig: Transition = {\n  type: 'spring',\n  stiffness: 200,\n  damping: 20,\n  mass: 1.1,\n};\n\nexport const DisclosureCard: FC<DisclosureCardProps> = ({\n  collections = DEFAULT_COLLECTIONS,\n}) => {\n  return (\n    <div className=\"flex w-full items-center justify-center\">\n      <motion.div\n        className=\"flex flex-col gap-2 will-change-transform\"\n        layout=\"position\"\n        transition={springConfig}\n      >\n        {collections.map((collection) => (\n          <GridContainer\n            key={collection.id}\n            title={collection.name}\n            items={collection.items}\n          />\n        ))}\n      </motion.div>\n    </div>\n  );\n};\n\nconst GridContainer = ({\n  items,\n  title,\n}: {\n  items: CollectionItem[];\n  title: string;\n}) => {\n  const [isExpanded, setIsExpanded] = useState(false);\n  const [ref, bounds] = useMeasure({ offsetSize: true });\n\n  return (\n    <MotionConfig transition={springConfig}>\n      <motion.div\n        className=\"w-[300px] cursor-pointer overflow-hidden rounded-lg border border-gray-200 bg-zinc-100 dark:border-zinc-700 dark:bg-zinc-800\"\n        animate={{\n          height: bounds.height > 0 ? bounds.height : \"auto\"\n        }}\n      >\n        <div className=\"p-2\" ref={ref}>\n          <AnimatePresence\n            mode=\"popLayout\"\n            key={isExpanded ? 'expanded' : 'collapsed'}\n            propagate\n          >\n            {!isExpanded ? (\n              <motion.div\n                key={'collapsed'}\n                className=\"flex w-full items-center space-x-2\"\n                onClick={() => setIsExpanded(true)}\n                exit={{ opacity: 0 }}\n                transition={{ duration: 0.1, ease: 'easeOut' }}\n              >\n                <div className=\"grid grid-cols-2 gap-1\">\n                  {items.map((item, index) => (\n                    <motion.div\n                      className=\"relative flex size-6 items-center justify-center rounded-full bg-zinc-300 p-1 dark:bg-white\"\n                      key={`${item.name}-${index}`}\n                      layoutId={`${item.name}`}\n                      transition={{ ...springConfig, delay: 0.01 }}\n                    >\n                      <item.icon className=\"size-4 fill-white dark:fill-black\" />\n                    </motion.div>\n                  ))}\n                </div>\n\n                <div className=\"ml-2 flex flex-1 flex-col items-start justify-center\">\n                  <motion.span\n                    layoutId={`title-${title}`}\n                    layout=\"position\"\n                    className=\"text-lg text-zinc-900 dark:text-zinc-100\"\n                  >\n                    {title}\n                  </motion.span>\n                  <span className=\"text-sm text-zinc-500 dark:text-zinc-400\">\n                    {items.length} Items\n                  </span>\n                </div>\n\n                <div>\n                  <ChevronRight className=\"size-6 text-zinc-500 dark:text-zinc-400\" />\n                </div>\n              </motion.div>\n            ) : (\n              <motion.div\n                key={'expanded'}\n                className=\"flex w-full flex-col gap-3\"\n                exit={{ opacity: 0 }}\n                transition={{ duration: 0.01, ease: 'easeOut' }}\n              >\n                <motion.div className=\"flex items-center px-1\" layout>\n                  <motion.span\n                    className=\"flex-1 text-lg text-zinc-900 dark:text-zinc-100\"\n                    layoutId={`title-${title}`}\n                    layout=\"position\"\n                  >\n                    {title}\n                  </motion.span>\n                  <div\n                    className=\"flex items-center justify-center rounded-full bg-zinc-400 p-1 dark:bg-white\"\n                    onClick={() => setIsExpanded(false)}\n                  >\n                    <X className=\"size-4 text-white dark:text-black\" />\n                  </div>\n                </motion.div>\n\n                <div className=\"flex flex-col gap-3\">\n                  <AnimatePresence mode=\"popLayout\">\n                    {items.map((item) => (\n                      <div\n                        className=\"flex items-center justify-center gap-2\"\n                        key={item.id}\n                      >\n                        <motion.div\n                          className=\"flex size-10 items-center justify-center rounded-full bg-black\"\n                          layoutId={`${item.name}`}\n                        >\n                          <item.icon className=\"size-6 fill-white\" />\n                        </motion.div>\n                        <motion.div\n                          className=\"mt-2 flex flex-1 flex-col items-start justify-center gap-2 leading-0\"\n                          initial={{ opacity: 0 }}\n                          animate={{ opacity: 1 }}\n                        >\n                          <motion.p className=\"text-md text-zinc-800 dark:text-zinc-100\">\n                            {item.name}\n                          </motion.p>\n                          <div className=\"flex gap-1 text-zinc-400 dark:text-zinc-500\">\n                            <div className=\"flex items-start justify-center gap-1\">\n                              <p className=\"text-sm\">${item.price}</p>\n                            </div>\n                          </div>\n                        </motion.div>\n                        <div>\n                          <ChevronRight className=\"mr-1 size-6 text-zinc-400 dark:text-zinc-500\" />\n                        </div>\n                      </div>\n                    ))}\n                  </AnimatePresence>\n                </div>\n              </motion.div>\n            )}\n          </AnimatePresence>\n        </div>\n      </motion.div>\n    </MotionConfig>\n  );\n};\n"
    }
  ]
}
