{
  "name": "multi-step-loader",
  "type": "registry:ui",
  "dependencies": [
    "@tabler/icons-react",
    "motion"
  ],
  "files": [
    {
      "path": "components/ui/multi-step-loader.tsx",
      "content": "\"use client\";\nimport { cn } from \"@/lib/utils\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport { useState, useEffect } from \"react\";\n\nconst CheckIcon = ({ className }: { className?: string }) => {\n  return (\n    <svg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      fill=\"none\"\n      viewBox=\"0 0 24 24\"\n      strokeWidth={1.5}\n      stroke=\"currentColor\"\n      className={cn(\"w-6 h-6 \", className)}\n    >\n      <path d=\"M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z\" />\n    </svg>\n  );\n};\n\nconst CheckFilled = ({ className }: { className?: string }) => {\n  return (\n    <svg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      viewBox=\"0 0 24 24\"\n      fill=\"currentColor\"\n      className={cn(\"w-6 h-6 \", className)}\n    >\n      <path\n        fillRule=\"evenodd\"\n        d=\"M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm13.36-1.814a.75.75 0 1 0-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.14-.094l3.75-5.25Z\"\n        clipRule=\"evenodd\"\n      />\n    </svg>\n  );\n};\n\ntype LoadingState = {\n  text: string;\n};\n\nconst LoaderCore = ({\n  loadingStates,\n  value = 0,\n}: {\n  loadingStates: LoadingState[];\n  value?: number;\n}) => {\n  return (\n    <div className=\"flex relative justify-start max-w-xl mx-auto flex-col mt-40\">\n      {loadingStates.map((loadingState, index) => {\n        const distance = Math.abs(index - value);\n        const opacity = Math.max(1 - distance * 0.2, 0); // Minimum opacity is 0, keep it 0.2 if you're sane.\n\n        return (\n          <motion.div\n            key={index}\n            className={cn(\"text-left flex gap-2 mb-4\")}\n            initial={{ opacity: 0, y: -(value * 40) }}\n            animate={{ opacity: opacity, y: -(value * 40) }}\n            transition={{ duration: 0.5 }}\n          >\n            <div>\n              {index > value && (\n                <CheckIcon className=\"text-black dark:text-white\" />\n              )}\n              {index <= value && (\n                <CheckFilled\n                  className={cn(\n                    \"text-black dark:text-white\",\n                    value === index &&\n                      \"text-black dark:text-lime-500 opacity-100\"\n                  )}\n                />\n              )}\n            </div>\n            <span\n              className={cn(\n                \"text-black dark:text-white\",\n                value === index && \"text-black dark:text-lime-500 opacity-100\"\n              )}\n            >\n              {loadingState.text}\n            </span>\n          </motion.div>\n        );\n      })}\n    </div>\n  );\n};\n\nexport const MultiStepLoader = ({\n  loadingStates,\n  loading,\n  duration = 2000,\n  loop = true,\n}: {\n  loadingStates: LoadingState[];\n  loading?: boolean;\n  duration?: number;\n  loop?: boolean;\n}) => {\n  const [currentState, setCurrentState] = useState(0);\n\n  useEffect(() => {\n    if (!loading) {\n      setCurrentState(0);\n      return;\n    }\n    const timeout = setTimeout(() => {\n      setCurrentState((prevState) =>\n        loop\n          ? prevState === loadingStates.length - 1\n            ? 0\n            : prevState + 1\n          : Math.min(prevState + 1, loadingStates.length - 1)\n      );\n    }, duration);\n\n    return () => clearTimeout(timeout);\n  }, [currentState, loading, loop, loadingStates.length, duration]);\n  return (\n    <AnimatePresence mode=\"wait\">\n      {loading && (\n        <motion.div\n          initial={{\n            opacity: 0,\n          }}\n          animate={{\n            opacity: 1,\n          }}\n          exit={{\n            opacity: 0,\n          }}\n          className=\"w-full h-full fixed inset-0 z-[100] flex items-center justify-center backdrop-blur-2xl\"\n        >\n          <div className=\"h-96  relative\">\n            <LoaderCore value={currentState} loadingStates={loadingStates} />\n          </div>\n\n          <div className=\"bg-gradient-to-t inset-x-0 z-20 bottom-0 bg-white dark:bg-black h-full absolute [mask-image:radial-gradient(900px_at_center,transparent_30%,white)]\" />\n        </motion.div>\n      )}\n    </AnimatePresence>\n  );\n};\n",
      "type": "registry:ui",
      "target": "components/ui/multi-step-loader.tsx"
    }
  ],
  "author": "Manu Arora <hi@manuarora.in>",
  "title": "Multi Step Loader"
}