{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "ai-response-typing-shadcnui", "type": "registry:component", "title": "AI Response Typing Stream", "description": "Character-by-character typing animation with natural pauses and thinking states", "registryDependencies": [ "button" ], "dependencies": [ "framer-motion", "react" ], "files": [ { "path": "@uitripled/react-shadcn/src/components/motion-core/ai-response-typing.tsx", "content": "\"use client\";\n\nimport { motion } from \"framer-motion\";\nimport { useEffect, useRef, useState } from \"react\";\n\ntype AIResponseTypingProps = {\n text?: string;\n speed?: number;\n showCursor?: boolean;\n onComplete?: () => void;\n thinkingState?: \"idle\" | \"thinking\" | \"typing\";\n};\n\nexport function AIResponseTyping({\n text = \"Hello! I'm an AI assistant. I can help you with questions, provide information, and assist with various tasks. Feel free to ask me anything!\",\n speed = 30,\n showCursor = true,\n onComplete,\n thinkingState = \"typing\",\n}: AIResponseTypingProps) {\n const [displayedText, setDisplayedText] = useState(\"\");\n const [isThinking, setIsThinking] = useState(false);\n const [isTyping, setIsTyping] = useState(false);\n const intervalRef = useRef(null);\n\n useEffect(() => {\n if (thinkingState === \"thinking\") {\n setIsThinking(true);\n setIsTyping(false);\n setDisplayedText(\"\");\n return;\n }\n\n if (thinkingState === \"typing\" && text) {\n setIsThinking(false);\n setIsTyping(true);\n setDisplayedText(\"\");\n\n let currentIndex = 0;\n const chars = text.split(\"\");\n\n const typeNextChar = () => {\n if (currentIndex < chars.length) {\n const nextChar = chars[currentIndex];\n\n // Simulate natural typing pauses at punctuation\n const isPause =\n nextChar === \".\" ||\n nextChar === \",\" ||\n nextChar === \"!\" ||\n nextChar === \"?\" ||\n nextChar === \"\\n\";\n\n setDisplayedText((prev) => prev + nextChar);\n currentIndex++;\n\n // Schedule next character with pause if needed\n if (isPause) {\n intervalRef.current = setTimeout(() => {\n typeNextChar();\n }, speed * 3);\n } else {\n intervalRef.current = setTimeout(() => {\n typeNextChar();\n }, speed);\n }\n } else {\n if (intervalRef.current) clearTimeout(intervalRef.current);\n setIsTyping(false);\n onComplete?.();\n }\n };\n\n // Start typing\n typeNextChar();\n\n return () => {\n if (intervalRef.current) clearTimeout(intervalRef.current);\n };\n }\n }, [text, speed, thinkingState, onComplete]);\n\n return (\n
\n
\n {/* Thinking state shimmer */}\n {isThinking && (\n \n Thinking\n
\n {[0, 1, 2].map((i) => (\n \n ))}\n
\n \n )}\n\n {/* Typing output */}\n {displayedText && (\n \n {displayedText}\n {showCursor && isTyping && (\n \n )}\n {showCursor && !isTyping && !isThinking && displayedText && (\n \n )}\n \n )}\n\n {/* Shimmer effect overlay */}\n {(isTyping || isThinking) && (\n \n )}\n\n {/* Decorative gradient border */}\n {(isTyping || isThinking) && (\n
\n \n
\n )}\n
\n\n {/* Status indicator */}\n
\n
\n \n \n {isThinking\n ? \"AI is thinking...\"\n : isTyping\n ? \"AI is typing...\"\n : \"Ready\"}\n \n
\n
\n
\n );\n}\n", "type": "registry:component", "target": "components/uitripled/ai-response-typing-shadcnui.tsx" } ] }