ComponentsAboutContactPrivacyTerms

Built by Lacy Morrow

    Close file
    Close file
    Close file
    Close file
    'use client';
    import {
      motion,
      VariantLabels,
      Target,
      TargetAndTransition,
      Transition,
    } from 'motion/react';
    
    export type TextRollProps = {
      children: string;
      duration?: number;
      getEnterDelay?: (index: number) => number;
      getExitDelay?: (index: number) => number;
      className?: string;
      transition?: Transition;
      variants?: {
        enter: {
          initial: Target | VariantLabels | boolean;
          animate: TargetAndTransition | VariantLabels;
        };
        exit: {
          initial: Target | VariantLabels | boolean;
          animate: TargetAndTransition | VariantLabels;
        };
      };
      onAnimationComplete?: () => void;
    };
    
    export function TextRoll({
      children,
      duration = 0.5,
      getEnterDelay = (i) => i * 0.1,
      getExitDelay = (i) => i * 0.1 + 0.2,
      className,
      transition = { ease: 'easeIn' },
      variants,
      onAnimationComplete,
    }: TextRollProps) {
      const defaultVariants = {
        enter: {
          initial: { rotateX: 0 },
          animate: { rotateX: 90 },
        },
        exit: {
          initial: { rotateX: 90 },
          animate: { rotateX: 0 },
        },
      } as const;
    
      const letters = children.split('');
    
      return (
        <span className={className}>
          {letters.map((letter, i) => {
            return (
              <span
                key={i}
                className='relative inline-block [perspective:10000px] [transform-style:preserve-3d] [width:auto]'
                aria-hidden='true'
              >
                <motion.span
                  className='absolute inline-block [backface-visibility:hidden] [transform-origin:50%_25%]'
                  initial={
                    variants?.enter?.initial ?? defaultVariants.enter.initial
                  }
                  animate={
                    variants?.enter?.animate ?? defaultVariants.enter.animate
                  }
                  transition={{
                    ...transition,
                    duration,
                    delay: getEnterDelay(i),
                  }}
                >
                  {letter === ' ' ? '\u00A0' : letter}
                </motion.span>
                <motion.span
                  className='absolute inline-block [backface-visibility:hidden] [transform-origin:50%_100%]'
                  initial={variants?.exit?.initial ?? defaultVariants.exit.initial}
                  animate={variants?.exit?.animate ?? defaultVariants.exit.animate}
                  transition={{
                    ...transition,
                    duration,
                    delay: getExitDelay(i),
                  }}
                  onAnimationComplete={
                    letters.length === i + 1 ? onAnimationComplete : undefined
                  }
                >
                  {letter === ' ' ? '\u00A0' : letter}
                </motion.span>
                <span className='invisible'>
                  {letter === ' ' ? '\u00A0' : letter}
                </span>
              </span>
            );
          })}
          <span className='sr-only'>{children}</span>
        </span>
      );
    }