{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "splitting-text",
  "type": "registry:ui",
  "title": "Splitting Text",
  "description": "A text component that dynamically simulates a splitting animation, progressively revealing characters as if typed in real-time.",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "registry/text/splitting/index.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport {\n  motion,\n  type Variants,\n  type TargetAndTransition,\n  type HTMLMotionProps,\n  useInView,\n  type UseInViewOptions,\n} from 'motion/react';\n\ntype DefaultSplittingTextProps = {\n  motionVariants?: {\n    initial?: Record<string, any>;\n    animate?: Record<string, any>;\n    transition?: Record<string, any>;\n    stagger?: number;\n  };\n  inView?: boolean;\n  inViewMargin?: UseInViewOptions['margin'];\n  inViewOnce?: boolean;\n  delay?: number;\n} & HTMLMotionProps<'div'>;\n\ntype CharsOrWordsSplittingTextProps = DefaultSplittingTextProps & {\n  type?: 'chars' | 'words';\n  text: string;\n};\n\ntype LinesSplittingTextProps = DefaultSplittingTextProps & {\n  type: 'lines';\n  text: string[];\n};\n\ntype SplittingTextProps =\n  | CharsOrWordsSplittingTextProps\n  | LinesSplittingTextProps;\n\nconst defaultItemVariant: Variants = {\n  hidden: { x: 150, opacity: 0 },\n  visible: {\n    x: 0,\n    opacity: 1,\n    transition: { duration: 0.7, ease: 'easeOut' },\n  },\n};\n\nexport const SplittingText: React.FC<SplittingTextProps> = ({\n  ref,\n  text,\n  type = 'chars',\n  motionVariants = {},\n  inView = false,\n  inViewMargin = '0px',\n  inViewOnce = true,\n  delay = 0,\n  ...props\n}) => {\n  const items = React.useMemo<React.ReactNode[]>(() => {\n    if (Array.isArray(text)) {\n      return text.flatMap((line, i) => [\n        <React.Fragment key={`line-${i}`}>{line}</React.Fragment>,\n        i < text.length - 1 ? <br key={`br-${i}`} /> : null,\n      ]);\n    }\n\n    if (type === 'words') {\n      const tokens = text.match(/\\S+\\s*/g) || [];\n      return tokens.map((token, i) => (\n        <React.Fragment key={i}>{token}</React.Fragment>\n      ));\n    }\n\n    return text\n      .split('')\n      .map((char, i) => <React.Fragment key={i}>{char}</React.Fragment>);\n  }, [text, type]);\n\n  const containerVariants: Variants = {\n    hidden: {},\n    visible: {\n      transition: {\n        delayChildren: delay / 1000,\n        staggerChildren:\n          motionVariants.stagger ??\n          (type === 'chars' ? 0.05 : type === 'words' ? 0.2 : 0.3),\n      },\n    },\n  };\n\n  const itemVariants: Variants = {\n    hidden: {\n      ...defaultItemVariant.hidden,\n      ...(motionVariants.initial || {}),\n    },\n    visible: {\n      ...defaultItemVariant.visible,\n      ...(motionVariants.animate || {}),\n      transition: {\n        ...((defaultItemVariant.visible as TargetAndTransition).transition ||\n          {}),\n        ...(motionVariants.transition || {}),\n      },\n    },\n  };\n\n  const localRef = React.useRef<HTMLDivElement>(null);\n  React.useImperativeHandle(ref, () => localRef.current as HTMLDivElement);\n\n  const inViewResult = useInView(localRef, {\n    once: inViewOnce,\n    margin: inViewMargin,\n  });\n  const isInView = !inView || inViewResult;\n\n  return (\n    <motion.span\n      ref={localRef}\n      initial=\"hidden\"\n      animate={isInView ? 'visible' : 'hidden'}\n      variants={containerVariants}\n      {...props}\n    >\n      {items.map(\n        (item, index) =>\n          item && (\n            <React.Fragment key={index}>\n              <motion.span\n                key={index}\n                variants={itemVariants}\n                style={{\n                  display: 'inline-block',\n                  whiteSpace:\n                    type === 'chars'\n                      ? 'pre'\n                      : Array.isArray(text)\n                        ? 'normal'\n                        : 'normal',\n                }}\n              >\n                {item}\n              </motion.span>\n              {type === 'words' && ' '}\n            </React.Fragment>\n          ),\n      )}\n    </motion.span>\n  );\n};\n",
      "type": "registry:ui",
      "target": "components/animate-ui/text/splitting.tsx"
    }
  ]
}