{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tooltips-magnetic",
  "title": "Magnetic tooltips",
  "description": "Styled tooltips: the Magnetic set. 5 decorative tooltips variations (MagneticTooltip, FloatTooltip, TiltTooltip, SpotlightTooltip, ParallaxTooltip) on the ai2 token system, powered by framer-motion, reduced-motion aware and sized sm to xl. Part of the free styled layer.",
  "dependencies": [
    "motion@^12.42.2"
  ],
  "registryDependencies": [
    "@ai2/tokens"
  ],
  "files": [
    {
      "path": "registry/ai2/styled/tooltips-magnetic.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { motion, useMotionTemplate, useMotionValue, useReducedMotion, useSpring } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* Magnetic tooltip family: 5 bubbles on a cursor-physics theme. The position values\n   are held with useMotionValue + useSpring (no re-render). The bubble opacity opens\n   through CSS group-hover/group-focus-within, so it is visible on keyboard focus\n   even without a pointer. ALL pointer effects are disabled under reduced-motion.\n   Color comes ONLY from tokens. size = the bubble padding/text. children = the\n   trigger, content = the tooltip. */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\nconst bubbleSize: Record<StyledSize, string> = {\n  sm: \"px-2 py-1 text-xs\",\n  md: \"px-2.5 py-1.5 text-xs\",\n  lg: \"px-3 py-2 text-sm\",\n  xl: \"px-3.5 py-2.5 text-sm\",\n}\n\n/* The positioning is on a static outer layer; the inner motion layer leaves the\n   transform to framer. */\nconst positioner = \"pointer-events-none absolute bottom-full left-1/2 z-10 mb-2 -translate-x-1/2\"\nconst bubbleReveal =\n  \"block w-max max-w-56 rounded-lg font-medium opacity-0 shadow-md transition-opacity duration-(--motion-base) ease-(--motion-ease) group-hover:opacity-100 group-focus-within:opacity-100 motion-reduce:transition-none\"\n\ninterface Props {\n  size?: StyledSize\n  content: React.ReactNode\n  children: React.ReactNode\n  className?: string\n}\n\n/* Magnetic: balon imlec x'ine dogru yayli suruklenir. */\nexport function MagneticTooltip({ size = \"md\", content, children, className }: Props) {\n  const ref = React.useRef<HTMLSpanElement>(null)\n  const reduce = useReducedMotion()\n  const x = useMotionValue(0)\n  const sx = useSpring(x, { stiffness: 300, damping: 22 })\n\n  const onMove = (e: React.PointerEvent<HTMLSpanElement>) => {\n    if (reduce || !ref.current) return\n    const r = ref.current.getBoundingClientRect()\n    x.set((e.clientX - (r.left + r.width / 2)) * 0.25)\n  }\n  const reset = () => x.set(0)\n\n  return (\n    <span ref={ref} data-slot=\"styled-tooltip\" onPointerMove={onMove} onPointerLeave={reset} className=\"group relative inline-flex\">\n      {children}\n      <span className={positioner}>\n        <motion.span role=\"tooltip\" style={reduce ? undefined : { x: sx }} className={cn(bubbleReveal, bubbleSize[size], \"border border-border bg-popover text-popover-foreground\", className)}>\n          {content}\n        </motion.span>\n      </span>\n    </span>\n  )\n}\n\n/* Float: while open the bubble sways gently upward (static under reduced-motion). */\nexport function FloatTooltip({ size = \"md\", content, children, className }: Props) {\n  const reduce = useReducedMotion()\n  return (\n    <span data-slot=\"styled-tooltip\" className=\"group relative inline-flex\">\n      {children}\n      <span className={positioner}>\n        <motion.span\n          role=\"tooltip\"\n          animate={reduce ? undefined : { y: [0, -4, 0] }}\n          transition={reduce ? undefined : { duration: 2.4, repeat: Infinity, ease: \"easeInOut\" }}\n          className={cn(bubbleReveal, bubbleSize[size], \"border border-border bg-popover text-popover-foreground\", className)}\n        >\n          {content}\n        </motion.span>\n      </span>\n    </span>\n  )\n}\n\n/* Tilt: balon imlece gore 3B egilir. */\nexport function TiltTooltip({ size = \"md\", content, children, className }: Props) {\n  const ref = React.useRef<HTMLSpanElement>(null)\n  const reduce = useReducedMotion()\n  const rx = useMotionValue(0)\n  const ry = useMotionValue(0)\n  const srx = useSpring(rx, { stiffness: 300, damping: 20 })\n  const sry = useSpring(ry, { stiffness: 300, damping: 20 })\n\n  const onMove = (e: React.PointerEvent<HTMLSpanElement>) => {\n    if (reduce || !ref.current) return\n    const r = ref.current.getBoundingClientRect()\n    const px = (e.clientX - r.left) / r.width - 0.5\n    const py = (e.clientY - r.top) / r.height - 0.5\n    rx.set(py * -18)\n    ry.set(px * 18)\n  }\n  const reset = () => {\n    rx.set(0)\n    ry.set(0)\n  }\n\n  return (\n    <span ref={ref} data-slot=\"styled-tooltip\" onPointerMove={onMove} onPointerLeave={reset} className=\"group relative inline-flex\">\n      {children}\n      <span className={positioner}>\n        <motion.span\n          role=\"tooltip\"\n          style={reduce ? undefined : { rotateX: srx, rotateY: sry, transformPerspective: 500 }}\n          className={cn(bubbleReveal, bubbleSize[size], \"border border-border bg-popover text-popover-foreground\", className)}\n        >\n          {content}\n        </motion.span>\n      </span>\n    </span>\n  )\n}\n\n/* Spotlight: balondaki token isik lekesi imleci takip eder. */\nexport function SpotlightTooltip({ size = \"md\", content, children, className }: Props) {\n  const ref = React.useRef<HTMLSpanElement>(null)\n  const reduce = useReducedMotion()\n  const mx = useMotionValue(50)\n  const my = useMotionValue(50)\n  const spot = useMotionTemplate`radial-gradient(60px circle at ${mx}% ${my}%, color-mix(in oklab, var(--color-info) 40%, transparent), transparent 70%)`\n\n  const onMove = (e: React.PointerEvent<HTMLSpanElement>) => {\n    if (reduce || !ref.current) return\n    const r = ref.current.getBoundingClientRect()\n    mx.set(((e.clientX - r.left) / r.width) * 100)\n    my.set(((e.clientY - r.top) / r.height) * 100)\n  }\n\n  return (\n    <span ref={ref} data-slot=\"styled-tooltip\" onPointerMove={onMove} className=\"group relative inline-flex\">\n      {children}\n      <span className={positioner}>\n        <span\n          role=\"tooltip\"\n          className={cn(\n            \"relative block w-max max-w-56 overflow-hidden rounded-lg font-medium opacity-0 shadow-md transition-opacity duration-(--motion-base) ease-(--motion-ease) group-hover:opacity-100 group-focus-within:opacity-100 motion-reduce:transition-none\",\n            bubbleSize[size],\n            \"border border-border bg-popover text-popover-foreground\",\n            className\n          )}\n        >\n          <motion.span aria-hidden className=\"pointer-events-none absolute inset-0\" style={reduce ? undefined : { background: spot }} />\n          <span className=\"relative\">{content}</span>\n        </span>\n      </span>\n    </span>\n  )\n}\n\n/* Parallax: balon imlecin TERSINE kayar. */\nexport function ParallaxTooltip({ size = \"md\", content, children, className }: Props) {\n  const ref = React.useRef<HTMLSpanElement>(null)\n  const reduce = useReducedMotion()\n  const x = useMotionValue(0)\n  const y = useMotionValue(0)\n  const sx = useSpring(x, { stiffness: 260, damping: 24 })\n  const sy = useSpring(y, { stiffness: 260, damping: 24 })\n\n  const onMove = (e: React.PointerEvent<HTMLSpanElement>) => {\n    if (reduce || !ref.current) return\n    const r = ref.current.getBoundingClientRect()\n    x.set((e.clientX - (r.left + r.width / 2)) * -0.3)\n    y.set((e.clientY - (r.top + r.height / 2)) * -0.3)\n  }\n  const reset = () => {\n    x.set(0)\n    y.set(0)\n  }\n\n  return (\n    <span ref={ref} data-slot=\"styled-tooltip\" onPointerMove={onMove} onPointerLeave={reset} className=\"group relative inline-flex\">\n      {children}\n      <span className={positioner}>\n        <motion.span role=\"tooltip\" style={reduce ? undefined : { x: sx, y: sy }} className={cn(bubbleReveal, bubbleSize[size], \"border border-border bg-popover text-popover-foreground\", className)}>\n          {content}\n        </motion.span>\n      </span>\n    </span>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/tooltips-magnetic.tsx"
    }
  ],
  "categories": [
    "styled",
    "tooltips"
  ],
  "type": "registry:component"
}