{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "marquee",
  "title": "Marquee",
  "author": "AlgorizeTech",
  "description": "A continuously scrolling row or column of content that loops seamlessly. Use it for logo walls and testimonial strips.",
  "dependencies": [],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "src/components/custom/blocks/MarqueeBlock.tsx",
      "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport React, { forwardRef } from \"react\";\n\n// ==========================================\n// MARQUEE COMPONENT\n// ==========================================\nexport interface MarqueeProps extends React.HTMLAttributes<HTMLDivElement> {\n  /** The direction the marquee should slide */\n  direction?: \"left\" | \"right\" | \"up\" | \"down\";\n  /** The speed of the marquee. Can be a preset string or a number in seconds */\n  speed?: \"slow\" | \"normal\" | \"fast\" | number;\n  /** Whether the marquee should pause when hovered */\n  pauseOnHover?: boolean;\n  /** Whether to apply a gradient fade mask to the edges */\n  fade?: boolean;\n  /** CSS gap between items (e.g., \"1rem\", \"24px\") */\n  gap?: string;\n  /** The content to be duplicated and animated */\n  children: React.ReactNode;\n}\n\nexport const MarqueeBlock = forwardRef<HTMLDivElement, MarqueeProps>(\n  (\n    {\n      direction = \"left\",\n      speed = \"normal\",\n      pauseOnHover = false,\n      fade = false,\n      gap = \"1rem\",\n      className,\n      children,\n      ...props\n    },\n    ref,\n  ) => {\n    const isVertical = direction === \"up\" || direction === \"down\";\n    const isReverse = direction === \"right\" || direction === \"down\";\n\n    // Determine animation duration based on speed\n    let duration: string;\n    if (typeof speed === \"number\") {\n      duration = `${speed}s`;\n    } else {\n      switch (speed) {\n        case \"slow\":\n          duration = \"40s\";\n          break;\n        case \"fast\":\n          duration = \"10s\";\n          break;\n        case \"normal\":\n        default:\n          duration = \"20s\";\n          break;\n      }\n    }\n\n    const uniqueId = React.useId().replace(/:/g, \"\");\n\n    const animationName = isVertical\n      ? isReverse\n        ? `marquee-v-down-${uniqueId}`\n        : `marquee-v-up-${uniqueId}`\n      : isReverse\n        ? `marquee-h-right-${uniqueId}`\n        : `marquee-h-left-${uniqueId}`;\n\n    return (\n      <div\n        ref={ref}\n        className={cn(\n          \"group relative flex overflow-hidden\",\n          `marquee-container-${uniqueId}`,\n          isVertical ? \"flex-col\" : \"flex-row\",\n          fade && isVertical && \"mask-vertical\",\n          fade && !isVertical && \"mask-horizontal\",\n          className,\n        )}\n        style={\n          {\n            \"--marquee-gap\": gap,\n            \"--marquee-duration\": duration,\n            gap: gap,\n          } as React.CSSProperties\n        }\n        {...props}\n      >\n        <style>{`\n          .marquee-inner-${uniqueId} {\n            display: flex;\n            flex-shrink: 0;\n            justify-content: flex-start;\n            gap: var(--marquee-gap);\n            will-change: transform;\n            transform: translateZ(0);\n            backface-visibility: hidden;\n            animation: ${animationName} var(--marquee-duration) linear infinite;\n          }\n          \n          /* Instant smooth pause without jumping or browser matrix snap */\n          ${pauseOnHover ? `\n            .marquee-container-${uniqueId}:hover .marquee-inner-${uniqueId},\n            .marquee-inner-${uniqueId}:hover {\n              animation-play-state: paused !important;\n            }\n          ` : \"\"}\n\n          /* Hold still for people who asked for less motion */\n          @media (prefers-reduced-motion: reduce) {\n            .marquee-inner-${uniqueId} { animation-play-state: paused !important; }\n          }\n\n          /* Leftward scroll: from 0 to -100% */\n          @keyframes marquee-h-left-${uniqueId} {\n            from { transform: translate3d(0, 0, 0); }\n            to { transform: translate3d(calc(-100% - var(--marquee-gap)), 0, 0); }\n          }\n\n          /* Rightward scroll: from -100% to 0, running forward so pause never jumps! */\n          @keyframes marquee-h-right-${uniqueId} {\n            from { transform: translate3d(calc(-100% - var(--marquee-gap)), 0, 0); }\n            to { transform: translate3d(0, 0, 0); }\n          }\n\n          /* Vertical up scroll */\n          @keyframes marquee-v-up-${uniqueId} {\n            from { transform: translate3d(0, 0, 0); }\n            to { transform: translate3d(0, calc(-100% - var(--marquee-gap)), 0); }\n          }\n\n          /* Vertical down scroll */\n          @keyframes marquee-v-down-${uniqueId} {\n            from { transform: translate3d(0, calc(-100% - var(--marquee-gap)), 0); }\n            to { transform: translate3d(0, 0, 0); }\n          }\n\n          .mask-horizontal {\n            mask-image: linear-gradient(to right, transparent, black 10%, black 90%, transparent);\n            -webkit-mask-image: linear-gradient(to right, transparent, black 10%, black 90%, transparent);\n          }\n\n          .mask-vertical {\n            mask-image: linear-gradient(to bottom, transparent, black 10%, black 90%, transparent);\n            -webkit-mask-image: linear-gradient(to bottom, transparent, black 10%, black 90%, transparent);\n          }\n        `}</style>\n\n        {/* Track 1 */}\n        <div\n          className={cn(\n            `marquee-inner-${uniqueId}`,\n            isVertical ? \"flex-col\" : \"flex-row\",\n          )}\n          aria-hidden=\"false\"\n        >\n          {children}\n        </div>\n\n        {/* Track 2 (Duplicate for seamless loop) */}\n        <div\n          className={cn(\n            `marquee-inner-${uniqueId}`,\n            isVertical ? \"flex-col\" : \"flex-row\",\n          )}\n          aria-hidden=\"true\"\n        >\n          {children}\n        </div>\n\n        {/* Track 3 (Guarantees zero-gap on reverse/rightward scroll and ultra-wide screens) */}\n        <div\n          className={cn(\n            `marquee-inner-${uniqueId}`,\n            isVertical ? \"flex-col\" : \"flex-row\",\n          )}\n          aria-hidden=\"true\"\n        >\n          {children}\n        </div>\n\n        {/* Track 4 (Guarantees zero-gap on reverse/rightward scroll and ultra-wide screens) */}\n        <div\n          className={cn(\n            `marquee-inner-${uniqueId}`,\n            isVertical ? \"flex-col\" : \"flex-row\",\n          )}\n          aria-hidden=\"true\"\n        >\n          {children}\n        </div>\n      </div>\n    );\n  },\n);\nMarqueeBlock.displayName = \"MarqueeBlock\";\n",
      "type": "registry:component",
      "target": "components/custom/blocks/MarqueeBlock.tsx"
    }
  ],
  "docs": "Duplicate the children set to keep the loop seamless; supports reverse and vertical orientations.",
  "categories": [
    "data-display"
  ],
  "type": "registry:component"
}
