@gfazioli/mantine-text-animate
Version:
The TextAnimate component allows you to animate text with various effects.
147 lines (144 loc) • 4.44 kB
JavaScript
'use client';
import React, { useState, useEffect } from 'react';
import { createVarsResolver, getSize, polymorphicFactory, useProps, useStyles, Box, Text } from '@mantine/core';
import { NumberTicker } from './NumberTicker/NumberTicker.mjs';
import { Spinner } from './Spinner/Spinner.mjs';
import { TextTicker } from './TextTicker/TextTicker.mjs';
import { Typewriter } from './Typewriter/Typewriter.mjs';
import classes from './TextAnimate.module.css.mjs';
const defaultProps = {
delay: 0,
duration: 0.3,
segmentDelay: 0.05,
by: "word",
animation: "fade",
animateProps: {
translateDistance: "20",
scaleAmount: 2,
blurAmount: "10"
}
};
const defaultStaggerTimings = {
text: 0.06,
word: 0.05,
character: 0.03,
line: 0.06
};
const varsResolver = createVarsResolver(
(_, { animateProps: { translateDistance, blurAmount, scaleAmount } }) => ({
root: {
"--text-animate-translation-distance": translateDistance ? getSize(translateDistance, "translate-distance") : "20px",
"--text-animate-blur-amount": blurAmount ? getSize(blurAmount, "blur-amount") : "10px",
"--text-animate-scale-amount": scaleAmount ? scaleAmount.toString() : "0.8"
}
})
);
const TextAnimate = polymorphicFactory((_props, ref) => {
const props = useProps("TextAnimate", defaultProps, _props);
const {
delay,
duration,
segmentClassName,
animate,
by,
animation,
segmentDelay,
animateProps,
onAnimationStart,
onAnimationEnd,
classNames,
style,
styles,
unstyled,
vars,
children,
className,
...others
} = props;
const staggerTiming = segmentDelay !== void 0 ? segmentDelay : defaultStaggerTimings[by];
const [isInitialRender, setIsInitialRender] = useState(true);
useEffect(() => {
if (animate === "in") {
setIsInitialRender(false);
}
}, [animate]);
const containerStyles = {
whiteSpace: "pre-wrap",
position: "relative",
display: "block",
minHeight: "1em"
};
const getStyles = useStyles({
name: "TextAnimate",
props,
classes,
className,
style,
classNames,
styles,
unstyled,
vars,
varsResolver
});
if (animate === "none" || animate === false || animate === void 0) {
if (!isInitialRender) {
setIsInitialRender(true);
}
return /* @__PURE__ */ React.createElement(Box, { ref, ...getStyles("root"), style: containerStyles }, /* @__PURE__ */ React.createElement(Text, { component: "span", ...others, style: { visibility: "hidden" } }, children));
}
if (animate === "static") {
return /* @__PURE__ */ React.createElement(Box, { ref, ...getStyles("root"), style: containerStyles }, /* @__PURE__ */ React.createElement(Text, { component: "span", ...others }, children));
}
function handleOnAnimationStart() {
onAnimationStart?.(animate);
}
function handleOnAnimationEnd() {
onAnimationEnd?.(animate);
}
let segments = [];
switch (by) {
case "word":
segments = children.split(/(\s+)/);
break;
case "character":
segments = children.split("");
break;
case "line":
segments = children.split("\n");
break;
case "text":
default:
segments = [children];
break;
}
return /* @__PURE__ */ React.createElement(Box, { ref, ...getStyles("root", { style: containerStyles }) }, segments.map((segment, i) => /* @__PURE__ */ React.createElement(
Text,
{
"data-text-animate": animate,
"data-text-animate-animation": animation,
key: `${by}-${segment}-${delay}-${animate}-${duration}-${JSON.stringify(animateProps)}-${i}`,
...getStyles("segment", {
style: {
...by === "line" ? { display: "block", whiteSpace: "normal" } : {},
animationDelay: `${delay + i * staggerTiming}s`,
animationDuration: `${duration}s`,
animationFillMode: "forwards",
animationDirection: animate === "in" ? "normal" : "reverse"
}
}),
component: "span",
onAnimationStart: handleOnAnimationStart,
onAnimationEnd: handleOnAnimationEnd,
...others
},
segment
)));
});
TextAnimate.classes = classes;
TextAnimate.displayName = "TextAnimate";
TextAnimate.Typewriter = Typewriter;
TextAnimate.Spinner = Spinner;
TextAnimate.NumberTicker = NumberTicker;
TextAnimate.TextTicker = TextTicker;
export { TextAnimate };
//# sourceMappingURL=TextAnimate.mjs.map