{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "spinning-text",
  "type": "registry:ui",
  "title": "SpinningText",
  "description": "The `SpinningText` component is a dynamic and visually engaging UI element that animates text in a circular spinning motion. It is highly customizable, allowing you to control the animation's speed, direction, radius, and more.",
  "files": [
    {
      "path": "registry/sonaui/spinning-text/spinning-text.tsx",
      "type": "registry:ui",
      "content": "\"use client\";\n\nimport {\n  motion,\n  type Transition,\n  useReducedMotion,\n  type Variants,\n} from \"motion/react\";\nimport { type CSSProperties, useMemo } from \"react\";\n\nimport { cn } from \"@/lib/sona-utils\";\n\ntype SpinningTextProps = {\n  /** The text content to be animated. Can be a single string or an array of strings. */\n  children: string | string[];\n  /** Custom styles for the container. */\n  style?: CSSProperties;\n  /**\n   * Duration of the spinning animation in seconds.\n   * @default 10\n   */\n  duration?: number;\n  /** Additional CSS classes for the container. */\n  className?: string;\n  /**\n   * Reverses the spinning direction when set to `true`.\n   * @default false\n   */\n  reverse?: boolean;\n  /**\n   * Radius of the circular path in `ch` units.\n   * @default 5\n   */\n  radius?: number;\n  /** Custom transition settings for the animation. Merges with the default transition. */\n  transition?: Transition;\n  /** Custom animation variants for the container and individual characters. */\n  variants?: {\n    container?: Variants;\n    item?: Variants;\n  };\n};\n\nconst BASE_TRANSITION = {\n  repeat: Infinity,\n  ease: \"linear\" as const,\n};\n\nconst BASE_ITEM_VARIANTS = {\n  hidden: {\n    opacity: 1,\n  },\n  visible: {\n    opacity: 1,\n  },\n};\n\nexport default function SpinningText({\n  children,\n  duration = 10,\n  style,\n  className,\n  reverse = false,\n  radius = 5,\n  transition,\n  variants,\n}: SpinningTextProps) {\n  const shouldReduceMotion = useReducedMotion();\n\n  const textContent = useMemo(\n    () => (Array.isArray(children) ? children.join(\"\") : children),\n    [children],\n  );\n\n  const characters = useMemo(() => {\n    const chars = textContent.split(\"\");\n    chars.push(\" \");\n    return chars;\n  }, [textContent]);\n\n  const finalTransition = useMemo(\n    () => ({\n      ...BASE_TRANSITION,\n      ...transition,\n      duration: (transition as { duration?: number })?.duration ?? duration,\n    }),\n    [transition, duration],\n  );\n\n  const containerVariants = useMemo(\n    () => ({\n      // Reduced motion: hold the ring static instead of spinning forever.\n      visible: { rotate: shouldReduceMotion ? 0 : reverse ? -360 : 360 },\n      ...variants?.container,\n    }),\n    [reverse, variants, shouldReduceMotion],\n  );\n\n  const itemVariants = useMemo(\n    () => ({\n      ...BASE_ITEM_VARIANTS,\n      ...variants?.item,\n    }),\n    [variants],\n  );\n\n  return (\n    <motion.div\n      className={cn(\"relative\", className)}\n      // Give the ring an intrinsic footprint so it doesn't collapse to 0x0.\n      style={{\n        width: `${radius * 2 + 1}ch`,\n        height: `${radius * 2 + 1}ch`,\n        ...style,\n      }}\n      initial=\"hidden\"\n      animate=\"visible\"\n      variants={containerVariants}\n      transition={finalTransition}\n    >\n      {characters.map((char, index) => (\n        <motion.span\n          aria-hidden=\"true\"\n          // biome-ignore lint/suspicious/noArrayIndexKey: chars repeat; position is the identity\n          key={`${index}-${char}`}\n          variants={itemVariants}\n          className=\"inline-block absolute left-1/2 top-1/2\"\n          style={\n            {\n              \"--index\": index,\n              \"--total\": characters.length,\n              \"--radius\": radius,\n              transform: `\n              translate(-50%, -50%)\n              rotate(calc(360deg / var(--total) * var(--index)))\n              translateY(calc(var(--radius, 5) * -1ch))\n            `,\n              transformOrigin: \"center\",\n            } as React.CSSProperties\n          }\n        >\n          {char}\n        </motion.span>\n      ))}\n      <span className=\"sr-only\">{textContent}</span>\n    </motion.div>\n  );\n}\n",
      "target": "components/ui/spinning-text/spinning-text.tsx"
    }
  ],
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "@sona-ui/sona-utils"
  ]
}