'use client'; import { forwardRef, useState, FormEvent, KeyboardEvent, HTMLAttributes } from 'react'; export type TransformType = 'none' | 'reverse' | 'glitch' | 'repeat' | 'scramble'; export interface EchoChatProps extends HTMLAttributes { /** Accent color */ accentColor?: string; /** Echo color for responses */ echoColor?: string; /** Maximum messages to display */ maxMessages?: number; /** Color variant */ variant?: 'default' | 'cyber' | 'terminal' | 'fire' | 'nuclear'; /** Size variant */ size?: 'default' | 'compact' | 'large'; /** Default transform type */ defaultTransform?: TransformType; /** Show transform selector */ showTransformSelector?: boolean; /** Placeholder text */ placeholder?: string; /** Send button text */ sendButtonText?: string; /** On message send callback */ onSend?: (message: string, transform: TransformType) => void; /** Custom echo function */ echoFunction?: (message: string, transform: TransformType) => string; } const DEFAULT_ECHO: Record string> = { none: (text) => text, reverse: (text) => text.split('').reverse().join(''), glitch: (text) => { const chars = '!<>-_\\/[]{}'; return text .split('') .map((char) => (Math.random() > 0.7 ? chars[Math.floor(Math.random() * chars.length)] : char)) .join(''); }, repeat: (text) => `${text}... ${text}... ${text}...`, scramble: (text) => { const words = text.split(' '); return words.map((word) => word.split('').sort(() => Math.random() - 0.5).join('')).join(' '); }, }; const variantColors = { default: { accent: '#00ff00', echo: '#ff00ff' }, cyber: { accent: '#00ffff', echo: '#ff00ff' }, terminal: { accent: '#00ff00', echo: '#ffff00' }, fire: { accent: '#ff4400', echo: '#ff0000' }, nuclear: { accent: '#ff00ff', echo: '#00ffff' }, }; export const EchoChat = forwardRef( ( { accentColor, echoColor, maxMessages = 50, variant = 'default', size = 'default', defaultTransform = 'none', showTransformSelector = true, placeholder = 'Type a message...', sendButtonText = 'Send', onSend, echoFunction, className = '', ...props }, ref ) => { const [messages, setMessages] = useState>([]); const [input, setInput] = useState(''); const [transform, setTransform] = useState(defaultTransform); const [messageId, setMessageId] = useState(0); const colors = accentColor && echoColor ? { accent: accentColor, echo: echoColor } : variantColors[variant]; const processEcho = (text: string, transformType: TransformType): string => { if (echoFunction) { return echoFunction(text, transformType); } return DEFAULT_ECHO[transformType](text); }; const handleSend = (e?: FormEvent) => { e?.preventDefault(); if (!input.trim()) return; const newUserMessage = { id: messageId, text: input, isUser: true, transform }; setMessages((prev) => [...prev, newUserMessage]); const echoText = processEcho(input, transform); const newEchoMessage = { id: messageId + 1, text: echoText, isUser: false, transform }; setMessages((prev) => { const updated = [...prev, newEchoMessage]; return updated.slice(-maxMessages); }); setMessageId((prev) => prev + 2); setInput(''); onSend?.(input, transform); }; const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSend(); } }; const sizeClasses = { compact: { list: 'max-h-[150px]', input: 'py-2 px-3 text-sm', button: 'py-2 px-4 text-xs' }, default: { list: 'max-h-[300px]', input: 'py-3 px-4 text-sm', button: 'py-3 px-6 text-xs' }, large: { list: 'max-h-[500px]', input: 'py-4 px-5 text-base', button: 'py-4 px-8 text-sm' }, }; const s = sizeClasses[size]; return (
{showTransformSelector && (
Echo Mode:
)}
{messages.map((msg) => (
{msg.isUser ? 'YOU' : 'ECHO'}
{msg.text}
))} {messages.length === 0 && (
No messages yet. Start the conversation...
)}
setInput(e.target.value)} onKeyDown={handleKeyDown} placeholder={placeholder} />
System Ready
); } ); EchoChat.displayName = 'EchoChat'; export default EchoChat;