fix: Emojis rendering in SplitText Animation (#7460)

This commit is contained in:
Sebastien Bruel 2025-05-20 22:26:58 +09:00 committed by GitHub
parent af96666ff4
commit e86842fd19
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 55 additions and 6 deletions

View file

@ -0,0 +1,38 @@
import { render } from '@testing-library/react';
import SplitText from './SplitText';
// Mock IntersectionObserver
class MockIntersectionObserver {
observe = jest.fn();
unobserve = jest.fn();
disconnect = jest.fn();
}
Object.defineProperty(window, 'IntersectionObserver', {
writable: true,
configurable: true,
value: MockIntersectionObserver,
});
describe('SplitText', () => {
it('renders emojis correctly', () => {
const emojis = ['🚧', '❤️‍🔥', '💜', '🦎', '❌', '✅', '⚠️'];
const originalText = emojis.join('');
const { container } = render(<SplitText text={originalText} />);
const textSpans = container.querySelectorAll('p > span > span.inline-block');
// Reconstruct the text by joining all span contents
const reconstructedText = Array.from(textSpans)
.map((span) => span.textContent)
.join('')
.trim();
// Compare the reconstructed text with the original
expect(reconstructedText).toBe(originalText);
// Check the first character specifically as the reconstructed text could hide issues
for (let i = 0; i < emojis.length; i++) {
expect(Array.from(textSpans)[i].textContent).toBe(emojis[i]);
}
});
});

View file

@ -15,6 +15,17 @@ interface SplitTextProps {
onLineCountChange?: (lineCount: number) => void;
}
const splitGraphemes = (text: string): string[] => {
if (typeof Intl !== 'undefined' && Intl.Segmenter) {
const segmenter = new Intl.Segmenter('en', { granularity: 'grapheme' });
const segments = segmenter.segment(text);
return Array.from(segments).map((s) => s.segment);
} else {
// Fallback for browsers without Intl.Segmenter
return [...text];
}
};
const SplitText: React.FC<SplitTextProps> = ({
text = '',
className = '',
@ -28,7 +39,7 @@ const SplitText: React.FC<SplitTextProps> = ({
onLetterAnimationComplete,
onLineCountChange,
}) => {
const words = text.split(' ').map((word) => word.split(''));
const words = text.split(' ').map(splitGraphemes);
const letters = words.flat();
const [inView, setInView] = useState(false);
const ref = useRef<HTMLParagraphElement>(null);
@ -40,12 +51,12 @@ const SplitText: React.FC<SplitTextProps> = ({
from: animationFrom,
to: inView
? async (next: (props: any) => Promise<void>) => {
await next(animationTo);
animatedCount.current += 1;
if (animatedCount.current === letters.length && onLetterAnimationComplete) {
onLetterAnimationComplete();
await next(animationTo);
animatedCount.current += 1;
if (animatedCount.current === letters.length && onLetterAnimationComplete) {
onLetterAnimationComplete();
}
}
}
: animationFrom,
delay: i * delay,
config: { easing },