{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "marquee",
  "type": "registry:component",
  "title": "Marquee",
  "description": "Continuously scrolling content lane for badges, logos, and status chips.",
  "dependencies": [
    "@vllnt/ui@^0.2.1"
  ],
  "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 = React.forwardRef<HTMLDivElement, MarqueeProps>(\n  (\n    {\n      children,\n      className,\n      duration,\n      fade = true,\n      gap = \"1rem\",\n      pauseOnHover = false,\n      repeat = 1,\n      reverse = false,\n      speed = \"normal\",\n      style,\n      vertical = false,\n      ...props\n    },\n    ref,\n  ) => {\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={\n          fade ? { ...style, maskImage, WebkitMaskImage: maskImage } : style\n        }\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);\n\nMarquee.displayName = \"Marquee\";\n",
      "type": "registry:component"
    }
  ],
  "version": "0.2.1",
  "stability": "stable"
}
