{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "marquee",
  "title": "Marquee",
  "description": "Continuously scrolling content lane for badges, logos, and status chips.",
  "dependencies": [
    "@vllnt/ui@^0.3.0"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/marquee/marquee.tsx",
      "content": "import * as React from \"react\";\n\nimport { cn } from \"@vllnt/ui\";\n\nexport type MarqueeSpeed = \"fast\" | \"normal\" | \"slow\";\n\nexport type MarqueeProps = React.ComponentPropsWithoutRef<\"div\"> & {\n  duration?: number;\n  fade?: boolean;\n  gap?: number | string;\n  pauseOnHover?: boolean;\n  repeat?: number;\n  reverse?: boolean;\n  speed?: MarqueeSpeed;\n  vertical?: boolean;\n};\n\nfunction getGapValue(gap: number | string): string {\n  return typeof gap === \"number\" ? `${gap}px` : gap;\n}\n\nfunction getMaskImage(vertical: boolean): string {\n  return vertical\n    ? \"linear-gradient(to bottom, transparent, black 12%, black 88%, transparent)\"\n    : \"linear-gradient(to right, transparent, black 12%, black 88%, transparent)\";\n}\n\nfunction getTrackItems(\n  children: React.ReactNode,\n  repeat: number,\n): React.ReactNode[] {\n  const items = React.Children.toArray(children);\n\n  return Array.from({ length: Math.max(1, repeat) }, (_, copyIndex) =>\n    items.map((item, itemIndex) => (\n      <div className=\"shrink-0\" key={`${copyIndex}-${itemIndex}`}>\n        {item}\n      </div>\n    )),\n  ).flat();\n}\n\nfunction getDuration(\n  duration: number | undefined,\n  speed: MarqueeSpeed,\n): number {\n  if (duration !== undefined) {\n    return duration;\n  }\n\n  switch (speed) {\n    case \"fast\":\n      return 10;\n    case \"normal\":\n      return 20;\n    case \"slow\":\n      return 32;\n  }\n}\n\nexport const Marquee = ({\n  children,\n  className,\n  duration,\n  fade = true,\n  gap = \"1rem\",\n  pauseOnHover = false,\n  ref,\n  repeat = 1,\n  reverse = false,\n  speed = \"normal\",\n  style,\n  vertical = false,\n  ...props\n}: MarqueeProps & { ref?: React.Ref<HTMLDivElement> }) => {\n  const resolvedGap = getGapValue(gap);\n  const resolvedDuration = getDuration(duration, speed);\n  const trackItems = getTrackItems(children, repeat);\n\n  const animationStyle: React.CSSProperties = {\n    animationDirection: reverse ? \"reverse\" : \"normal\",\n    animationDuration: `${resolvedDuration}s`,\n    animationIterationCount: \"infinite\",\n    animationName: vertical ? \"vllnt-marquee-y\" : \"vllnt-marquee-x\",\n    animationTimingFunction: \"linear\",\n  };\n  const maskImage = getMaskImage(vertical);\n\n  return (\n    <div\n      className={cn(\n        \"group relative overflow-hidden\",\n        vertical ? \"flex h-full flex-col\" : \"flex w-full flex-row\",\n        className,\n      )}\n      ref={ref}\n      style={fade ? { ...style, maskImage, WebkitMaskImage: maskImage } : style}\n      {...props}\n    >\n      <div\n        className={cn(\n          \"flex shrink-0 will-change-transform motion-reduce:animate-none motion-reduce:transform-none\",\n          pauseOnHover && \"group-hover:[animation-play-state:paused]\",\n          vertical ? \"min-h-full flex-col\" : \"min-w-full flex-row\",\n        )}\n        style={animationStyle}\n      >\n        {[0, 1].map((groupIndex) => (\n          <div\n            aria-hidden={groupIndex === 1}\n            className={cn(\n              \"flex shrink-0\",\n              vertical ? \"flex-col items-stretch\" : \"flex-row items-center\",\n            )}\n            key={groupIndex}\n            style={{ gap: resolvedGap }}\n          >\n            {trackItems}\n          </div>\n        ))}\n      </div>\n    </div>\n  );\n};\n\nMarquee.displayName = \"Marquee\";\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component",
  "version": "0.3.0",
  "stability": "stable"
}
