{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "loader-signal-bars",
  "title": "Signal Bars Loader",
  "description": "Audio waveform / frequency spectrum bars that pulse rhythmically as a loading indicator",
  "dependencies": [],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/blocks/loaders/loader-signal-bars/components/elements/loader-signal-bars.tsx",
      "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst sizeConfig = {\n  sm: { height: \"h-4\", width: \"w-0.5\", gap: \"gap-0.5\" },\n  md: { height: \"h-6\", width: \"w-[3px]\", gap: \"gap-[3px]\" },\n  lg: { height: \"h-8\", width: \"w-1\", gap: \"gap-1\" },\n};\n\nexport interface LoaderSignalBarsProps {\n  bars?: number;\n  variant?: \"equalizer\" | \"waveform\" | \"heartbeat\";\n  size?: \"sm\" | \"md\" | \"lg\";\n  className?: string;\n}\n\nexport function LoaderSignalBars({\n  bars = 5,\n  variant = \"equalizer\",\n  size = \"md\",\n  className,\n}: LoaderSignalBarsProps) {\n  const { height, width, gap } = sizeConfig[size];\n  const barArray = Array.from({ length: bars }, (_, i) => i);\n\n  const getAnimationStyle = (index: number) => {\n    if (variant === \"equalizer\") {\n      const durations = [0.8, 1.1, 0.9, 1.3, 1.0];\n      const duration = durations[index % durations.length];\n      const delay = index * 0.1;\n      return {\n        animation: `equalizer ${duration}s ease-in-out ${delay}s infinite`,\n      };\n    }\n\n    if (variant === \"waveform\") {\n      const delay = index * 0.15;\n      return {\n        animation: `waveform 1.2s ease-in-out ${delay}s infinite`,\n      };\n    }\n\n    if (variant === \"heartbeat\") {\n      return {\n        animation: `heartbeat 1.5s ease-in-out infinite`,\n      };\n    }\n\n    return {};\n  };\n\n  return (\n    <>\n      <style>{`\n        @keyframes equalizer {\n          0%, 100% {\n            transform: scaleY(0.3);\n          }\n          50% {\n            transform: scaleY(1);\n          }\n        }\n\n        @keyframes waveform {\n          0%, 100% {\n            transform: scaleY(0.4);\n          }\n          50% {\n            transform: scaleY(1);\n          }\n        }\n\n        @keyframes heartbeat {\n          0%, 100% {\n            transform: scaleY(0.3);\n          }\n          10% {\n            transform: scaleY(1);\n          }\n          20% {\n            transform: scaleY(0.3);\n          }\n          30% {\n            transform: scaleY(0.9);\n          }\n          40%, 60% {\n            transform: scaleY(0.3);\n          }\n        }\n      `}</style>\n      <output\n        data-slot=\"loader-signal-bars\"\n        aria-live=\"polite\"\n        aria-label=\"Loading\"\n        className={cn(\"flex items-center justify-center\", gap, className)}\n      >\n        <span className=\"sr-only\">Loading</span>\n        {barArray.map((index) => (\n          <span\n            key={index}\n            className={cn(\n              \"rounded-full bg-foreground origin-center will-change-transform\",\n              height,\n              width,\n            )}\n            style={getAnimationStyle(index)}\n          />\n        ))}\n      </output>\n    </>\n  );\n}\n\nexport type { LoaderSignalBarsProps as LoaderSignalBarsPropsType };\n",
      "type": "registry:component"
    }
  ],
  "docs": "Equalizer-style loading bars with configurable count, variants (equalizer, waveform, heartbeat), and sizes. CSS-only animations.",
  "categories": [
    "loaders"
  ],
  "type": "registry:block"
}