@datalayer/core
Version:
[](https://datalayer.io)
55 lines (54 loc) • 2.35 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/*
* Copyright (c) 2023-2025 Datalayer, Inc.
* Distributed under the terms of the Modified BSD License.
*/
import React, { useEffect } from 'react';
import clsx from 'clsx';
import { useTextRevealAnimationLines } from './useTextRevealAnimationLines';
import styles from './TextRevealAnimation.module.css';
export function TextRevealAnimation({ children, ...rest }) {
const [animationStarted, setAnimationStarted] = React.useState(false);
const [hasAnimationCompleted, setHasAnimationCompleted] = React.useState(false);
const { ref, lines } = useTextRevealAnimationLines(children.toString() || '');
const onLineAnimationEnd = (i) => {
if (lines && i === lines.length - 1) {
setHasAnimationCompleted(true);
}
};
useEffect(() => {
const el = ref.current;
const observer = new IntersectionObserver(entries => {
for (const entry of entries) {
if (entry.isIntersecting) {
setAnimationStarted(true);
if (el) {
observer.unobserve(el);
}
}
}
}, {
threshold: 1,
rootMargin: '0px 0px -10% 0px',
});
if (el) {
observer.observe(el);
}
return () => {
if (el) {
observer.unobserve(el);
}
};
}, [ref]);
if (typeof children !== 'string' &&
(process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test')) {
console.warn('Children passed to TextRevealAnimation must be a string');
return null;
}
return (_jsx("span", { ref: ref, ...rest, children: lines?.map((line, i) => (_jsxs(React.Fragment, { children: [_jsx("span", { className: clsx(styles.TextRevealAnimation, animationStarted && styles['TextRevealAnimation--visible'], animationStarted &&
(hasAnimationCompleted
? styles['TextRevealAnimation']
: styles['TextRevealAnimation--animated'])), style: {
'--animation-delay': `${220 + i * 200}ms`,
}, onAnimationEnd: () => onLineAnimationEnd(i), children: line }), ' '] }, line))) }));
}