{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"loader","type":"registry:ui","title":"Loader","description":"Five small, clean loaders in one component: a stretching arc spinner, squashy hopping dots, equalizer bars, a heartbeat pulse and bunching orbit dots.","dependencies":[],"registryDependencies":[],"files":[{"path":"registry/ui/loader.tsx","type":"registry:ui","content":"\"use client\";\n\nimport type { CSSProperties } from \"react\";\n\nexport type LoaderVariant = \"spinner\" | \"dots\" | \"bars\" | \"pulse\" | \"orbit\";\n\nexport interface LoaderProps {\n  variant?: LoaderVariant;\n  /** Box size in px. */\n  size?: number;\n  color?: string;\n  /** Speed multiplier. */\n  speed?: number;\n  /** Announced to screen readers. */\n  label?: string;\n  className?: string;\n}\n\n// Every duration is a multiple of --d, so `speed` scales the whole set at once.\nconst css = `\n.ldr *{box-sizing:border-box}\n.ldr-spin{animation:ldr-rotate calc(var(--d)*1.4s) linear infinite}\n.ldr-spin circle+circle{stroke-dasharray:1 150;animation:ldr-dash calc(var(--d)*1.4s) ease-in-out infinite}\n@keyframes ldr-rotate{to{transform:rotate(360deg)}}\n@keyframes ldr-dash{0%{stroke-dasharray:1 150;stroke-dashoffset:0}50%{stroke-dasharray:90 150;stroke-dashoffset:-35}100%{stroke-dasharray:90 150;stroke-dashoffset:-124}}\n.ldr-dot{animation:ldr-hop calc(var(--d)*1s) cubic-bezier(.45,0,.55,1) infinite both;transform-origin:50% 100%}\n@keyframes ldr-hop{0%,70%,100%{transform:translateY(0) scale(1.15,.85)}20%{transform:translateY(-10%) scale(.9,1.1)}40%{transform:translateY(-70%) scale(.95,1.05)}60%{transform:translateY(0) scale(1.25,.75)}}\n.ldr-bar{animation:ldr-eq calc(var(--d)*1.1s) ease-in-out infinite}\n@keyframes ldr-eq{0%,100%{transform:scaleY(.35)}50%{transform:scaleY(1)}}\n.ldr-ripple{animation:ldr-ripple calc(var(--d)*1.8s) cubic-bezier(.2,.6,.35,1) infinite}\n@keyframes ldr-ripple{0%{transform:scale(.1);opacity:1}100%{transform:scale(1);opacity:0}}\n.ldr-core{animation:ldr-beat calc(var(--d)*1.8s) ease-in-out infinite}\n@keyframes ldr-beat{0%,100%{transform:scale(.8)}15%{transform:scale(1.1)}30%{transform:scale(.9)}}\n.ldr-orbit{animation:ldr-rotate calc(var(--d)*1.6s) cubic-bezier(.6,.1,.4,.9) infinite}\n@keyframes ldr-fade{50%{opacity:.35}}\n@media (prefers-reduced-motion:reduce){.ldr-spin,.ldr-spin circle+circle,.ldr-dot,.ldr-bar,.ldr-ripple,.ldr-core,.ldr-orbit{animation:ldr-fade 2s ease-in-out infinite}}\n`;\n\nexport function Loader({ variant = \"spinner\", size = 32, color = \"currentColor\", speed = 1, label = \"Loading\", className }: LoaderProps) {\n  const style = { width: size, height: size, color, \"--d\": 1 / Math.max(0.1, speed) } as CSSProperties;\n  const delay = (i: number, step: number) => ({ animationDelay: `calc(var(--d) * ${i * step}s)` });\n\n  return (\n    <span role=\"status\" className={`ldr relative inline-grid shrink-0 place-items-center ${className ?? \"\"}`} style={style}>\n      <style href=\"loader\" precedence=\"default\">\n        {css}\n      </style>\n      <span className=\"sr-only\">{label}</span>\n\n      {variant === \"spinner\" && (\n        <svg aria-hidden viewBox=\"0 0 50 50\" className=\"ldr-spin size-full\">\n          <circle cx=\"25\" cy=\"25\" r=\"20\" fill=\"none\" stroke=\"currentColor\" strokeOpacity={0.15} strokeWidth=\"5\" />\n          <circle cx=\"25\" cy=\"25\" r=\"20\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"5\" strokeLinecap=\"round\" />\n        </svg>\n      )}\n\n      {variant === \"dots\" && (\n        <span aria-hidden className=\"flex h-1/2 w-full items-end justify-between px-[4%]\">\n          {[0, 1, 2].map((i) => (\n            <span key={i} className=\"ldr-dot aspect-square w-[24%] rounded-full bg-current\" style={delay(i, 0.14)} />\n          ))}\n        </span>\n      )}\n\n      {variant === \"bars\" && (\n        <span aria-hidden className=\"flex h-3/4 w-full items-center justify-between\">\n          {[0, 1, 2, 3, 4].map((i) => (\n            <span key={i} className=\"ldr-bar h-full w-[13%] rounded-full bg-current\" style={delay(i, 0.1)} />\n          ))}\n        </span>\n      )}\n\n      {variant === \"pulse\" && (\n        <>\n          {[0, 1].map((i) => (\n            <span aria-hidden key={i} className=\"ldr-ripple absolute inset-0 rounded-full border-2 border-current\" style={delay(i, 0.9)} />\n          ))}\n          <span aria-hidden className=\"ldr-core size-1/3 rounded-full bg-current\" />\n        </>\n      )}\n\n      {variant === \"orbit\" &&\n        [0, 1, 2].map((i) => (\n          <span aria-hidden key={i} className=\"ldr-orbit absolute inset-0\" style={delay(i, 0.12)}>\n            <span\n              className=\"absolute top-0 left-1/2 -translate-x-1/2 rounded-full bg-current\"\n              style={{ width: `${26 - i * 6}%`, height: `${26 - i * 6}%`, opacity: 1 - i * 0.25 }}\n            />\n          </span>\n        ))}\n    </span>\n  );\n}\n"}]}