"use client"; import { useEffect, useRef, useState } from "react"; /** * Cycles through `words` with a typewriter effect. * @param words - Must be referentially stable (define outside component or wrap in useMemo). * @param typingSpeed - ms per character while typing (default 80) * @param deletingSpeed - ms per character while deleting (default 40) * @param pauseMs - ms to pause after a full word is typed (default 2000) * @returns The currently displayed string */ export function useTypewriter(words: string[], typingSpeed = 80, deletingSpeed = 40, pauseMs = 2000) { const [displayed, setDisplayed] = useState(""); const [wordIndex, setWordIndex] = useState(0); const [isDeleting, setIsDeleting] = useState(false); const pauseRef = useRef | null>(null); useEffect(() => { if (!words.length) return; const current = words[wordIndex % words.length]; const timeout = setTimeout(() => { if (!isDeleting) { setDisplayed(current.slice(0, displayed.length + 1)); if (displayed.length + 1 === current.length) { pauseRef.current = setTimeout(() => setIsDeleting(true), pauseMs); } } else { setDisplayed(current.slice(0, displayed.length - 1)); if (displayed.length - 1 === 0) { setIsDeleting(false); setWordIndex((i) => i + 1); } } }, isDeleting ? deletingSpeed : typingSpeed); return () => { clearTimeout(timeout); if (pauseRef.current) clearTimeout(pauseRef.current); }; }, [displayed, isDeleting, wordIndex, words, typingSpeed, deletingSpeed, pauseMs]); return displayed; }