{
  "name": "type-writer",
  "type": "registry:component",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "type": "registry:component",
      "content": "\"use client\";\n\n/**\n * @author: @dorianbaffier\n * @description: Typewriter\n * @version: 1.0.0\n * @date: 2025-06-26\n * @license: MIT\n * @website: https://kokonutui.com\n * @github: https://github.com/kokonut-labs/kokonutui\n */\n\nimport { motion } from \"motion/react\";\nimport { useEffect, useRef, useState } from \"react\";\n\ntype TypewriterSequence = {\n  text: string;\n  deleteAfter?: boolean;\n  pauseAfter?: number;\n};\n\ntype TypewriterTitleProps = {\n  sequences?: TypewriterSequence[];\n  typingSpeed?: number;\n  startDelay?: number;\n  autoLoop?: boolean;\n  loopDelay?: number;\n  deleteSpeed?: number;\n  pauseBeforeDelete?: number;\n  naturalVariance?: boolean;\n};\n\nconst DEFAULT_SEQUENCES: TypewriterSequence[] = [\n  { text: \"Typewriter\", deleteAfter: true },\n  { text: \"Multiple Words\", deleteAfter: true },\n  { text: \"Auto Loop\", deleteAfter: false },\n];\n\nexport default function TypewriterTitle({\n  sequences = DEFAULT_SEQUENCES,\n  typingSpeed = 50,\n  startDelay = 200,\n  autoLoop = true,\n  loopDelay = 1000,\n  deleteSpeed = 30,\n  pauseBeforeDelete = 1000,\n  naturalVariance = true,\n}: TypewriterTitleProps) {\n  const [displayText, setDisplayText] = useState(\"\");\n  const sequenceIndexRef = useRef(0);\n  const charIndexRef = useRef(0);\n  const isDeletingRef = useRef(false);\n  const timeoutRef = useRef<NodeJS.Timeout | null>(null);\n\n  // Initialize with the sequences provided\n  const sequencesRef = useRef(sequences);\n  useEffect(() => {\n    sequencesRef.current = sequences;\n  }, [sequences]);\n\n  useEffect(() => {\n    const getTypingDelay = () => {\n      if (!naturalVariance) {\n        return typingSpeed;\n      }\n\n      // More natural human typing pattern\n      const random = Math.random();\n\n      // 10% chance of a longer pause (thinking/hesitation)\n      if (random < 0.1) {\n        return typingSpeed * 2;\n      }\n\n      // 10% chance of a burst (fast typing)\n      if (random > 0.9) {\n        return typingSpeed * 0.5;\n      }\n\n      // Standard variance (+/- 40%)\n      const variance = 0.4;\n      const min = typingSpeed * (1 - variance);\n      const max = typingSpeed * (1 + variance);\n      return Math.random() * (max - min) + min;\n    };\n\n    const runTypewriter = () => {\n      const currentSequence = sequencesRef.current[sequenceIndexRef.current];\n      if (!currentSequence) {\n        return;\n      }\n\n      if (isDeletingRef.current) {\n        if (charIndexRef.current > 0) {\n          charIndexRef.current -= 1;\n          setDisplayText(currentSequence.text.slice(0, charIndexRef.current));\n          timeoutRef.current = setTimeout(runTypewriter, deleteSpeed);\n        } else {\n          isDeletingRef.current = false;\n          const isLastSequence =\n            sequenceIndexRef.current === sequencesRef.current.length - 1;\n\n          if (isLastSequence && autoLoop) {\n            timeoutRef.current = setTimeout(() => {\n              sequenceIndexRef.current = 0;\n              runTypewriter();\n            }, loopDelay);\n          } else if (!isLastSequence) {\n            timeoutRef.current = setTimeout(() => {\n              sequenceIndexRef.current += 1;\n              runTypewriter();\n            }, 100); // Quick transition to next word\n          }\n        }\n      } else if (charIndexRef.current < currentSequence.text.length) {\n        charIndexRef.current += 1;\n        setDisplayText(currentSequence.text.slice(0, charIndexRef.current));\n        timeoutRef.current = setTimeout(runTypewriter, getTypingDelay());\n      } else {\n        const pauseDuration = currentSequence.pauseAfter ?? pauseBeforeDelete;\n\n        if (currentSequence.deleteAfter) {\n          timeoutRef.current = setTimeout(() => {\n            isDeletingRef.current = true;\n            runTypewriter();\n          }, pauseDuration);\n        } else {\n          const isLastSequence =\n            sequenceIndexRef.current === sequencesRef.current.length - 1;\n\n          if (isLastSequence && autoLoop) {\n            timeoutRef.current = setTimeout(() => {\n              sequenceIndexRef.current = 0;\n              charIndexRef.current = 0;\n              setDisplayText(\"\");\n              runTypewriter();\n            }, loopDelay);\n          } else if (!isLastSequence) {\n            timeoutRef.current = setTimeout(() => {\n              sequenceIndexRef.current += 1;\n              charIndexRef.current = 0;\n              setDisplayText(\"\");\n              runTypewriter();\n            }, pauseDuration);\n          }\n        }\n      }\n    };\n\n    // Start the loop\n    timeoutRef.current = setTimeout(runTypewriter, startDelay);\n\n    return () => {\n      if (timeoutRef.current) {\n        clearTimeout(timeoutRef.current);\n      }\n    };\n  }, [\n    // Only restart effect if timing configs change.\n    // We use sequencesRef for content to avoid restarting on array reference change.\n    typingSpeed,\n    deleteSpeed,\n    pauseBeforeDelete,\n    autoLoop,\n    loopDelay,\n    startDelay,\n    naturalVariance,\n  ]);\n\n  return (\n    <div className=\"relative mx-auto w-full max-w-4xl py-24\">\n      <div className=\"relative z-10 flex flex-col items-center justify-center text-center\">\n        <motion.div\n          animate={{ opacity: 1 }}\n          className=\"flex items-center gap-1 font-mono text-4xl text-black tracking-tight md:text-6xl dark:text-white\"\n          initial={{ opacity: 0 }}\n          transition={{ duration: 0.5 }}\n        >\n          <span className=\"inline-block min-h-[1.2em] min-w-[0.5em]\">\n            {displayText}\n          </span>\n          <motion.span\n            animate={{\n              opacity: [1, 1, 0, 0],\n            }}\n            className=\"inline-block h-[1em] w-[3px] bg-black dark:bg-white\"\n            transition={{\n              duration: 1,\n              repeat: Number.POSITIVE_INFINITY,\n              repeatType: \"loop\",\n              ease: \"linear\",\n            }}\n          />\n        </motion.div>\n      </div>\n    </div>\n  );\n}\n",
      "path": "/components/kokonutui/type-writer.tsx",
      "target": "components/kokonutui/type-writer.tsx"
    }
  ]
}