Spaces:
Sleeping
Sleeping
| import React, { useState, useRef, useEffect } from 'react'; | |
| interface ChatInputProps { | |
| onSendMessage: (content: string) => void; | |
| isSending: boolean; | |
| disabled: boolean; | |
| } | |
| const ChatInput: React.FC<ChatInputProps> = ({ onSendMessage, isSending, disabled }) => { | |
| const [message, setMessage] = useState(''); | |
| const textareaRef = useRef<HTMLTextAreaElement>(null); | |
| // Auto-resize textarea | |
| useEffect(() => { | |
| if (textareaRef.current) { | |
| textareaRef.current.style.height = 'auto'; | |
| textareaRef.current.style.height = `${Math.min(textareaRef.current.scrollHeight, 200)}px`; | |
| } | |
| }, [message]); | |
| const handleSubmit = () => { | |
| const trimmed = message.trim(); | |
| if (trimmed && !isSending && !disabled) { | |
| onSendMessage(trimmed); | |
| setMessage(''); | |
| if (textareaRef.current) { | |
| textareaRef.current.style.height = 'auto'; | |
| } | |
| } | |
| }; | |
| const handleKeyDown = (e: React.KeyboardEvent) => { | |
| if (e.key === 'Enter' && !e.shiftKey) { | |
| e.preventDefault(); | |
| handleSubmit(); | |
| } | |
| }; | |
| return ( | |
| <div className="border-t border-gray-200 bg-white p-4"> | |
| <div className="max-w-4xl mx-auto"> | |
| <div className="relative flex items-end gap-3 bg-gray-50 border border-gray-200 rounded-2xl p-2 focus-within:border-indigo-300 focus-within:ring-2 focus-within:ring-indigo-100 transition-all"> | |
| <textarea | |
| ref={textareaRef} | |
| value={message} | |
| onChange={(e) => setMessage(e.target.value)} | |
| onKeyDown={handleKeyDown} | |
| placeholder={disabled ? "Select or create a chat to start..." : "Ask a question..."} | |
| disabled={disabled || isSending} | |
| rows={1} | |
| className="flex-1 resize-none bg-transparent px-3 py-2 text-gray-800 placeholder-gray-400 focus:outline-none text-sm leading-relaxed max-h-[200px] disabled:cursor-not-allowed" | |
| /> | |
| <button | |
| onClick={onsubmit} | |
| disabled={!message.trim() || isSending || disabled} | |
| className={`flex-shrink-0 p-3 rounded-xl transition-all duration-200 ${message.trim() && !isSending && !disabled | |
| ? 'bg-gradient-to-r from-indigo-600 to-purple-600 text-white shadow-lg hover:shadow-indigo-500/30 hover:scale-105 active:scale-95' | |
| : 'bg-gray-200 text-gray-400 cursor-not-allowed' | |
| }`} | |
| > | |
| {isSending ? ( | |
| <svg className="w-5 h-5 animate-spin" fill="none" viewBox="0 0 24 24"> | |
| <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle> | |
| <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> | |
| </svg> | |
| ) : ( | |
| <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" /> | |
| </svg> | |
| )} | |
| </button> | |
| </div> | |
| <p className="text-xs text-gray-400 text-center mt-2"> | |
| Press Enter to send, Shift+Enter for new line | |
| </p> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export default ChatInput; | |