UNPKG

@gfazioli/mantine-text-animate

Version:

The TextAnimate component allows you to animate text with various effects.

147 lines (144 loc) 4.44 kB
'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