xlibs-components
Version:
Modern React component library with Aceternity, MagicUI, and ShadCN components for building beautiful web applications
298 lines (297 loc) • 8.98 kB
JavaScript
"use client";
import { jsx as _jsx } from "react/jsx-runtime";
import * as React from "react";
import { cn } from '../../lib/utils.js';
import { AnimatePresence, motion } from "motion/react";
const staggerTimings = {
text: 0.06,
word: 0.05,
character: 0.03,
line: 0.06,
};
const defaultContainerVariants = {
hidden: { opacity: 1 },
show: {
opacity: 1,
transition: {
delayChildren: 0,
staggerChildren: 0.05,
},
},
exit: {
opacity: 0,
transition: {
staggerChildren: 0.05,
staggerDirection: -1,
},
},
};
const defaultItemVariants = {
hidden: { opacity: 0 },
show: {
opacity: 1,
},
exit: {
opacity: 0,
},
};
const defaultItemAnimationVariants = {
fadeIn: {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0, y: 20 },
show: {
opacity: 1,
y: 0,
transition: {
duration: 0.3,
},
},
exit: {
opacity: 0,
y: 20,
transition: { duration: 0.3 },
},
},
},
blurIn: {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0, filter: "blur(10px)" },
show: {
opacity: 1,
filter: "blur(0px)",
transition: {
duration: 0.3,
},
},
exit: {
opacity: 0,
filter: "blur(10px)",
transition: { duration: 0.3 },
},
},
},
blurInUp: {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0, filter: "blur(10px)", y: 20 },
show: {
opacity: 1,
filter: "blur(0px)",
y: 0,
transition: {
y: { duration: 0.3 },
opacity: { duration: 0.4 },
filter: { duration: 0.3 },
},
},
exit: {
opacity: 0,
filter: "blur(10px)",
y: 20,
transition: {
y: { duration: 0.3 },
opacity: { duration: 0.4 },
filter: { duration: 0.3 },
},
},
},
},
blurInDown: {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0, filter: "blur(10px)", y: -20 },
show: {
opacity: 1,
filter: "blur(0px)",
y: 0,
transition: {
y: { duration: 0.3 },
opacity: { duration: 0.4 },
filter: { duration: 0.3 },
},
},
},
},
slideUp: {
container: defaultContainerVariants,
item: {
hidden: { y: 20, opacity: 0 },
show: {
y: 0,
opacity: 1,
transition: {
duration: 0.3,
},
},
exit: {
y: -20,
opacity: 0,
transition: {
duration: 0.3,
},
},
},
},
slideDown: {
container: defaultContainerVariants,
item: {
hidden: { y: -20, opacity: 0 },
show: {
y: 0,
opacity: 1,
transition: { duration: 0.3 },
},
exit: {
y: 20,
opacity: 0,
transition: { duration: 0.3 },
},
},
},
slideLeft: {
container: defaultContainerVariants,
item: {
hidden: { x: 20, opacity: 0 },
show: {
x: 0,
opacity: 1,
transition: { duration: 0.3 },
},
exit: {
x: -20,
opacity: 0,
transition: { duration: 0.3 },
},
},
},
slideRight: {
container: defaultContainerVariants,
item: {
hidden: { x: -20, opacity: 0 },
show: {
x: 0,
opacity: 1,
transition: { duration: 0.3 },
},
exit: {
x: 20,
opacity: 0,
transition: { duration: 0.3 },
},
},
},
scaleUp: {
container: defaultContainerVariants,
item: {
hidden: { scale: 0.5, opacity: 0 },
show: {
scale: 1,
opacity: 1,
transition: {
duration: 0.3,
scale: {
type: "spring",
damping: 15,
stiffness: 300,
},
},
},
exit: {
scale: 0.5,
opacity: 0,
transition: { duration: 0.3 },
},
},
},
scaleDown: {
container: defaultContainerVariants,
item: {
hidden: { scale: 1.5, opacity: 0 },
show: {
scale: 1,
opacity: 1,
transition: {
duration: 0.3,
scale: {
type: "spring",
damping: 15,
stiffness: 300,
},
},
},
exit: {
scale: 1.5,
opacity: 0,
transition: { duration: 0.3 },
},
},
},
};
const TextAnimateBase = ({ children, delay = 0, duration = 0.3, variants, className, segmentClassName, as: Component = "p", startOnView = true, once = false, by = "word", animation = "fadeIn", ...props }) => {
const MotionComponent = motion.create(Component);
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;
}
const finalVariants = variants
? {
container: {
hidden: { opacity: 0 },
show: {
opacity: 1,
transition: {
opacity: { duration: 0.01, delay },
delayChildren: delay,
staggerChildren: duration / segments.length,
},
},
exit: {
opacity: 0,
transition: {
staggerChildren: duration / segments.length,
staggerDirection: -1,
},
},
},
item: variants,
}
: animation
? {
container: {
...defaultItemAnimationVariants[animation].container,
show: {
...defaultItemAnimationVariants[animation].container.show,
transition: {
delayChildren: delay,
staggerChildren: duration / segments.length,
},
},
exit: {
...defaultItemAnimationVariants[animation].container.exit,
transition: {
staggerChildren: duration / segments.length,
staggerDirection: -1,
},
},
},
item: defaultItemAnimationVariants[animation].item,
}
: { container: defaultContainerVariants, item: defaultItemVariants };
return (_jsx(AnimatePresence, { mode: "popLayout", children: _jsx(MotionComponent, { variants: finalVariants.container, initial: "hidden", whileInView: startOnView ? "show" : undefined, animate: startOnView ? undefined : "show", exit: "exit", className: cn("whitespace-pre-wrap", className), viewport: { once }, ...props, children: segments.map((segment, i) => (_jsx(motion.span, { variants: finalVariants.item, custom: i * staggerTimings[by], className: cn(by === "line" ? "block" : "inline-block whitespace-pre", by === "character" && "", segmentClassName), children: segment }, `${by}-${segment}-${i}`))) }) }));
};
// Export the memoized version
export const TextAnimate = React.memo(TextAnimateBase);