{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "loader",
  "title": "Loader",
  "description": "A single flexible loading spinner component with 22 built-in animated variants (spinner, dots, bars, skeleton, DNA, matrix and more), Tailwind dark mode support, and configurable size.",
  "files": [
    {
      "path": "registry/loader.tsx",
      "content": "import React from 'react';\n\nexport type LoaderVariant =\n  | 'classic-spinner'\n  | 'dots-pulse'\n  | 'pulse-ring'\n  | 'bars'\n  | 'square-spin'\n  | 'double-bounce'\n  | 'circular-progress'\n  | 'wave-loader'\n  | 'skeleton'\n  | 'glow-pulse'\n  | 'clock'\n  | 'hourglass'\n  | 'gear'\n  | 'orbit'\n  | 'snake'\n  | 'infinity'\n  | 'text-shimmer'\n  | 'grid'\n  | 'heartbeat'\n  | 'floating-bubble'\n  | 'matrix'\n  | 'loader-dna';\n\nexport interface LoaderProps {\n  variant: LoaderVariant;\n  size?: 'sm' | 'md' | 'lg' | 'xl';\n  className?: string;\n  color?: string;\n}\n\nexport const Loader: React.FC<LoaderProps> = ({\n  variant,\n  size = 'md',\n  className = '',\n  color = 'currentColor',\n}) => {\n  const sizeClasses = {\n    sm: 'w-4 h-4',\n    md: 'w-8 h-8',\n    lg: 'w-12 h-12',\n    xl: 'w-16 h-16',\n  };\n\n  const containerSize = sizeClasses[size];\n  const primaryColorClass = 'text-zinc-900 dark:text-zinc-50';\n  const primaryBgClass = 'bg-zinc-900 dark:bg-zinc-50';\n  const primaryBorderClass = 'border-zinc-900 dark:border-zinc-50';\n\n  switch (variant) {\n    case 'classic-spinner':\n      return (\n        <div className={`${containerSize} border-2 border-zinc-200 dark:border-zinc-800 border-t-zinc-900 dark:border-t-zinc-50 rounded-full animate-spin ${className}`} />\n      );\n\n    case 'dots-pulse':\n      return (\n        <div className={`flex gap-1 items-center ${className}`}>\n          {[0, 1, 2].map((i) => (\n            <div\n              key={i}\n              className={`${size === 'sm' ? 'w-1 h-1' : 'w-2 h-2'} ${primaryBgClass} rounded-full animate-bounce`}\n              style={{ animationDelay: `${i * 0.15}s` }}\n            />\n          ))}\n        </div>\n      );\n\n    case 'pulse-ring':\n      return (\n        <div className={`relative ${containerSize} ${className}`}>\n          <div className=\"absolute inset-0 border-2 border-zinc-900 dark:border-zinc-50 rounded-full animate-ping opacity-75\" />\n          <div className=\"absolute inset-2 border-2 border-zinc-600 dark:border-zinc-400 rounded-full animate-pulse\" />\n        </div>\n      );\n\n    case 'bars':\n      return (\n        <div className={`flex items-end gap-1 h-8 ${className}`}>\n          {[0, 1, 2, 3, 4].map((i) => (\n            <div\n              key={i}\n              className={`w-1 ${primaryBgClass} rounded-full animate-[pulse_1s_ease-in-out_infinite]`}\n              style={{ height: `${20 + Math.random() * 80}%`, animationDelay: `${i * 0.1}s` }}\n            />\n          ))}\n        </div>\n      );\n\n    case 'square-spin':\n      return (\n        <div className={`${containerSize} ${primaryBgClass} animate-[spin_2s_linear_infinite] rounded-sm shadow-sm ${className}`} />\n      );\n\n    case 'double-bounce':\n      return (\n        <div className={`relative ${containerSize} ${className}`}>\n          <div className={`absolute inset-0 ${primaryBgClass} rounded-full opacity-60 animate-bounce`} />\n          <div className=\"absolute inset-0 bg-zinc-400 dark:bg-zinc-600 rounded-full opacity-60 animate-bounce delay-700\" />\n        </div>\n      );\n\n    case 'circular-progress':\n      return (\n        <svg className={`${containerSize} animate-spin ${className}`} viewBox=\"0 0 50 50\">\n          <circle\n            className=\"stroke-zinc-900 dark:stroke-zinc-50 fill-none\"\n            cx=\"25\" cy=\"25\" r=\"20\"\n            strokeWidth=\"4\"\n            strokeLinecap=\"round\"\n            strokeDasharray=\"80, 200\"\n          />\n        </svg>\n      );\n\n    case 'wave-loader':\n      return (\n        <div className={`flex gap-0.5 ${className}`}>\n          {[...Array(10)].map((_, i) => (\n            <div\n              key={i}\n              className={`w-1 h-4 ${primaryBgClass} animate-[pulse_1.5s_infinite]`}\n              style={{ animationDelay: `${i * 0.1}s` }}\n            />\n          ))}\n        </div>\n      );\n\n    case 'skeleton':\n      return (\n        <div className={`relative overflow-hidden bg-zinc-100 dark:bg-zinc-900 rounded border border-zinc-200/50 dark:border-zinc-800/50 ${containerSize} ${className}`}>\n          <div className=\"absolute inset-0 bg-gradient-to-r from-transparent via-zinc-200 dark:via-zinc-800 to-transparent animate-shimmer -translate-x-full\" />\n        </div>\n      );\n\n    case 'glow-pulse':\n      return (\n        <div className={`${primaryBgClass} rounded-full shadow-[0_0_20px_rgba(0,0,0,0.2)] dark:shadow-[0_0_20px_rgba(255,255,255,0.1)] animate-pulse ${containerSize} ${className}`} />\n      );\n\n    case 'clock':\n      return (\n        <div className={`${containerSize} border-2 border-zinc-300 dark:border-zinc-700 rounded-full relative ${className}`}>\n          <div className=\"absolute top-1/2 left-1/2 w-[40%] h-0.5 bg-zinc-900 dark:bg-zinc-50 origin-left -rotate-90 animate-[spin_2s_linear_infinite]\" />\n          <div className=\"absolute top-1/2 left-1/2 w-[30%] h-0.5 bg-zinc-500 origin-left -rotate-90 animate-[spin_8s_linear_infinite]\" />\n        </div>\n      );\n\n    case 'hourglass':\n      return (\n        <div className={`${containerSize} relative animate-[spin_2s_ease-in-out_infinite] ${className}`}>\n          <div className=\"absolute inset-0 border-t-[16px] border-t-zinc-900 dark:border-t-zinc-50 border-x-[16px] border-x-transparent border-b-[16px] border-b-transparent rounded-t-full\" />\n          <div className=\"absolute inset-0 border-b-[16px] border-b-zinc-400 dark:border-b-zinc-600 border-x-[16px] border-x-transparent border-t-[16px] border-t-transparent rounded-b-full\" />\n        </div>\n      );\n\n    case 'gear':\n      return (\n        <div className={`${containerSize} ${primaryColorClass} animate-[spin_3s_linear_infinite] ${className}`}>\n          <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n            <path d=\"M12.22 2h-.44a2 2 0 0 0-2 2 2 2 0 0 1-2 2 2 2 0 0 0-2 2 2 2 0 0 1-2 2 2 2 0 0 0-2 2v.44a2 2 0 0 0 2 2 2 2 0 0 1 2 2 2 2 0 0 0 2 2 2 2 0 0 1 2 2 2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2 2 2 0 0 1 2-2 2 2 0 0 0 2-2 2 2 0 0 1 2-2 2 2 0 0 0 2-2v-.44a2 2 0 0 0-2-2 2 2 0 0 1-2-2 2 2 0 0 0-2-2 2 2 0 0 1-2-2 2 2 0 0 0-2-2Z\" />\n            <circle cx=\"12\" cy=\"12\" r=\"3\" />\n          </svg>\n        </div>\n      );\n\n    case 'orbit':\n      return (\n        <div className={`${containerSize} relative flex items-center justify-center ${className}`}>\n          <div className={`w-2 h-2 ${primaryBgClass} rounded-full`} />\n          <div className=\"absolute w-full h-full border border-zinc-200 dark:border-zinc-800 rounded-full animate-spin\">\n            <div className={`absolute top-0 left-1/2 -translate-x-1/2 w-1.5 h-1.5 ${primaryBgClass} rounded-full`} />\n          </div>\n        </div>\n      );\n\n    case 'snake':\n      return (\n        <div className={`${containerSize} border-2 border-zinc-100 dark:border-zinc-900 relative rounded-md overflow-hidden ${className}`}>\n          <div className={`absolute inset-0 border-2 ${primaryBorderClass} animate-snake`} />\n        </div>\n      );\n\n    case 'infinity':\n      return (\n        <div className={`${containerSize} ${primaryColorClass} ${className}`}>\n          <svg viewBox=\"0 0 100 50\" className=\"w-full h-full\">\n            <path\n              fill=\"none\"\n              stroke=\"currentColor\"\n              strokeWidth=\"4\"\n              strokeDasharray=\"10 5\"\n              className=\"animate-[shimmer_2s_linear_infinite]\"\n              d=\"M25,25 C25,10 40,10 50,25 C60,40 75,40 75,25 C75,10 60,10 50,25 C40,40 25,40 25,25\"\n            />\n          </svg>\n        </div>\n      );\n\n    case 'text-shimmer':\n      return (\n        <div className={`text-xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-zinc-400 via-zinc-900 dark:via-zinc-100 to-zinc-400 bg-[length:200%_auto] animate-[shimmer_2s_linear_infinite] ${className}`}>\n          Loading...\n        </div>\n      );\n\n    case 'grid':\n      return (\n        <div className={`grid grid-cols-3 gap-1 ${className}`}>\n          {[...Array(9)].map((_, i) => (\n            <div\n              key={i}\n              className={`w-2 h-2 ${primaryBgClass} rounded-sm animate-pulse`}\n              style={{ animationDelay: `${i * 0.1}s` }}\n            />\n          ))}\n        </div>\n      );\n\n    case 'heartbeat':\n      return (\n        <div className={`${containerSize} ${primaryColorClass} animate-[ping_1.5s_infinite] flex items-center justify-center ${className}`}>\n          <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className=\"w-full h-full\">\n            <path d=\"M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z\" />\n          </svg>\n        </div>\n      );\n\n    case 'matrix':\n      return (\n        <div className={`flex flex-col gap-0.5 overflow-hidden ${containerSize} items-center ${className}`}>\n          {[...Array(4)].map((_, i) => (\n            <div\n              key={i}\n              className=\"w-full h-1 bg-zinc-100 dark:bg-zinc-900 relative\"\n            >\n              <div\n                className={`absolute top-0 bottom-0 w-4 ${primaryBgClass} shadow-[0_0_10px_rgba(0,0,0,0.1)]`}\n                style={{\n                  left: '-20%',\n                  animation: `shimmer 2s linear infinite`,\n                  animationDelay: `${i * 0.5}s`,\n                }}\n              />\n            </div>\n          ))}\n        </div>\n      );\n\n    case 'loader-dna':\n      return (\n        <div className={`flex justify-center items-center h-full gap-1 ${className}`}>\n          {[...Array(5)].map((_, i) => (\n            <div key={i} className=\"flex flex-col gap-2\">\n              <div className={`w-2 h-2 ${primaryBgClass} rounded-full animate-bounce`} style={{ animationDelay: `${i * 0.1}s` }} />\n              <div className=\"w-2 h-2 bg-zinc-300 dark:bg-zinc-700 rounded-full animate-bounce\" style={{ animationDelay: `${(i * 0.1) + 0.5}s` }} />\n            </div>\n          ))}\n        </div>\n      );\n\n    case 'floating-bubble':\n      return (\n        <div className={`relative overflow-hidden ${containerSize} border border-zinc-200 dark:border-zinc-800 rounded-lg bg-zinc-50/50 dark:bg-zinc-900/50 ${className}`}>\n          {[...Array(5)].map((_, i) => (\n            <div\n              key={i}\n              className={`absolute ${primaryBgClass} opacity-30 rounded-full animate-bounce`}\n              style={{\n                width: `${Math.random() * 8 + 4}px`,\n                height: `${Math.random() * 8 + 4}px`,\n                left: `${Math.random() * 80 + 10}%`,\n                bottom: '-20%',\n                animationDuration: `${Math.random() * 3 + 2}s`,\n                animationDelay: `${Math.random() * 2}s`,\n              }}\n            />\n          ))}\n        </div>\n      );\n\n    default:\n      return null;\n  }\n};\n",
      "type": "registry:ui"
    }
  ],
  "css": {
    "@keyframes snake": {
      "0%, 100%": {
        "clip-path": "inset(0 0 95% 0)"
      },
      "25%": {
        "clip-path": "inset(0 95% 0 0)"
      },
      "50%": {
        "clip-path": "inset(95% 0 0 0)"
      },
      "75%": {
        "clip-path": "inset(0 0 0 95%)"
      }
    },
    "@keyframes shimmer": {
      "0%": {
        "transform": "translateX(-100%)"
      },
      "100%": {
        "transform": "translateX(100%)"
      }
    },
    "@utility animate-snake": {
      "animation": "snake 2s linear infinite"
    },
    "@utility animate-shimmer": {
      "animation": "shimmer 2s infinite"
    }
  },
  "type": "registry:ui"
}