UNPKG

@erosnicolau/animated-text

Version:

Advanced React animated text component with comprehensive animation effects

150 lines (149 loc) 7.76 kB
import { jsx as _jsx } from "react/jsx-runtime"; import { DEFAULT_TIMING } from '../types'; import AnimatedPhrase from './AnimatedPhrase'; import AnimatedWord from './AnimatedWord'; import AnimatedLetter from './AnimatedLetter'; import AnimatedWordTypewriterWord from './AnimatedWordTypewriterWord'; import { sanitizeHtml, tokenizeLetters, tokenizePhrases, tokenizeWords, tokenizeWordTypewriter } from '../utils/textProcessing'; const ContentRenderer = ({ content, animation, allowHtml, phraseStyles, usePhrases, itemSpacing, wordEffect, wordDuration, wordEasing, wordStyles, typewriterEffect, typewriterDuration, typewriterEasing, wordTypewriterEffect, wordTypewriterDuration, wordTypewriterEasing, animatedItems, effectiveReplayKey, performanceModeActive, verticalAlign }) => { // Helper function to simplify effects for performance mode const getSimplifiedEffect = (effect) => { if (Array.isArray(effect)) { // For arrays, prefer fadeIn if available, otherwise take the first effect for (const e of effect) { if (e === 'fadeIn') return ['fadeIn']; } // Return the first effect if no fadeIn found if (effect.length > 0) { const firstEffect = effect[0]; if (typeof firstEffect === 'string') { return [firstEffect]; } } return ['fadeIn']; // Fallback } if (typeof effect === 'string') { // Allow fadeIn, fallback to fadeIn for other effects return effect === 'fadeIn' ? effect : 'fadeIn'; } // For object effects, always fallback to fadeIn return 'fadeIn'; }; // Optimize effects when performance mode is active const optimizedWordEffect = performanceModeActive ? getSimplifiedEffect(wordEffect) : wordEffect; const optimizedTypewriterEffect = performanceModeActive ? getSimplifiedEffect(typewriterEffect) : typewriterEffect; const optimizedWordTypewriterEffect = performanceModeActive ? getSimplifiedEffect(wordTypewriterEffect) : wordTypewriterEffect; const optimizedWordDuration = performanceModeActive ? Math.min(wordDuration, 300) : wordDuration; const optimizedTypewriterDuration = performanceModeActive ? Math.min(typewriterDuration, 300) : typewriterDuration; // Create timing defaults for animations const timingDefaults = { startDelay: DEFAULT_TIMING.startDelay, itemSpacing, defaultDuration: DEFAULT_TIMING.defaultDuration, defaultEffect: DEFAULT_TIMING.defaultEffect, defaultEasing: DEFAULT_TIMING.defaultEasing }; // Enhanced props - phrase-based styling with animations if ((phraseStyles || animation === 'phrases') && usePhrases) { let processedContent = content; if (allowHtml) { processedContent = sanitizeHtml(content); } const tokens = tokenizePhrases(processedContent); // Create default phrase styles if none provided but animation is 'phrases' const basePhraseStyles = phraseStyles || (animation === 'phrases' ? tokens .filter(t => t.type === 'phrase') .map((_, index) => ({ phrase: index + 1, effect: ['fadeIn', 'slide-up'], delayBefore: index * itemSpacing, duration: 600, easing: 'ease-out' })) : []); // Optimize phrase styles when performance mode is active const effectivePhraseStyles = performanceModeActive ? basePhraseStyles.map(style => ({ ...style, effect: getSimplifiedEffect(style.effect || ['fadeIn']), duration: Math.min(style.duration || 600, 300), delayBefore: Math.min(style.delayBefore || 0, 100) })) : basePhraseStyles; return tokens.map((token, index) => { if (token.type === 'phrase' && token.phraseIndex) { return (_jsx(AnimatedPhrase, { phraseIndex: token.phraseIndex, content: token.content, phraseStyles: effectivePhraseStyles, animatedItems: animatedItems, timingDefaults: timingDefaults, globalVerticalAlign: verticalAlign }, `${index}-${effectiveReplayKey}`)); } else if (token.type === 'html') { return _jsx("span", { dangerouslySetInnerHTML: { __html: token.content } }, index); } else { return _jsx("span", { children: token.content }, index); } }); } // Word sequence animation (word-by-word typewriter effect) if (animation === 'word') { let processedContent = content; if (allowHtml) { processedContent = sanitizeHtml(content); } const tokens = tokenizeWords(processedContent); return tokens.map((token, index) => { if (token.type === 'word' && token.wordIndex > 0) { // Find specific styling for this word const wordStyle = wordStyles?.find(style => style.word === token.wordIndex); return (_jsx(AnimatedWord, { wordIndex: token.wordIndex, content: token.content, effect: optimizedWordEffect, duration: optimizedWordDuration, easing: wordEasing, animatedItems: animatedItems, className: wordStyle?.className }, `${index}-${effectiveReplayKey}`)); } else { return (_jsx("span", { dangerouslySetInnerHTML: allowHtml ? { __html: token.content } : undefined, children: !allowHtml ? token.content : undefined }, index)); } }); } // Typewriter animation (letter-by-letter) if (animation === 'typewriter') { let processedContent = content; if (allowHtml) { processedContent = sanitizeHtml(content); } const tokens = tokenizeLetters(processedContent); return tokens.map((token, index) => { if (token.type === 'letter' && token.letterIndex > 0) { return (_jsx(AnimatedLetter, { letterIndex: token.letterIndex, content: token.content, effect: optimizedTypewriterEffect, duration: optimizedTypewriterDuration, easing: typewriterEasing, animatedItems: animatedItems }, `${index}-${effectiveReplayKey}`)); } else { return (_jsx("span", { dangerouslySetInnerHTML: allowHtml ? { __html: token.content } : undefined, children: !allowHtml ? token.content : undefined }, index)); } }); } // Word-typewriter animation (letter-by-letter with word pauses) if (animation === 'word-typewriter') { let processedContent = content; if (allowHtml) { processedContent = sanitizeHtml(content); } const tokens = tokenizeWordTypewriter(processedContent); return tokens.map((token, index) => { if (token.type === 'word') { return (_jsx(AnimatedWordTypewriterWord, { letters: token.letters, effect: optimizedWordTypewriterEffect, duration: wordTypewriterDuration, easing: wordTypewriterEasing, animatedItems: animatedItems }, `${index}-${effectiveReplayKey}`)); } else { // Space token return _jsx("span", { children: token.content }, index); } }); } // HTML support without styling if (allowHtml) { const sanitizedContent = sanitizeHtml(content); return _jsx("span", { dangerouslySetInnerHTML: { __html: sanitizedContent } }); } // Plain text fallback return content; }; export default ContentRenderer;