{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "file-upload-motion",
  "type": "registry:component",
  "description": "A file upload component with drag and drop animation.",
  "dependencies": [
    "motion/react",
    "@tabler/icons-react",
    "react-dropzone"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "src/app/components/animatedComponents/forms/file-upload/FileUploadMotion.tsx",
      "content": "import { cn } from \"@/lib/utils\";\r\nimport React, { useRef, useState } from \"react\";\r\nimport { motion } from \"motion/react\";\r\nimport { IconUpload } from \"@tabler/icons-react\";\r\nimport { useDropzone } from \"react-dropzone\";\r\n\r\nconst mainVariant = {\r\n  initial: { x: 0, y: 0 },\r\n  animate: { x: 20, y: -20, opacity: 0.9 },\r\n};\r\n\r\nconst secondaryVariant = {\r\n  initial: { opacity: 0 },\r\n  animate: { opacity: 1 },\r\n};\r\n\r\ninterface FileUploadProps {\r\n  onChange?: (files: File[]) => void;\r\n}\r\n\r\nexport const FileUploadStruc: React.FC<FileUploadProps> = ({ onChange }) => {\r\n  const [files, setFiles] = useState<File[]>([]);\r\n  const fileInputRef = useRef<HTMLInputElement>(null);\r\n\r\n  const handleFileChange = (newFiles: File[]) => {\r\n    setFiles((prev) => [...prev, ...newFiles]);\r\n    onChange?.(newFiles);\r\n  };\r\n\r\n  const handleClick = () => {\r\n    fileInputRef.current?.click();\r\n  };\r\n\r\n  const { getRootProps, isDragActive } = useDropzone({\r\n    multiple: false,\r\n    noClick: true,\r\n    onDrop: handleFileChange,\r\n    onDropRejected: console.error,\r\n  });\r\n\r\n  const formatFileSize = (size: number) =>\r\n    (size / (1024 * 1024)).toFixed(2);\r\n\r\n  const formatDate = (timestamp: number) =>\r\n    new Date(timestamp).toLocaleDateString();\r\n\r\n  return (\r\n    <div className=\"w-full\" {...getRootProps()}>\r\n      <motion.div\r\n        onClick={handleClick}\r\n        whileHover=\"animate\"\r\n        className=\"p-6 group/file block rounded-lg cursor-pointer w-full relative overflow-hidden\"\r\n      >\r\n        <input\r\n          ref={fileInputRef}\r\n          id=\"file-upload-handle\"\r\n          type=\"file\"\r\n          onChange={(e) => handleFileChange(Array.from(e.target.files || []))}\r\n          className=\"hidden\"\r\n        />\r\n        <div className=\"flex flex-col items-center justify-center\">\r\n          <p className=\"relative z-20 font-bold text-dark dark:text-neutral-300 text-xl\">\r\n            Upload file\r\n          </p>\r\n          <p className=\"relative z-20 font-normal text-neutral-400 dark:text-neutral-400 text-base mt-2\">\r\n            Drag or drop your files here or click to upload\r\n          </p>\r\n          <div className=\"relative w-full mt-10 max-w-xl mx-auto\">\r\n            {files.length > 0 ? (\r\n              files.map((file, idx) => (\r\n                <FileItem\r\n                  key={file.name + idx}\r\n                  file={file}\r\n                  formatFileSize={formatFileSize}\r\n                  formatDate={formatDate}\r\n                  isFirst={idx === 0}\r\n                />\r\n              ))\r\n            ) : (\r\n              <EmptyState isDragActive={isDragActive} />\r\n            )}\r\n          </div>\r\n        </div>\r\n      </motion.div>\r\n    </div>\r\n  );\r\n};\r\n\r\n// File Item Component\r\ninterface FileItemProps {\r\n  file: File;\r\n  formatFileSize: (size: number) => string;\r\n  formatDate: (timestamp: number) => string;\r\n  isFirst: boolean;\r\n}\r\nconst FileItem: React.FC<FileItemProps> = ({\r\n  file,\r\n  formatFileSize,\r\n  formatDate,\r\n  isFirst,\r\n}) => (\r\n  <motion.div\r\n    layoutId={isFirst ? \"file-upload\" : `file-upload-${file.name}`}\r\n    className={cn(\r\n      \"relative overflow-hidden z-40 bg-white dark:bg-white/10 flex flex-col items-start justify-start md:h-24 p-4 mt-4 w-full mx-auto rounded-md shadow-sm\"\r\n    )}\r\n  >\r\n    <div className=\"flex justify-between w-full items-center gap-4\">\r\n      <motion.p\r\n        initial={{ opacity: 0 }}\r\n        animate={{ opacity: 1 }}\r\n        layout\r\n        className=\"text-sm font-medium text-neutral-700 dark:text-neutral-300 truncate max-w-xs\"\r\n      >\r\n        {file.name}\r\n      </motion.p>\r\n      <motion.p\r\n        initial={{ opacity: 0 }}\r\n        animate={{ opacity: 1 }}\r\n        layout\r\n        className=\"rounded-lg px-2 py-1 w-fit shrink-0 text-xs font-medium text-neutral-600 dark:bg-white/20 dark:text-white shadow-input\"\r\n      >\r\n        {formatFileSize(file.size)} MB\r\n      </motion.p>\r\n    </div>\r\n    <div className=\"flex text-sm md:flex-row flex-col items-start md:items-center w-full mt-2 justify-between text-neutral-600 dark:text-neutral-400\">\r\n      <motion.p\r\n        initial={{ opacity: 0 }}\r\n        animate={{ opacity: 1 }}\r\n        layout\r\n        className=\"px-3 py-1 rounded-md bg-gray-100 dark:bg-white/20 text-xs\"\r\n      >\r\n        {file.type}\r\n      </motion.p>\r\n      <motion.p\r\n        initial={{ opacity: 0 }}\r\n        animate={{ opacity: 1 }}\r\n        layout\r\n        className=\"text-sm\"\r\n      >\r\n        modified {formatDate(file.lastModified)}\r\n      </motion.p>\r\n    </div>\r\n  </motion.div>\r\n);\r\n\r\n// Empty State Component\r\ninterface EmptyStateProps {\r\n  isDragActive: boolean;\r\n}\r\nconst EmptyState: React.FC<EmptyStateProps> = ({ isDragActive }) => (\r\n  <>\r\n    <motion.div\r\n      layoutId=\"file-upload\"\r\n      variants={mainVariant}\r\n      transition={{\r\n        type: \"spring\",\r\n        stiffness: 300,\r\n        damping: 20,\r\n      }}\r\n      className={cn(\r\n        \"relative group-hover/file:shadow-2xl z-40 bg-white dark:bg-white/10 flex items-center justify-center h-28 mt-4 w-full max-w-[8rem] mx-auto rounded-md shadow-[0px_10px_50px_rgba(0,0,0,0.1)]\"\r\n      )}\r\n    >\r\n      {isDragActive ? (\r\n        <motion.p\r\n          initial={{ opacity: 0 }}\r\n          animate={{ opacity: 1 }}\r\n          className=\"text-neutral-600 flex flex-col items-center\"\r\n        >\r\n          Drop it\r\n          <IconUpload className=\"h-6 w-6 text-neutral-600 dark:text-neutral-400\" />\r\n        </motion.p>\r\n      ) : (\r\n        <IconUpload className=\"h-6 w-6 text-neutral-600 dark:text-neutral-300\" />\r\n      )}\r\n    </motion.div>\r\n    <motion.div\r\n      variants={secondaryVariant}\r\n      className=\"absolute opacity-0 border border-dashed border-primary inset-0 z-30 bg-transparent flex items-center justify-center h-28 mt-4 w-full max-w-[8rem] mx-auto rounded-md\"\r\n    />\r\n  </>\r\n);\r\n\r\n\r\nexport default function FileUploadMotion(){\r\n  const [files, setFiles] = useState<File[]>([]);\r\n  const handleFileUpload = (files: File[]) => {\r\n    setFiles(files);\r\n  };\r\n    return (\r\n        <>\r\n<div className=\"w-full max-w-md mx-auto min-h-72 border border-dashed bg-white dark:bg-forest-black border-border rounded-lg\">\r\n      <FileUploadStruc onChange={handleFileUpload} />\r\n    </div>\r\n        </>\r\n    )\r\n}\r\n\r\n\r\n",
      "type": "registry:component",
      "target": "components/animated/forms/file-upload/FileUploadMotion.tsx"
    }
  ]
}