import React from 'react'; import resolveClassName from '../../util/resolveClassName'; import classNames from './SplitFlapBoard.scss'; interface ISplitFlapBoardProps { /** Message the split flap board shall display */ message: string; /** True to start the animation */ start: boolean; /** Size of one split flap module, default of 40px */ size?: number; /** Duration of one transition animation */ duration?: number; } const SplitFlapBoard: React.FunctionComponent = ({ message, start, size, duration, }: ISplitFlapBoardProps) => { const classesMain = { name: 'split-flap', modifiers: [], }; const classesTopNext = { name: 'top-next', modifiers: [], }; const classesTopCurrent = { name: 'top-current', modifiers: ['stop', 'animate'], }; const classesBottomCurrent = { name: 'bottom-current', modifiers: [], }; const classesBottomNext = { name: 'bottom-next', modifiers: ['stop', 'animate'], }; const typeSet = [ ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', ]; const [animate, setAnimate] = React.useState(false); const currentCharacter = React.useRef(Array(message.length).fill(0)); const nextCharacter = React.useRef(Array(message.length).fill(1)); const flapStop = React.useRef(Array(message.length).fill(false)); const timeout = React.useRef(); const animation = () => { for (let i = 0; i < currentCharacter.current.length; i++) { if (typeSet[currentCharacter.current[i]] !== message.split('')[i]) { currentCharacter.current[i] = nextCharacter.current[i]; nextCharacter.current[i] = (nextCharacter.current[i] % 36) + 1; if (typeSet[currentCharacter.current[i]] === message.split('')[i]) { flapStop.current[i] = true; } } } setAnimate(false); if (!flapStop.current.reduce((acc, val) => acc && val)) { timeout.current = setTimeout(() => { setAnimate(true); timeout.current = setTimeout(animation, duration ? duration * 1000 : 2000); }, Math.max(25, Math.random() * 100)); } }; React.useEffect(() => { if (start) { setAnimate(true); timeout.current = setTimeout(animation, duration ? duration * 1000 : 2000); } }, [start]); //eslint-disable-line react-hooks/exhaustive-deps React.useEffect(() => { return () => clearTimeout(timeout.current); }, []); return (
{message.split('').map((char, index) => { return (
{/* TOP NEXT CHAR */}
{typeSet[nextCharacter.current[index]]}
{/* TOP CUR CHAR */}
{typeSet[currentCharacter.current[index]]}
{/* BOTTOM CUR CHAR */}
{typeSet[currentCharacter.current[index]]}
{/* BOTTOM NEXT CHAR */}
{typeSet[nextCharacter.current[index]]}
); })}
); }; export default SplitFlapBoard;