{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "text-modifier",
  "type": "registry:ui",
  "title": "Text Modifier",
  "description": "text highlighter with solid background and decorative markers for emphasis.",
  "author": "Ahdeetai <https://aditya.is-cool.dev>",
  "registryDependencies": [],
  "dependencies": ["motion"],
  "files": [
    {
      "type": "registry:ui",
      "path": "components/ui/text-modifier.tsx",
      "content": "'use client';\nimport React, { useRef, useEffect, useState } from 'react';\nimport { motion } from 'motion/react';\n\ninterface TextModifierProps extends React.HTMLAttributes<HTMLDivElement> {\n  highlightColorClass?: string;\n  markerColorClass?: string;\n  opacity?: number;\n  animationDuration?: number;\n  animationDelay?: number;\n  animate?: boolean;\n  triggerOnView?: boolean;\n  repeat?: boolean;\n  padding?: string;\n}\n\nconst TextModifier: React.FC<TextModifierProps> = ({\n  children,\n  highlightColorClass = 'bg-yellow-200',\n  markerColorClass = 'bg-yellow-500',\n  opacity = 0.8,\n  animationDuration = 0.6,\n  animationDelay = 0,\n  animate = true,\n  triggerOnView = true,\n  repeat = false,\n  padding = '0.125rem 0.375rem',\n  className,\n  ...props\n}) => {\n  const [isVisible, setIsVisible] = useState(!triggerOnView);\n  const textRef = useRef<HTMLSpanElement>(null);\n  const observerRef = useRef<IntersectionObserver | null>(null);\n\n  useEffect(() => {\n    if (!triggerOnView || !textRef.current) return;\n    observerRef.current = new IntersectionObserver(\n      ([entry]) => {\n        if (entry.isIntersecting) {\n          setIsVisible(true);\n          if (!repeat && observerRef.current) observerRef.current.disconnect();\n        } else if (repeat) setIsVisible(false);\n      },\n      { threshold: 0.1, rootMargin: '-50px' },\n    );\n    observerRef.current.observe(textRef.current);\n    return () => observerRef.current?.disconnect();\n  }, [triggerOnView, repeat]);\n\n  const shouldAnimate = animate && isVisible;\n  const markerSize = 8;\n\n  const renderMarkers = () => {\n    const lineLength = 25;\n    const offset = 4;\n    return (\n      <>\n        <motion.span\n          className='absolute'\n          style={{ top: '-9px', left: `-${offset}px` }}\n          initial={{ opacity: 0, y: -5 }}\n          animate={shouldAnimate ? { opacity: 1, y: 0 } : { opacity: 0, y: -5 }}\n          transition={{\n            duration: 0.3,\n            delay: animationDelay + animationDuration * 0.8,\n            ease: 'easeOut',\n          }}\n        >\n          <span\n            className={`block rounded-full ${markerColorClass}`}\n            style={{ width: `${markerSize}px`, height: `${markerSize}px` }}\n          />\n          <span\n            className={`block ${markerColorClass}`}\n            style={{\n              width: '2px',\n              height: `${lineLength}px`,\n              marginLeft: `${(markerSize - 2) / 2}px`,\n            }}\n          />\n        </motion.span>\n        <motion.span\n          className='absolute'\n          style={{ bottom: '-9px', right: `-${offset}px` }}\n          initial={{ opacity: 0, y: 5 }}\n          animate={shouldAnimate ? { opacity: 1, y: 0 } : { opacity: 0, y: 5 }}\n          transition={{\n            duration: 0.3,\n            delay: animationDelay + animationDuration,\n            ease: 'easeOut',\n          }}\n        >\n          <span\n            className={`block ${markerColorClass}`}\n            style={{\n              width: '2px',\n              height: `${lineLength}px`,\n              marginLeft: `${(markerSize - 2) / 2}px`,\n            }}\n          />\n          <span\n            className={`block rounded-full ${markerColorClass}`}\n            style={{ width: `${markerSize}px`, height: `${markerSize}px` }}\n          />\n        </motion.span>\n      </>\n    );\n  };\n\n  const textContent = (\n    <span ref={textRef} className={`relative ${className}`}>\n      {children}\n    </span>\n  );\n\n  const content = (\n    <span className='relative inline' style={{ padding }}>\n      <motion.span\n        className={`${highlightColorClass} rounded`}\n        style={{\n          opacity,\n          boxDecorationBreak: 'clone',\n          WebkitBoxDecorationBreak: 'clone',\n          padding: '0.125rem 0.25rem',\n          display: 'inline',\n        }}\n        initial={{ opacity: 0 }}\n        animate={shouldAnimate ? { opacity } : { opacity: 0 }}\n        transition={{\n          duration: animationDuration,\n          delay: animationDelay,\n          ease: 'easeOut',\n        }}\n      >\n        {textContent}\n      </motion.span>\n      {renderMarkers()}\n    </span>\n  );\n\n  return <div {...props}>{content}</div>;\n};\n\nexport default TextModifier;\n"
    }
  ]
}
