{
  "$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<Props> = ({\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      <h2 className=\"mt-10 text-3xl font-black text-black dark:text-neutral-100 py-5 pb-8 px-8 md:text-5xl\">\n        {text.split(\" \").map((word, index) => {\n          return (\n            <motion.span\n              ref={ref}\n              className=\"inline-block mr-[0.25em] whitespace-nowrap\"\n              aria-hidden=\"true\"\n              key={index}\n              initial=\"hidden\"\n              animate=\"visible\"\n              variants={container}\n              transition={{\n                delayChildren: index * 0.13,\n                // delayChildren: index * 0.35,\n                staggerChildren: 0.025,\n                // staggerChildren: 0.05,\n              }}\n            >\n              {word.split(\"\").map((character, index) => {\n                return (\n                  <motion.span\n                    aria-hidden=\"true\"\n                    key={index}\n                    variants={child}\n                    className=\"inline-block -mr-[0.01em]\"\n                  >\n                    {character}\n                  </motion.span>\n                )\n              })}\n            </motion.span>\n          )\n        })}\n      </h2>\n    )\n  }\n\n  return (\n    <motion.h2\n      style={{ display: \"flex\", overflow: \"hidden\" }}\n      role=\"heading\"\n      variants={container}\n      initial=\"hidden\"\n      animate=\"visible\"\n      className=\"mt-10 text-4xl font-black text-black dark:text-neutral-100 py-5 pb-8 px-8 md:text-5xl\"\n      {...props}\n    >\n      {letters.map((letter, index) => (\n        <motion.span key={index} variants={child}>\n          {letter === \" \" ? \"\\u00A0\" : letter}\n        </motion.span>\n      ))}\n    </motion.h2>\n  )\n}\n\nexport { TextAnimate }\nexport default TextAnimate\n",
      "type": "registry:ui"
    }
  ]
}