{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "expandable-card-motion",
  "description": "A Card component that expands on click.",
  "dependencies": [
    "motion/react",
    "lucide-react"
  ],
  "registryDependencies": [
    "button"
  ],
  "files": [
    {
      "path": "src/app/components/animatedComponents/cards/expandable-card/ExpandableCardMotion.tsx",
      "content": "\"use client\";\n\nimport React, { useEffect, useId, useRef, useState } from \"react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport Image from \"next/image\";\nimport { Button } from \"@/components/ui/button\";\n\nconst useOutsideClick = (\n  ref: React.RefObject<HTMLDivElement>,\n  callback: Function\n) => {\n  useEffect(() => {\n    const listener = (event: any) => {\n      if (!ref.current || ref.current.contains(event.target)) {\n        return;\n      }\n      callback(event);\n    };\n \n    document.addEventListener(\"mousedown\", listener);\n    document.addEventListener(\"touchstart\", listener);\n \n    return () => {\n      document.removeEventListener(\"mousedown\", listener);\n      document.removeEventListener(\"touchstart\", listener);\n    };\n  }, [ref, callback]);\n};\nexport default function ExpandableCardMotion() {\n  const [active, setActive] = useState<(typeof cards)[number] | boolean | null>(\n    null\n  );\n  const ref = useRef<HTMLDivElement>(null);\n  const id = useId();\n\n  useEffect(() => {\n    function onKeyDown(event: KeyboardEvent) {\n      if (event.key === \"Escape\") {\n        setActive(false);\n      }\n    }\n\n    if (active && typeof active === \"object\") {\n      document.body.style.overflow = \"hidden\";\n    } else {\n      document.body.style.overflow = \"auto\";\n    }\n\n    window.addEventListener(\"keydown\", onKeyDown);\n    return () => window.removeEventListener(\"keydown\", onKeyDown);\n  }, [active]);\n\n  useOutsideClick(ref as any, () => setActive(null));\n\n  return (\n    <>\n      <AnimatePresence>\n        {active && typeof active === \"object\" && (\n          <motion.div\n            initial={{ opacity: 0 }}\n            animate={{ opacity: 1 }}\n            exit={{ opacity: 0 }}\n            className=\"fixed inset-0 bg-black/20 dark:bg-white/5 h-full w-full z-[999]\"\n          />\n        )}\n      </AnimatePresence>\n      <AnimatePresence>\n        {active && typeof active === \"object\" ? (\n          <div className=\"fixed inset-0  grid place-items-center z-[9999]\">\n            <motion.button\n              key={`button-${active.title}-${id}`}\n              layout\n              initial={{\n                opacity: 0,\n              }}\n              animate={{\n                opacity: 1,\n              }}\n              exit={{\n                opacity: 0,\n                transition: {\n                  duration: 0.05,\n                },\n              }}\n              className=\"flex absolute top-2 right-2 lg:hidden items-center justify-center bg-white rounded-full h-6 w-6\"\n              onClick={() => setActive(null)}\n            >\n              <CloseIcon />\n            </motion.button>\n            <motion.div \n              layoutId={`card-${active.title}-${id}`}\n              ref={ref}\n              className=\"w-full max-w-[500px]  h-full md:h-fit md:max-h-[90%]  flex flex-col bg-white dark:bg-sidebar sm:rounded-3xl overflow-hidden\"\n            >\n              <motion.div layoutId={`image-${active.title}-${id}`}>\n                <img\n                  width={200}\n                  height={200}\n                  src={active.src}\n                  alt={active.title}\n                  className=\"w-full h-80 lg:h-80 sm:rounded-tr-lg sm:rounded-tl-lg object-cover object-top\"\n                />\n              </motion.div>\n\n              <div>\n                <div className=\"flex justify-between items-start p-4 gap-6\">\n                  <div className=\"\">\n                    <motion.h3\n                      layoutId={`title-${active.title}-${id}`}\n                      className=\"font-bold text-neutral-700 dark:text-neutral-200 text-lg\"\n                    >\n                      {active.title}\n                    </motion.h3>\n                    <motion.p\n                      layoutId={`author-${active.author}-${id}`}\n                      className=\"text-neutral-600 dark:text-neutral-400 text-sm font-medium\"\n                    >\n                      {active.author}\n                    </motion.p>\n                  </div>\n                </div>\n                <div className=\"pt-4 relative px-4\">\n                  <motion.div\n                    layout\n                    initial={{ opacity: 0 }}\n                    animate={{ opacity: 1 }}\n                    exit={{ opacity: 0 }}\n                    className=\"text-neutral-600 !text-xs h-40 md:h-fit pb-10 flex flex-col items-start gap-4 expandable-card overflow-auto dark:text-neutral-400 [mask:linear-gradient(to_bottom,white,white,transparent)] [scrollbar-width:none] [-ms-overflow-style:none] [-webkit-overflow-scrolling:touch]\"\n                  >\n                    {typeof active.content === \"function\"\n                      ? active.content()\n                      : active.content}\n                  </motion.div>\n                </div>\n              </div>\n            </motion.div>\n          </div>\n        ) : null}\n      </AnimatePresence>\n      <ul className=\" w-full gap-4\">\n        {cards.map((card, index) => (\n          <motion.div\n            layoutId={`card-${card.title}-${id}`}\n            key={`card-${card.title}-${id}`}\n            onClick={() => setActive(card)}\n            className=\"p-4 flex flex-col md:flex-row justify-between items-center hover:bg-neutral-50 dark:hover:bg-white/10 rounded-xl cursor-pointer\"\n          >\n            <div className=\"flex gap-4 flex-col md:flex-row align-items-center\">\n              <motion.div layoutId={`image-${card.title}-${id}`}>\n                <Image\n                  width={100}\n                  height={100}\n                  src={card.src}\n                  alt={card.title}\n                  className=\"h-40 w-40 md:h-14 md:w-14 rounded-lg object-cover object-top\"\n                />\n              </motion.div>\n              <div className=\"\">\n                <motion.h3\n                  layoutId={`title-${card.title}-${id}`}\n                  className=\"font-medium text-neutral-800 dark:text-neutral-200 text-center md:text-left text-base\"\n                >\n                  {card.title}\n                </motion.h3>\n                <motion.p\n                  layoutId={`author-${card.author}-${id}`}\n                  className=\"text-neutral-600 dark:text-neutral-400 text-center md:text-left text-sm font-medium\"\n                >\n                  {card.author}\n                </motion.p>\n              </div>\n            </div>\n            <Button asChild className=\"rounded-full\" >\n            <motion.button\n              layoutId={`button-${card.title}-${id}`}\n              className=\"px-4 py-2 text-sm rounded-full font-bold mt-4 md:mt-0\"\n            >\n              {card.ctaText}\n            </motion.button>\n            </Button>\n          </motion.div>\n        ))}\n      </ul>\n    </>\n  );\n}\n const CloseIcon = () => {\n  return (\n    <motion.svg\n      initial={{\n        opacity: 0,\n      }}\n      animate={{\n        opacity: 1,\n      }}\n      exit={{\n        opacity: 0,\n        transition: {\n          duration: 0.05,\n        },\n      }}\n      xmlns=\"http://www.w3.org/2000/svg\"\n      width=\"24\"\n      height=\"24\"\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth=\"2\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      className=\"h-4 w-4 text-black\"\n    >\n      <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\" />\n      <path d=\"M18 6l-12 12\" />\n      <path d=\"M6 6l12 12\" />\n    </motion.svg>\n  );\n};\n\nconst cards = [\n  {\n    author: \"David Mathew\",\n    title: \"As yen tumbles, gadget-loving Japan goes for secondhand iPhones\",\n    src: \"/images/blog/blog-img1.jpg\",\n    ctaText: \"Read\",\n    ctaLink: \"https://nextjs.tailwind-admin.com/apps/blog/post\",\n    content: () => {\n      return (\n        <p>\n          But you cannot figure out what it is or what it can do. MTA web directory is the simplest way in which one can bid on a link, or a few links if they wish to do so. The link directory on MTA displays all of the links it currently has, and does so in alphabetical order, which makes it much easier for someone to find what they are looking for if it is something specific and they do not want to go through all the other sites and links as well. It allows you to start your bid at the bottom and slowly work your way to the top of the list\n        </p>\n      );\n    },\n  },\n  {\n    author: \"Ben Stokes\",\n    title: \"Intel loses bid to revive antitrust case against patent foe Fortress\",\n    src: \"/images/blog/blog-img2.jpg\",\n    ctaText: \"Read\",\n    ctaLink: \"https://nextjs.tailwind-admin.com/apps/blog/post\",\n    content: () => {\n      return (\n        <p>\nBut you cannot figure out what it is or what it can do. MTA web directory is the simplest way in which one can bid on a link, or a few links if they wish to do so. The link directory on MTA displays all of the links it currently has, and does so in alphabetical order, which makes it much easier for someone to find what they are looking for if it is something specific and they do not want to go through all the other sites and links as well. It allows you to start your bid at the bottom and slowly work your way to the top of the list\n        </p>\n      );\n    },\n  },\n\n  {\n    author: \"Michael Jhonson\",\n    title: \"COVID outbreak deepens as more lockdowns loom in China\",\n    src: \"/images/blog/blog-img3.jpg\",\n    ctaText: \"Read\",\n    ctaLink: \"https://nextjs.tailwind-admin.com/apps/blog/post\",\n    content: () => {\n      return (\n        <p>\nBut you cannot figure out what it is or what it can do. MTA web directory is the simplest way in which one can bid on a link, or a few links if they wish to do so. The link directory on MTA displays all of the links it currently has, and does so in alphabetical order, which makes it much easier for someone to find what they are looking for if it is something specific and they do not want to go through all the other sites and links as well. It allows you to start your bid at the bottom and slowly work your way to the top of the list\n        </p>\n      );\n    },\n  },\n  {\n    author: \"Sanju Samson\",\n    title: \"Streaming video way before it was cool, go dark tomorrow\",\n    src: \"/images/blog/blog-img4.jpg\",\n    ctaText: \"Read\",\n    ctaLink: \"https://nextjs.tailwind-admin.com/apps/blog/post\",\n    content: () => {\n      return (\n        <p>\nBut you cannot figure out what it is or what it can do. MTA web directory is the simplest way in which one can bid on a link, or a few links if they wish to do so. The link directory on MTA displays all of the links it currently has, and does so in alphabetical order, which makes it much easier for someone to find what they are looking for if it is something specific and they do not want to go through all the other sites and links as well. It allows you to start your bid at the bottom and slowly work your way to the top of the list\n        </p>\n      );\n    },\n  },\n  {\n    author: \"Peter Parker\",\n    title: \"After Twitter Staff Cuts, Survivors Face Radio Silence\",\n    src: \"/images/blog/blog-img5.jpg\",\n    ctaText: \"Read\",\n    ctaLink: \"https://nextjs.tailwind-admin.com/apps/blog/post\",\n    content: () => {\n      return (\n        <p>\nBut you cannot figure out what it is or what it can do. MTA web directory is the simplest way in which one can bid on a link, or a few links if they wish to do so. The link directory on MTA displays all of the links it currently has, and does so in alphabetical order, which makes it much easier for someone to find what they are looking for if it is something specific and they do not want to go through all the other sites and links as well. It allows you to start your bid at the bottom and slowly work your way to the top of the list\n        </p>\n      );\n    },\n  },\n];\n",
      "type": "registry:component",
      "target": "components/animated/cards/expandable-card/ExpandableCardMotion.tsx"
    }
  ],
  "type": "registry:component"
}