{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"chat-conversation","type":"registry:component","title":"Chat Conversation","description":"Conversa que se escreve sozinha, com indicador de digitação, em loop.","author":"UI Catalog <https://ui.codehall.io>","dependencies":["motion"],"registryDependencies":[],"files":[{"path":"components/illustrations/chat-conversation.tsx","type":"registry:component","content":"'use client'\n\nimport { useEffect, useState } from 'react'\nimport { AnimatePresence, motion } from 'motion/react'\n\n// \"Chat Conversation\": mensagens aparecem em sequência com indicador de digitação; reinicia em loop.\nconst SCRIPT = [\n  { from: 'user', text: 'Consigo importar meus contatos do CSV?' },\n  { from: 'bot', text: 'Sim! Envie o arquivo e eu mapeio as colunas pra você.' },\n  { from: 'user', text: 'E as tags vêm junto?' },\n  { from: 'bot', text: 'Vêm. Já encontrei 3 colunas de tags e 1.284 contatos válidos.' },\n] as const\n\nexport default function ChatConversation() {\n  const [shown, setShown] = useState(0)\n  const [typing, setTyping] = useState(false)\n\n  useEffect(() => {\n    let cancelled = false\n    const run = async () => {\n      const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))\n      while (!cancelled) {\n        setShown(0)\n        await sleep(600)\n        for (let i = 0; i < SCRIPT.length; i++) {\n          if (cancelled) return\n          if (SCRIPT[i]!.from === 'bot') {\n            setTyping(true)\n            await sleep(1100)\n            setTyping(false)\n          }\n          setShown(i + 1)\n          await sleep(1300)\n        }\n        await sleep(2200)\n      }\n    }\n    void run()\n    return () => {\n      cancelled = true\n    }\n  }, [])\n\n  return (\n    <div className=\"flex h-[260px] w-[340px] flex-col justify-end gap-2 rounded-2xl border bg-card p-4 text-foreground\">\n      <AnimatePresence initial={false}>\n        {SCRIPT.slice(0, shown).map((m, i) => (\n          <motion.div\n            key={i}\n            initial={{ opacity: 0, y: 10, scale: 0.96 }}\n            animate={{ opacity: 1, y: 0, scale: 1 }}\n            exit={{ opacity: 0 }}\n            transition={{ type: 'spring', stiffness: 300, damping: 24 }}\n            className={m.from === 'user' ? 'self-end rounded-2xl rounded-br-sm bg-primary px-3 py-2 text-sm text-primary-foreground' : 'self-start rounded-2xl rounded-bl-sm bg-muted px-3 py-2 text-sm'}\n            style={{ maxWidth: '85%' }}\n          >\n            {m.text}\n          </motion.div>\n        ))}\n        {typing && (\n          <motion.div key=\"typing\" initial={{ opacity: 0, y: 6 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0 }} className=\"flex gap-1 self-start rounded-2xl rounded-bl-sm bg-muted px-3 py-2.5\">\n            {[0, 1, 2].map((i) => (\n              <motion.span key={i} className=\"size-1.5 rounded-full bg-muted-foreground\" animate={{ y: [0, -3, 0] }} transition={{ duration: 0.8, repeat: Infinity, delay: i * 0.15 }} />\n            ))}\n          </motion.div>\n        )}\n      </AnimatePresence>\n    </div>\n  )\n}\n"}]}