File size: 1,160 Bytes
e7a5a81
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import { useEffect, useRef } from 'react';
import { motion, useInView, useAnimation } from 'framer-motion';

/* Splits text into individual chars, animates each on mount/scroll */
export default function SplitText({
  text = '',
  className = '',
  delay = 0,
  stagger = 0.04,
  from = { opacity: 0, y: 30 },
  to   = { opacity: 1, y: 0 },
}) {
  const ref     = useRef(null);
  const inView  = useInView(ref, { once: true, margin: '-50px' });
  const controls = useAnimation();

  useEffect(() => {
    if (inView) controls.start('visible');
  }, [inView, controls]);

  const chars = text.split('');

  return (
    <span ref={ref} className={`inline-block ${className}`} aria-label={text}>
      {chars.map((ch, i) => (
        <motion.span
          key={i}
          className="inline-block whitespace-pre"
          variants={{
            hidden:  from,
            visible: { ...to, transition: { duration: 0.5, delay: delay + i * stagger, ease: [0.25, 0.46, 0.45, 0.94] } },
          }}
          initial="hidden"
          animate={controls}
          aria-hidden="true"
        >
          {ch}
        </motion.span>
      ))}
    </span>
  );
}