{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "text-animate", "type": "registry:ui", "description": "Animated text component with customizable reveal effects and timing", "dependencies": [ "motion" ], "files": [ { "path": "registry/default/ui/text-animate.tsx", "content": "\"use client\"\n\nimport { FC, useEffect, useRef } from \"react\"\nimport { HTMLMotionProps, motion, useAnimation, useInView } from \"motion/react\"\n\ntype AnimationType =\n | \"fadeIn\"\n | \"fadeInUp\"\n | \"popIn\"\n | \"shiftInUp\"\n | \"rollIn\"\n | \"whipIn\"\n | \"whipInUp\"\n | \"calmInUp\"\n\ninterface Props extends HTMLMotionProps<\"div\"> {\n text: string\n type?: AnimationType\n delay?: number\n duration?: number\n}\n\nconst animationVariants = {\n fadeIn: {\n container: {\n hidden: { opacity: 0 },\n visible: (i: number = 1) => ({\n opacity: 1,\n transition: { staggerChildren: 0.05, delayChildren: i * 0.3 },\n }),\n },\n child: {\n visible: {\n opacity: 1,\n y: 0,\n transition: {\n type: \"spring\" as const,\n damping: 12,\n stiffness: 100,\n },\n },\n hidden: { opacity: 0, y: 10 },\n },\n },\n fadeInUp: {\n container: {\n hidden: { opacity: 0 },\n visible: {\n opacity: 1,\n transition: { staggerChildren: 0.1, delayChildren: 0.2 },\n },\n },\n child: {\n visible: { opacity: 1, y: 0, transition: { duration: 0.5 } },\n hidden: { opacity: 0, y: 20 },\n },\n },\n popIn: {\n container: {\n hidden: { scale: 0 },\n visible: {\n scale: 1,\n transition: { staggerChildren: 0.05, delayChildren: 0.2 },\n },\n },\n child: {\n visible: {\n opacity: 1,\n scale: 1.1,\n transition: { type: \"spring\" as const, damping: 15, stiffness: 400 },\n },\n hidden: { opacity: 0, scale: 0 },\n },\n },\n calmInUp: {\n container: {\n hidden: {},\n visible: (i: number = 1) => ({\n transition: { staggerChildren: 0.01, delayChildren: 0.2 * i },\n }),\n },\n child: {\n hidden: {\n y: \"200%\",\n transition: {\n ease: [0.455, 0.03, 0.515, 0.955] as const,\n duration: 0.85,\n },\n },\n visible: {\n y: 0,\n transition: {\n ease: [0.125, 0.92, 0.69, 0.975] as const, // Drawing attention to dynamic content or interactive elements, where the animation needs to be engaging but not abrupt\n duration: 0.75,\n // ease: [0.455, 0.03, 0.515, 0.955], // smooth and gradual acceleration followed by a steady deceleration towards the end of the animation\n // ease: [0.115, 0.955, 0.655, 0.939], // smooth and gradual acceleration followed by a steady deceleration towards the end of the animation\n // ease: [0.09, 0.88, 0.68, 0.98], // Very Gentle Onset, Swift Mid-Section, Soft Landing\n // ease: [0.11, 0.97, 0.64, 0.945], // Minimal Start, Energetic Acceleration, Smooth Closure\n },\n },\n },\n },\n shiftInUp: {\n container: {\n hidden: {},\n visible: (i: number = 1) => ({\n transition: { staggerChildren: 0.01, delayChildren: 0.2 * i },\n }),\n },\n child: {\n hidden: {\n y: \"100%\", // Starting from below but not too far to ensure a dramatic but manageable shift.\n transition: {\n ease: [0.75, 0, 0.25, 1] as const, // Starting quickly\n duration: 0.6, // Shortened duration for a more dramatic start\n },\n },\n visible: {\n y: 0,\n transition: {\n duration: 0.8, // Slightly longer to accommodate the slow middle and swift end\n ease: [0.22, 1, 0.36, 1] as const, // This easing function starts quickly (dramatic shift), slows down (slow middle), and ends quickly (clean swift end)\n },\n },\n },\n },\n\n whipInUp: {\n container: {\n hidden: {},\n visible: (i: number = 1) => ({\n transition: { staggerChildren: 0.01, delayChildren: 0.2 * i },\n }),\n },\n child: {\n hidden: {\n y: \"200%\",\n transition: {\n ease: [0.455, 0.03, 0.515, 0.955] as const,\n duration: 0.45,\n },\n },\n visible: {\n y: 0,\n transition: {\n ease: [0.5, -0.15, 0.25, 1.05] as const,\n duration: 0.75,\n },\n },\n },\n },\n rollIn: {\n container: {\n hidden: {},\n visible: {},\n },\n child: {\n hidden: {\n opacity: 0,\n y: `0.25em`,\n },\n visible: {\n opacity: 1,\n y: `0em`,\n transition: {\n duration: 0.65,\n ease: [0.65, 0, 0.75, 1] as const, // Great! Swift Beginning, Prolonged Ease, Quick Finish\n // ease: [0.75, 0.05, 0.85, 1], // Quick Start, Smooth Middle, Sharp End\n // ease: [0.7, -0.25, 0.9, 1.25], // Fast Acceleration, Gentle Slowdown, Sudden Snap\n // ease: [0.7, -0.5, 0.85, 1.5], // Quick Leap, Soft Glide, Snappy Closure\n },\n },\n },\n },\n whipIn: {\n container: {\n hidden: {},\n visible: {},\n },\n child: {\n hidden: {\n opacity: 0,\n y: `0.35em`,\n },\n visible: {\n opacity: 1,\n y: `0em`,\n transition: {\n duration: 0.45,\n // ease: [0.75, 0.05, 0.85, 1], // Quick Start, Smooth Middle, Sharp End\n // ease: [0.7, -0.25, 0.9, 1.25], // Fast Acceleration, Gentle Slowdown, Sudden Snap\n // ease: [0.65, 0, 0.75, 1], // Great! Swift Beginning, Prolonged Ease, Quick Finish\n ease: [0.85, 0.1, 0.9, 1.2] as const, // Rapid Initiation, Subtle Slow, Sharp Conclusion\n },\n },\n },\n },\n}\n\nconst TextAnimate: FC = ({\n text,\n type = \"whipInUp\",\n ...props\n}: Props) => {\n // const { ref, inView } = useInView({\n // threshold: 0.5,\n // triggerOnce: true,\n // });\n\n const ref = useRef(null)\n const isInView = useInView(ref, { once: true })\n\n const letters = Array.from(text)\n const { container, child } = animationVariants[type]\n\n const ctrls = useAnimation()\n\n // useEffect(() => {\n // if (isInView) {\n // ctrls.start(\"visible\");\n // }\n // if (!isInView) {\n // ctrls.start(\"hidden\");\n // }\n // }, [ctrls, isInView]);\n\n if (type === \"rollIn\" || type === \"whipIn\") {\n return (\n

\n {text.split(\" \").map((word, index) => {\n return (\n \n {word.split(\"\").map((character, index) => {\n return (\n \n {character}\n \n )\n })}\n \n )\n })}\n

\n )\n }\n\n return (\n \n {letters.map((letter, index) => (\n \n {letter === \" \" ? \"\\u00A0\" : letter}\n \n ))}\n \n )\n}\n\nexport { TextAnimate }\nexport default TextAnimate\n", "type": "registry:ui" } ] }