{
  "name": "animated-modal",
  "type": "registry:ui",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "components/ui/animated-modal.tsx",
      "content": "\"use client\";\nimport { cn } from \"@/lib/utils\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport React, {\n  ReactNode,\n  createContext,\n  useContext,\n  useEffect,\n  useRef,\n  useState,\n} from \"react\";\n\ninterface ModalContextType {\n  open: boolean;\n  setOpen: (open: boolean) => void;\n}\n\nconst ModalContext = createContext<ModalContextType | undefined>(undefined);\n\nexport const ModalProvider = ({ children }: { children: ReactNode }) => {\n  const [open, setOpen] = useState(false);\n\n  return (\n    <ModalContext.Provider value={{ open, setOpen }}>\n      {children}\n    </ModalContext.Provider>\n  );\n};\n\nexport const useModal = () => {\n  const context = useContext(ModalContext);\n  if (!context) {\n    throw new Error(\"useModal must be used within a ModalProvider\");\n  }\n  return context;\n};\n\nexport function Modal({ children }: { children: ReactNode }) {\n  return <ModalProvider>{children}</ModalProvider>;\n}\n\nexport const ModalTrigger = ({\n  children,\n  className,\n}: {\n  children: ReactNode;\n  className?: string;\n}) => {\n  const { setOpen } = useModal();\n  return (\n    <button\n      className={cn(\n        \"px-4 py-2 rounded-md text-black dark:text-white text-center relative overflow-hidden\",\n        className\n      )}\n      onClick={() => setOpen(true)}\n    >\n      {children}\n    </button>\n  );\n};\n\nexport const ModalBody = ({\n  children,\n  className,\n}: {\n  children: ReactNode;\n  className?: string;\n}) => {\n  const { open } = useModal();\n\n  useEffect(() => {\n    if (open) {\n      document.body.style.overflow = \"hidden\";\n    } else {\n      document.body.style.overflow = \"auto\";\n    }\n  }, [open]);\n\n  const modalRef = useRef(null);\n  const { setOpen } = useModal();\n  useOutsideClick(modalRef, () => setOpen(false));\n\n  return (\n    <AnimatePresence>\n      {open && (\n        <motion.div\n          initial={{\n            opacity: 0,\n          }}\n          animate={{\n            opacity: 1,\n            backdropFilter: \"blur(10px)\",\n          }}\n          exit={{\n            opacity: 0,\n            backdropFilter: \"blur(0px)\",\n          }}\n          className=\"fixed [perspective:800px] [transform-style:preserve-3d] inset-0 h-full w-full  flex items-center justify-center z-50\"\n        >\n          <Overlay />\n\n          <motion.div\n            ref={modalRef}\n            className={cn(\n              \"min-h-[50%] max-h-[90%] md:max-w-[40%] bg-white dark:bg-neutral-950 border border-transparent dark:border-neutral-800 md:rounded-2xl relative z-50 flex flex-col flex-1 overflow-hidden\",\n              className\n            )}\n            initial={{\n              opacity: 0,\n              scale: 0.5,\n              rotateX: 40,\n              y: 40,\n            }}\n            animate={{\n              opacity: 1,\n              scale: 1,\n              rotateX: 0,\n              y: 0,\n            }}\n            exit={{\n              opacity: 0,\n              scale: 0.8,\n              rotateX: 10,\n            }}\n            transition={{\n              type: \"spring\",\n              stiffness: 260,\n              damping: 15,\n            }}\n          >\n            <CloseIcon />\n            {children}\n          </motion.div>\n        </motion.div>\n      )}\n    </AnimatePresence>\n  );\n};\n\nexport const ModalContent = ({\n  children,\n  className,\n}: {\n  children: ReactNode;\n  className?: string;\n}) => {\n  return (\n    <div className={cn(\"flex flex-col flex-1 p-8 md:p-10\", className)}>\n      {children}\n    </div>\n  );\n};\n\nexport const ModalFooter = ({\n  children,\n  className,\n}: {\n  children: ReactNode;\n  className?: string;\n}) => {\n  return (\n    <div\n      className={cn(\n        \"flex justify-end p-4 bg-gray-100 dark:bg-neutral-900\",\n        className\n      )}\n    >\n      {children}\n    </div>\n  );\n};\n\nconst Overlay = ({ className }: { className?: string }) => {\n  return (\n    <motion.div\n      initial={{\n        opacity: 0,\n      }}\n      animate={{\n        opacity: 1,\n        backdropFilter: \"blur(10px)\",\n      }}\n      exit={{\n        opacity: 0,\n        backdropFilter: \"blur(0px)\",\n      }}\n      className={`fixed inset-0 h-full w-full bg-black bg-opacity-50 z-50 ${className}`}\n    ></motion.div>\n  );\n};\n\nconst CloseIcon = () => {\n  const { setOpen } = useModal();\n  return (\n    <button\n      onClick={() => setOpen(false)}\n      className=\"absolute top-4 right-4 group\"\n    >\n      <svg\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=\"text-black dark:text-white h-4 w-4 group-hover:scale-125 group-hover:rotate-3 transition duration-200\"\n      >\n        <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\" />\n        <path d=\"M18 6l-12 12\" />\n        <path d=\"M6 6l12 12\" />\n      </svg>\n    </button>\n  );\n};\n\n// Hook to detect clicks outside of a component.\n// Add it in a separate file, I've added here for simplicity\nexport const useOutsideClick = (\n  ref: React.RefObject<HTMLDivElement>,\n  callback: Function\n) => {\n  useEffect(() => {\n    const listener = (event: any) => {\n      // DO NOTHING if the element being clicked is the target element or their children\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};\n",
      "type": "registry:ui",
      "target": "components/ui/animated-modal.tsx"
    }
  ],
  "author": "Manu Arora <hi@manuarora.in>",
  "title": "Animated Modal"
}