{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "marquee-effect",
  "type": "registry:component",
  "title": "Marquee Effect",
  "author": "Toby Belhome",
  "description": "Add dynamic movement to your UI with Marquee effect, ideal for highlighting important information with smooth, continuous scrolling. Built with Tailwind CSS and Motion.",
  "dependencies": [
    "motion",
    "react-use-measure"
  ],
  "registryDependencies": [
    "http://localhost:3000/r/marquee-effect.json"
  ],
  "files": [
    {
      "path": "examples/motion/components/marquee-effect/01/marquee-effect.tsx",
      "content": "\"use client\";\n\nimport React from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport { useMotionValue, animate, motion } from \"motion/react\";\nimport useMeasure from \"react-use-measure\";\n\nexport type InfiniteSliderProps = {\n  children: React.ReactNode;\n  gap?: number;\n  speed?: number;\n  speedOnHover?: number;\n  direction?: \"horizontal\" | \"vertical\";\n  reverse?: boolean;\n  className?: string;\n};\n\nexport function MarqueeEffect({\n  children,\n  gap = 16,\n  speed = 100,\n  speedOnHover,\n  direction = \"horizontal\",\n  reverse = false,\n  className\n}: InfiniteSliderProps) {\n  const [currentSpeed, setCurrentSpeed] = React.useState(speed);\n  const [ref, { width, height }] = useMeasure();\n  const translation = useMotionValue(0);\n  const [isTransitioning, setIsTransitioning] = React.useState(false);\n  const [key, setKey] = React.useState(0);\n\n  React.useEffect(() => {\n    let controls;\n    const size = direction === \"horizontal\" ? width : height;\n    const contentSize = size + gap;\n    const from = reverse ? -contentSize / 2 : 0;\n    const to = reverse ? 0 : -contentSize / 2;\n\n    const distanceToTravel = Math.abs(to - from);\n    const duration = distanceToTravel / currentSpeed;\n\n    if (isTransitioning) {\n      const remainingDistance = Math.abs(translation.get() - to);\n      const transitionDuration = remainingDistance / currentSpeed;\n\n      controls = animate(translation, [translation.get(), to], {\n        ease: \"linear\",\n        duration: transitionDuration,\n        onComplete: () => {\n          setIsTransitioning(false);\n          setKey((prevKey) => prevKey + 1);\n        }\n      });\n    } else {\n      controls = animate(translation, [from, to], {\n        ease: \"linear\",\n        duration: duration,\n        repeat: Infinity,\n        repeatType: \"loop\",\n        repeatDelay: 0,\n        onRepeat: () => {\n          translation.set(from);\n        }\n      });\n    }\n\n    return controls?.stop;\n  }, [key, translation, currentSpeed, width, height, gap, isTransitioning, direction, reverse]);\n\n  const hoverProps = speedOnHover\n    ? {\n        onHoverStart: () => {\n          setIsTransitioning(true);\n          setCurrentSpeed(speedOnHover);\n        },\n        onHoverEnd: () => {\n          setIsTransitioning(true);\n          setCurrentSpeed(speed);\n        }\n      }\n    : {};\n\n  return (\n    <div className={cn(\"overflow-hidden\", className)}>\n      <motion.div\n        className={cn(\"flex\", { \"w-max\": direction !== \"vertical\" })}\n        style={{\n          ...(direction === \"horizontal\" ? { x: translation } : { y: translation }),\n          gap: `${gap}px`,\n          flexDirection: direction === \"horizontal\" ? \"row\" : \"column\"\n        }}\n        ref={ref}\n        {...hoverProps}>\n        {children}\n        {children}\n      </motion.div>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/marquee-effect/marquee-effect.tsx"
    },
    {
      "path": "examples/motion/components/marquee-effect/01/page.tsx",
      "content": "import { MarqueeEffect } from \"./marquee-effect\";\n\nconst images = [\n  \"/images/products/list1.png\",\n  \"/images/products/list2.png\",\n  \"/images/products/list3.png\",\n  \"/images/products/list4.png\",\n  \"/images/products/list5.png\",\n  \"/images/products/list6.png\",\n  \"/images/products/list7.png\",\n  \"/images/products/list8.png\",\n  \"/images/products/list9.png\",\n  \"/images/products/list10.png\"\n];\n\nexport default function MarqueeEffectExample() {\n  return (\n    <MarqueeEffect gap={24}>\n      {images.map((src, i) => (\n        <img\n          key={i}\n          src={src}\n          alt={`Product ${i + 1}`}\n          className=\"aspect-square w-32 rounded-md object-cover\"\n        />\n      ))}\n    </MarqueeEffect>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/marquee-effect/marquee-effect-example.tsx"
    }
  ],
  "meta": {
    "isPro": false
  }
}