{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "primitives-texts-splitting",
  "title": "Splitting Text",
  "description": "A splitting text animation.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "@animate-ui/hooks-use-is-in-view"
  ],
  "files": [
    {
      "path": "registry/primitives/texts/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  type Transition,\n} from 'motion/react';\n\nimport {\n  useIsInView,\n  type UseIsInViewOptions,\n} from '@/hooks/use-is-in-view';\n\ntype DefaultSplittingTextProps = Omit<\n  HTMLMotionProps<'div'>,\n  'children' | 'initial' | 'animate' | 'transition'\n> & {\n  initial?: TargetAndTransition;\n  animate?: TargetAndTransition;\n  transition?: Transition;\n  stagger?: number;\n  delay?: number;\n  disableAnimation?: boolean;\n} & UseIsInViewOptions;\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 SplittingText: React.FC<SplittingTextProps> = ({\n  ref,\n  text,\n  type = 'chars',\n  initial = { x: 150, opacity: 0 },\n  animate = { x: 0, opacity: 1 },\n  transition = { duration: 0.7, ease: 'easeOut' },\n  stagger,\n  delay = 0,\n  inView = false,\n  inViewMargin = '0px',\n  inViewOnce = true,\n  disableAnimation = false,\n  ...props\n}) => {\n  const containerVariants: Variants = {\n    hidden: {},\n    visible: {\n      transition: {\n        delayChildren: delay / 1000,\n        staggerChildren:\n          stagger ?? (type === 'chars' ? 0.05 : type === 'words' ? 0.2 : 0.3),\n      },\n    },\n  };\n\n  const itemVariants: Variants = {\n    hidden: disableAnimation ? animate : initial,\n    visible: {\n      ...animate,\n      transition: disableAnimation ? { duration: 0 } : transition,\n    },\n  };\n\n  const { ref: localRef, isInView } = useIsInView(\n    ref as React.Ref<HTMLElement>,\n    {\n      inView,\n      inViewOnce,\n      inViewMargin,\n    },\n  );\n\n  if (Array.isArray(text)) {\n    return (\n      <motion.span\n        ref={localRef}\n        initial=\"hidden\"\n        animate={isInView ? 'visible' : 'hidden'}\n        variants={containerVariants}\n        {...props}\n      >\n        {text.map((line, i) => (\n          <React.Fragment key={`line-${i}`}>\n            <motion.span\n              variants={itemVariants}\n              style={{ display: 'inline-block' }}\n            >\n              {line}\n            </motion.span>\n            {i < text.length - 1 ? <br /> : null}\n          </React.Fragment>\n        ))}\n      </motion.span>\n    );\n  }\n\n  if (type === 'words') {\n    const tokens = (text as string).match(/\\S+\\s*/g) || [];\n    return (\n      <motion.span\n        ref={localRef}\n        initial=\"hidden\"\n        animate={isInView ? 'visible' : 'hidden'}\n        variants={containerVariants}\n        {...props}\n      >\n        {tokens.map((token, i) => (\n          <React.Fragment key={i}>\n            <motion.span\n              variants={itemVariants}\n              style={{ display: 'inline-block', whiteSpace: 'normal' }}\n            >\n              {token.trim()}\n            </motion.span>\n            {/\\s$/.test(token) ? ' ' : null}\n          </React.Fragment>\n        ))}\n      </motion.span>\n    );\n  }\n\n  const tokens = (text as string).split(/(\\s+)/);\n  const perChar = stagger ?? 0.05;\n  const baseDelaySec = (delay ?? 0) / 1000;\n\n  let globalIndex = 0;\n\n  return (\n    <motion.span\n      ref={localRef}\n      initial=\"hidden\"\n      animate={isInView ? 'visible' : 'hidden'}\n      variants={{\n        hidden: {},\n        visible: { transition: {} },\n      }}\n      {...props}\n    >\n      {tokens.map((tok, wi) => {\n        if (/^\\s+$/.test(tok)) {\n          return <span key={`space-${wi}`}>{tok}</span>;\n        }\n        const chars = Array.from(tok);\n        const wordDelay = baseDelaySec + perChar * globalIndex;\n        globalIndex += chars.length;\n\n        return (\n          <motion.span\n            key={`word-${wi}`}\n            style={{ display: 'inline-block', whiteSpace: 'nowrap' }}\n            variants={{}}\n            transition={{ delayChildren: wordDelay, staggerChildren: perChar }}\n            initial=\"hidden\"\n            animate={isInView ? 'visible' : 'hidden'}\n          >\n            {chars.map((ch, ci) => (\n              <motion.span\n                key={`ch-${wi}-${ci}`}\n                variants={itemVariants}\n                style={{ display: 'inline-block', whiteSpace: 'pre' }}\n              >\n                {ch}\n              </motion.span>\n            ))}\n          </motion.span>\n        );\n      })}\n    </motion.span>\n  );\n};\n\nexport { SplittingText, type SplittingTextProps };\n",
      "type": "registry:ui",
      "target": "components/animate-ui/primitives/texts/splitting.tsx"
    }
  ],
  "type": "registry:ui"
}