{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "dynamic-text",
  "type": "registry:component",
  "title": "Dynamic Text",
  "description": "Rapidly cycles a phrase through a sequence with a slide transition (KokonutUI, MIT), bridged to contract tokens.",
  "dependencies": [
    "framer-motion"
  ],
  "registryDependencies": [
    "https://design.subconscious.ai/r/utils.json"
  ],
  "files": [
    {
      "path": "registry/components/dynamic-text.tsx",
      "type": "registry:component",
      "content": "\"use client\";\n\n/**\n * @author: @dorianbaffier\n * @description: Dynamic Text\n * @version: 1.0.0\n * @date: 2025-06-26\n * @license: MIT\n * @website: https://kokonutui.com\n * @github: https://github.com/kokonut-labs/kokonutui\n */\n\nimport { AnimatePresence, motion } from \"framer-motion\";\nimport { useEffect, useState } from \"react\";\n\ninterface Greeting {\n  text: string;\n  language: string;\n}\n\ninterface DynamicTextProps {\n  sequences?: string[];\n}\n\nconst greetings: Greeting[] = [\n  { text: \"Hello\", language: \"English\" },\n  { text: \"こんにちは\", language: \"Japanese\" },\n  { text: \"Bonjour\", language: \"French\" },\n  { text: \"Hola\", language: \"Spanish\" },\n  { text: \"안녕하세요\", language: \"Korean\" },\n  { text: \"Ciao\", language: \"Italian\" },\n  { text: \"Hallo\", language: \"German\" },\n  { text: \"こんにちは\", language: \"Japanese\" },\n];\n\nconst DEFAULT_SEQUENCES = greetings.map((g) => g.text);\n\nconst DynamicText = ({ sequences }: DynamicTextProps = {}) => {\n  const texts = sequences ?? DEFAULT_SEQUENCES;\n  const [currentIndex, setCurrentIndex] = useState(0);\n  const [isAnimating, setIsAnimating] = useState(true);\n\n  useEffect(() => {\n    if (!isAnimating) return;\n\n    const interval = setInterval(() => {\n      setCurrentIndex((prevIndex) => {\n        const nextIndex = prevIndex + 1;\n\n        if (nextIndex >= texts.length) {\n          clearInterval(interval);\n          setIsAnimating(false);\n          return prevIndex;\n        }\n\n        return nextIndex;\n      });\n    }, 300);\n\n    return () => clearInterval(interval);\n  }, [isAnimating, texts.length]);\n\n  // Animation variants for the text\n  const textVariants = {\n    hidden: { y: 20, opacity: 0 },\n    visible: { y: 0, opacity: 1 },\n    exit: { y: -100, opacity: 0 },\n  };\n\n  return (\n    <section\n      aria-label=\"Rapid greetings in different languages\"\n      className=\"flex items-center justify-center gap-1 p-4\"\n      style={{ minHeight: \"200px\" }}\n    >\n      <div className=\"relative flex h-16 w-60 items-center justify-center overflow-visible\">\n        {isAnimating ? (\n          <AnimatePresence mode=\"popLayout\">\n            <motion.div\n              animate={textVariants.visible}\n              aria-live=\"off\"\n              className=\"absolute flex items-center gap-2 font-medium text-2xl\"\n              exit={textVariants.exit}\n              initial={textVariants.hidden}\n              key={currentIndex}\n              style={{ color: \"var(--color)\" }}\n              transition={{ duration: 0.2, ease: \"easeOut\" }}\n            >\n              <div\n                aria-hidden=\"true\"\n                className=\"h-2 w-2 rounded-full\"\n                style={{ background: \"var(--color)\" }}\n              />\n              {texts[currentIndex]}\n            </motion.div>\n          </AnimatePresence>\n        ) : (\n          <div\n            className=\"flex items-center gap-2 font-medium text-2xl\"\n            style={{ color: \"var(--color)\" }}\n          >\n            <div\n              aria-hidden=\"true\"\n              className=\"h-2 w-2 rounded-full\"\n              style={{ background: \"var(--color)\" }}\n            />\n            {texts[currentIndex]}\n          </div>\n        )}\n      </div>\n    </section>\n  );\n};\n\nexport default DynamicText;\n"
    }
  ]
}
