forked from 77media/video-flow
63 lines
2.2 KiB
TypeScript
63 lines
2.2 KiB
TypeScript
import { useEffect, useMemo, useState } from 'react';
|
|
|
|
/**
|
|
* Renders a typewriter-style text that cycles through a list of strings.
|
|
* It types each string character-by-character, pauses, clears, then proceeds to the next.
|
|
* @param {string[]} strings - The list of sentences to cycle through.
|
|
* @param {{ typingMs?: number; pauseMs?: number; resetMs?: number }} [options] - Timing options.
|
|
* @returns {string} - The current text to display.
|
|
*/
|
|
export function useTypewriterText(
|
|
strings: string[],
|
|
options?: { typingMs?: number; pauseMs?: number; resetMs?: number }
|
|
): string {
|
|
const typingMs = options?.typingMs ?? 40;
|
|
const pauseMs = options?.pauseMs ?? 1200;
|
|
const resetMs = options?.resetMs ?? 300;
|
|
|
|
const [text, setText] = useState('');
|
|
const [listIndex, setListIndex] = useState(0);
|
|
const [charIndex, setCharIndex] = useState(0);
|
|
const [phase, setPhase] = useState<'typing' | 'pausing' | 'clearing'>('typing');
|
|
const key = useMemo(() => (strings && strings.length ? strings.join('|') : ''), [strings]);
|
|
|
|
useEffect(() => {
|
|
setText('');
|
|
setListIndex(0);
|
|
setCharIndex(0);
|
|
setPhase('typing');
|
|
}, [key]);
|
|
|
|
useEffect(() => {
|
|
const list = strings && strings.length ? strings : ['Describe the story you want to make...'];
|
|
const full = list[listIndex % list.length] ?? '';
|
|
let timer: number | undefined;
|
|
|
|
if (phase === 'typing') {
|
|
if (charIndex <= full.length) {
|
|
setText(full.slice(0, charIndex));
|
|
timer = window.setTimeout(() => setCharIndex(charIndex + 1), typingMs);
|
|
} else {
|
|
setPhase('pausing');
|
|
}
|
|
} else if (phase === 'pausing') {
|
|
timer = window.setTimeout(() => setPhase('clearing'), pauseMs);
|
|
} else {
|
|
setText('');
|
|
timer = window.setTimeout(() => {
|
|
setListIndex((listIndex + 1) % list.length);
|
|
setCharIndex(0);
|
|
setPhase('typing');
|
|
}, resetMs);
|
|
}
|
|
|
|
return () => {
|
|
if (timer) window.clearTimeout(timer);
|
|
};
|
|
}, [strings, listIndex, charIndex, phase, typingMs, pauseMs, resetMs]);
|
|
|
|
return text;
|
|
}
|
|
|
|
|