{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "text-animate",
  "type": "registry:ui",
  "title": "Text Animate",
  "description": "A text animation component that animates text using a variety of different animations.",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "registry/magicui/text-animate.tsx",
      "content": "\"use client\"\n\nimport { memo } from \"react\"\nimport {\n  AnimatePresence,\n  motion,\n  Variants,\n  type DOMMotionComponents,\n  type MotionProps,\n} from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype AnimationType = \"text\" | \"word\" | \"character\" | \"line\"\ntype AnimationVariant =\n  | \"fadeIn\"\n  | \"blurIn\"\n  | \"blurInUp\"\n  | \"blurInDown\"\n  | \"slideUp\"\n  | \"slideDown\"\n  | \"slideLeft\"\n  | \"slideRight\"\n  | \"scaleUp\"\n  | \"scaleDown\"\n\nconst motionElements = {\n  article: motion.article,\n  div: motion.div,\n  h1: motion.h1,\n  h2: motion.h2,\n  h3: motion.h3,\n  h4: motion.h4,\n  h5: motion.h5,\n  h6: motion.h6,\n  li: motion.li,\n  p: motion.p,\n  section: motion.section,\n  span: motion.span,\n} as const\n\ntype MotionElementType = Extract<\n  keyof DOMMotionComponents,\n  keyof typeof motionElements\n>\n\ninterface TextAnimateProps extends Omit<MotionProps, \"children\"> {\n  /**\n   * The text content to animate\n   */\n  children: string\n  /**\n   * The class name to be applied to the component\n   */\n  className?: string\n  /**\n   * The class name to be applied to each segment\n   */\n  segmentClassName?: string\n  /**\n   * The delay before the animation starts\n   */\n  delay?: number\n  /**\n   * The duration of the animation\n   */\n  duration?: number\n  /**\n   * Custom motion variants for the animation\n   */\n  variants?: Variants\n  /**\n   * The element type to render\n   */\n  as?: MotionElementType\n  /**\n   * How to split the text (\"text\", \"word\", \"character\")\n   */\n  by?: AnimationType\n  /**\n   * Whether to start animation when component enters viewport\n   */\n  startOnView?: boolean\n  /**\n   * Whether to animate only once\n   */\n  once?: boolean\n  /**\n   * The animation preset to use\n   */\n  animation?: AnimationVariant\n  /**\n   * Whether to enable accessibility features (default: true)\n   */\n  accessible?: boolean\n}\n\nconst staggerTimings: Record<AnimationType, number> = {\n  text: 0.06,\n  word: 0.05,\n  character: 0.03,\n  line: 0.06,\n}\n\nconst defaultContainerVariants = {\n  hidden: { opacity: 1 },\n  show: {\n    opacity: 1,\n    transition: {\n      delayChildren: 0,\n      staggerChildren: 0.05,\n    },\n  },\n  exit: {\n    opacity: 0,\n    transition: {\n      staggerChildren: 0.05,\n      staggerDirection: -1,\n    },\n  },\n}\n\nconst defaultItemVariants: Variants = {\n  hidden: { opacity: 0 },\n  show: {\n    opacity: 1,\n  },\n  exit: {\n    opacity: 0,\n  },\n}\n\nconst defaultItemAnimationVariants: Record<\n  AnimationVariant,\n  { container: Variants; item: Variants }\n> = {\n  fadeIn: {\n    container: defaultContainerVariants,\n    item: {\n      hidden: { opacity: 0, y: 20 },\n      show: {\n        opacity: 1,\n        y: 0,\n        transition: {\n          duration: 0.3,\n        },\n      },\n      exit: {\n        opacity: 0,\n        y: 20,\n        transition: { duration: 0.3 },\n      },\n    },\n  },\n  blurIn: {\n    container: defaultContainerVariants,\n    item: {\n      hidden: { opacity: 0, filter: \"blur(10px)\" },\n      show: {\n        opacity: 1,\n        filter: \"blur(0px)\",\n        transition: {\n          duration: 0.3,\n        },\n      },\n      exit: {\n        opacity: 0,\n        filter: \"blur(10px)\",\n        transition: { duration: 0.3 },\n      },\n    },\n  },\n  blurInUp: {\n    container: defaultContainerVariants,\n    item: {\n      hidden: { opacity: 0, filter: \"blur(10px)\", y: 20 },\n      show: {\n        opacity: 1,\n        filter: \"blur(0px)\",\n        y: 0,\n        transition: {\n          y: { duration: 0.3 },\n          opacity: { duration: 0.4 },\n          filter: { duration: 0.3 },\n        },\n      },\n      exit: {\n        opacity: 0,\n        filter: \"blur(10px)\",\n        y: 20,\n        transition: {\n          y: { duration: 0.3 },\n          opacity: { duration: 0.4 },\n          filter: { duration: 0.3 },\n        },\n      },\n    },\n  },\n  blurInDown: {\n    container: defaultContainerVariants,\n    item: {\n      hidden: { opacity: 0, filter: \"blur(10px)\", y: -20 },\n      show: {\n        opacity: 1,\n        filter: \"blur(0px)\",\n        y: 0,\n        transition: {\n          y: { duration: 0.3 },\n          opacity: { duration: 0.4 },\n          filter: { duration: 0.3 },\n        },\n      },\n    },\n  },\n  slideUp: {\n    container: defaultContainerVariants,\n    item: {\n      hidden: { y: 20, opacity: 0 },\n      show: {\n        y: 0,\n        opacity: 1,\n        transition: {\n          duration: 0.3,\n        },\n      },\n      exit: {\n        y: -20,\n        opacity: 0,\n        transition: {\n          duration: 0.3,\n        },\n      },\n    },\n  },\n  slideDown: {\n    container: defaultContainerVariants,\n    item: {\n      hidden: { y: -20, opacity: 0 },\n      show: {\n        y: 0,\n        opacity: 1,\n        transition: { duration: 0.3 },\n      },\n      exit: {\n        y: 20,\n        opacity: 0,\n        transition: { duration: 0.3 },\n      },\n    },\n  },\n  slideLeft: {\n    container: defaultContainerVariants,\n    item: {\n      hidden: { x: 20, opacity: 0 },\n      show: {\n        x: 0,\n        opacity: 1,\n        transition: { duration: 0.3 },\n      },\n      exit: {\n        x: -20,\n        opacity: 0,\n        transition: { duration: 0.3 },\n      },\n    },\n  },\n  slideRight: {\n    container: defaultContainerVariants,\n    item: {\n      hidden: { x: -20, opacity: 0 },\n      show: {\n        x: 0,\n        opacity: 1,\n        transition: { duration: 0.3 },\n      },\n      exit: {\n        x: 20,\n        opacity: 0,\n        transition: { duration: 0.3 },\n      },\n    },\n  },\n  scaleUp: {\n    container: defaultContainerVariants,\n    item: {\n      hidden: { scale: 0.5, opacity: 0 },\n      show: {\n        scale: 1,\n        opacity: 1,\n        transition: {\n          duration: 0.3,\n          scale: {\n            type: \"spring\",\n            damping: 15,\n            stiffness: 300,\n          },\n        },\n      },\n      exit: {\n        scale: 0.5,\n        opacity: 0,\n        transition: { duration: 0.3 },\n      },\n    },\n  },\n  scaleDown: {\n    container: defaultContainerVariants,\n    item: {\n      hidden: { scale: 1.5, opacity: 0 },\n      show: {\n        scale: 1,\n        opacity: 1,\n        transition: {\n          duration: 0.3,\n          scale: {\n            type: \"spring\",\n            damping: 15,\n            stiffness: 300,\n          },\n        },\n      },\n      exit: {\n        scale: 1.5,\n        opacity: 0,\n        transition: { duration: 0.3 },\n      },\n    },\n  },\n}\n\nconst TextAnimateBase = ({\n  children,\n  delay = 0,\n  duration = 0.3,\n  variants,\n  className,\n  segmentClassName,\n  as: Component = \"p\",\n  startOnView = true,\n  once = false,\n  by = \"word\",\n  animation = \"fadeIn\",\n  accessible = true,\n  ...props\n}: TextAnimateProps) => {\n  const MotionComponent = motionElements[Component]\n\n  let segments: string[] = []\n  switch (by) {\n    case \"word\":\n      segments = children.split(/(\\s+)/)\n      break\n    case \"character\":\n      segments = children.split(\"\")\n      break\n    case \"line\":\n      segments = children.split(\"\\n\")\n      break\n    case \"text\":\n    default:\n      segments = [children]\n      break\n  }\n\n  const finalVariants = variants\n    ? {\n        container: {\n          hidden: { opacity: 0 },\n          show: {\n            opacity: 1,\n            transition: {\n              opacity: { duration: 0.01, delay },\n              delayChildren: delay,\n              staggerChildren: duration / segments.length,\n            },\n          },\n          exit: {\n            opacity: 0,\n            transition: {\n              staggerChildren: duration / segments.length,\n              staggerDirection: -1,\n            },\n          },\n        },\n        item: variants,\n      }\n    : animation\n      ? {\n          container: {\n            ...defaultItemAnimationVariants[animation].container,\n            show: {\n              ...defaultItemAnimationVariants[animation].container.show,\n              transition: {\n                delayChildren: delay,\n                staggerChildren: duration / segments.length,\n              },\n            },\n            exit: {\n              ...defaultItemAnimationVariants[animation].container.exit,\n              transition: {\n                staggerChildren: duration / segments.length,\n                staggerDirection: -1,\n              },\n            },\n          },\n          item: defaultItemAnimationVariants[animation].item,\n        }\n      : { container: defaultContainerVariants, item: defaultItemVariants }\n\n  return (\n    <AnimatePresence mode=\"popLayout\">\n      <MotionComponent\n        variants={finalVariants.container as Variants}\n        initial=\"hidden\"\n        whileInView={startOnView ? \"show\" : undefined}\n        animate={startOnView ? undefined : \"show\"}\n        exit=\"exit\"\n        className={cn(\"whitespace-pre-wrap\", className)}\n        viewport={{ once }}\n        aria-label={accessible ? children : undefined}\n        {...props}\n      >\n        {accessible && <span className=\"sr-only\">{children}</span>}\n        {segments.map((segment, i) => (\n          <motion.span\n            key={`${by}-${segment}-${i}`}\n            variants={finalVariants.item}\n            custom={i * staggerTimings[by]}\n            className={cn(\n              by === \"line\" ? \"block\" : \"inline-block whitespace-pre\",\n              by === \"character\" && \"\",\n              segmentClassName\n            )}\n            aria-hidden={accessible ? true : undefined}\n          >\n            {segment}\n          </motion.span>\n        ))}\n      </MotionComponent>\n    </AnimatePresence>\n  )\n}\n\n// Export the memoized version\nexport const TextAnimate = memo(TextAnimateBase)\n",
      "type": "registry:ui"
    }
  ]
}