{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "transaction-list",
  "type": "registry:component",
  "title": "Transaction List",
  "description": "An animated transaction list with smooth expand and collapse transitions for detailed views.",
  "dependencies": [
    "lucide-react",
    "motion",
    "react-use-measure"
  ],
  "files": [
    {
      "path": "components/watermelon/transaction-list.tsx",
      "type": "registry:component",
      "content": "import {\n  AnimatePresence,\n  motion,\n  MotionConfig,\n  type Transition,\n} from 'motion/react';\n\nimport { useState } from 'react';\nimport { ArrowRight, X } from 'lucide-react';\nimport useMeasure from 'react-use-measure';\n\nexport interface Transaction {\n  id: string;\n  icon: React.ReactNode;\n  name: string;\n  category: string;\n  amount: string;\n  date: string;\n  time: string;\n  transactionId: string;\n  paymentMethod: string;\n  cardNumber: string;\n  cardType: string;\n}\n\nconst springConfig: Transition = {\n  type: 'spring',\n  bounce: 0,\n  duration: 0.6,\n};\n\nconst opacityConfig: Transition = {\n  duration: 0.4,\n  ease: [0.19, 1, 0.22, 1],\n};\n\nexport function TransactionList({\n  transactions,\n}: {\n  transactions: Transaction[];\n}) {\n  const [open, setOpen] = useState<string | null>(null);\n  const isOpen = open === null;\n  const [ref, bounds] = useMeasure();\n\n  const selected = transactions.find((t) => t.id === open) ?? null;\n\n  return (\n    <MotionConfig transition={springConfig}>\n      <motion.div\n        className=\"flex items-center justify-center overflow-hidden rounded-2xl border border-zinc-200 bg-zinc-100 shadow-sm dark:border-white/10 dark:bg-zinc-900\"\n        animate={{ height: bounds.height > 0 ? bounds.height : 'auto' }}\n      >\n        <div className=\"p-3\" ref={ref}>\n          <AnimatePresence mode=\"popLayout\">\n            {isOpen ? (\n              <motion.div\n                key=\"collapsed\"\n                initial={{ opacity: 0 }}\n                animate={{ opacity: 1 }}\n                exit={{ opacity: 0 }}\n                transition={opacityConfig}\n                className=\"flex w-64 flex-col gap-2\"\n              >\n                <span className=\"font-medium text-zinc-500 dark:text-zinc-100\">\n                  Transaction\n                </span>\n\n                {transactions.map((item) => (\n                  <TransactionItem\n                    key={item.id}\n                    data={item}\n                    onClick={() => setOpen(item.id)}\n                  />\n                ))}\n\n                <button className=\"flex items-center justify-center gap-1 rounded-sm py-1 text-zinc-700 dark:text-zinc-200\">\n                  <p className=\"text-sm\">All transactions</p>\n                  <ArrowRight size={14} />\n                </button>\n              </motion.div>\n            ) : (\n              selected && (\n                <motion.div exit={{ opacity: 0 }}>\n                  <TransactionItemExpanded\n                    data={selected}\n                    onClose={() => setOpen(null)}\n                  />\n                </motion.div>\n              )\n            )}\n          </AnimatePresence>\n        </div>\n      </motion.div>\n    </MotionConfig>\n  );\n}\n\nfunction TransactionItem({\n  data,\n  onClick,\n}: {\n  data: Transaction;\n  onClick: () => void;\n}) {\n  return (\n    <div className=\"flex w-64 cursor-pointer gap-2\" onClick={onClick}>\n      <motion.div\n        className=\"flex size-10 shrink-0 items-center justify-center rounded-full bg-zinc-800\"\n        layoutId={`icon-${data.id}`}\n      >\n        <div className=\"flex items-center justify-center\">{data.icon}</div>\n      </motion.div>\n\n      <div className=\"flex flex-1 flex-col justify-center text-xs\">\n        <motion.p\n          className=\"font-semibold text-zinc-700 dark:text-zinc-100\"\n          layoutId={`name-${data.id}`}\n        >\n          {data.name}\n        </motion.p>\n\n        <motion.p\n          className=\"text-zinc-500 dark:text-zinc-400\"\n          layoutId={`category-${data.id}`}\n        >\n          {data.category}\n        </motion.p>\n      </div>\n\n      <motion.p\n        className=\"flex items-center text-xs text-zinc-500 dark:text-zinc-400\"\n        layoutId={`amount-${data.id}`}\n      >\n        {data.amount}\n      </motion.p>\n    </div>\n  );\n}\n\nfunction TransactionItemExpanded({\n  data,\n  onClose,\n}: {\n  data: Transaction;\n  onClose: () => void;\n}) {\n  return (\n    <div className=\"flex w-64 flex-col gap-2\">\n      <div className=\"flex justify-between\">\n        <motion.div\n          className=\"flex size-10 items-center justify-center rounded-md bg-zinc-800\"\n          layoutId={`icon-${data.id}`}\n        >\n          {data.icon}\n        </motion.div>\n\n        <div\n          className=\"flex cursor-pointer items-center justify-center self-start rounded-full bg-zinc-300 p-2 dark:bg-zinc-700\"\n          onClick={onClose}\n        >\n          <X className=\"size-4\" />\n        </div>\n      </div>\n\n      <div className=\"flex justify-between\">\n        <div>\n          <motion.p\n            className=\"font-semibold text-zinc-700 dark:text-zinc-100\"\n            layoutId={`name-${data.id}`}\n          >\n            {data.name}\n          </motion.p>\n\n          <motion.p\n            className=\"text-sm text-zinc-500 dark:text-zinc-400\"\n            layoutId={`category-${data.id}`}\n          >\n            {data.category}\n          </motion.p>\n        </div>\n\n        <motion.p layoutId={`amount-${data.id}`}>{data.amount}</motion.p>\n      </div>\n\n      <motion.div\n        className=\"flex flex-col gap-2 text-xs\"\n        initial={{ opacity: 0 }}\n        animate={{ opacity: 1 }}\n        exit={{ opacity: 0 }}\n        transition={{\n          ...opacityConfig,\n          delay: 0.1,\n        }}\n      >\n        <div className=\"border border-dashed border-zinc-200 dark:border-white/20\" />\n\n        <p className=\"text-zinc-500 dark:text-zinc-400\">\n          #{data.transactionId}\n        </p>\n\n        <p className=\"text-zinc-500 dark:text-zinc-400\">{data.date}</p>\n\n        <p className=\"text-zinc-500 dark:text-zinc-400\">{data.time}</p>\n\n        <div className=\"border border-dashed border-zinc-200 dark:border-white/20\" />\n\n        <p className=\"text-zinc-500\">Paid Via {data.paymentMethod}</p>\n\n        <p className=\"text-zinc-500 dark:text-zinc-400\">\n          XXXX {data.cardNumber}{' '}\n          <span className=\"font-bold text-black uppercase italic dark:text-zinc-100\">\n            {data.cardType}\n          </span>\n        </p>\n      </motion.div>\n    </div>\n  );\n}\n"
    }
  ]
}
