123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
- interface ChatInputProps {
- onSendMessage: (text: string) => void;
- onStopTask: () => void;
- disabled: boolean;
- showStopButton: boolean;
- setContent?: (setter: (text: string) => void) => void;
- isDarkMode?: boolean;
- }
- export default function ChatInput({
- onSendMessage,
- onStopTask,
- disabled,
- showStopButton,
- setContent,
- isDarkMode = false,
- }: ChatInputProps) {
- const [text, setText] = useState('');
- const isSendButtonDisabled = useMemo(() => disabled || text.trim() === '', [disabled, text]);
- const textareaRef = useRef<HTMLTextAreaElement>(null);
- // Handle text changes and resize textarea
- const handleTextChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
- const newText = e.target.value;
- setText(newText);
- // Resize textarea
- const textarea = textareaRef.current;
- if (textarea) {
- textarea.style.height = 'auto';
- textarea.style.height = `${Math.min(textarea.scrollHeight, 100)}px`;
- }
- };
- // Expose a method to set content from outside
- useEffect(() => {
- if (setContent) {
- setContent(setText);
- }
- }, [setContent]);
- // Initial resize when component mounts
- useEffect(() => {
- const textarea = textareaRef.current;
- if (textarea) {
- textarea.style.height = 'auto';
- textarea.style.height = `${Math.min(textarea.scrollHeight, 100)}px`;
- }
- }, []);
- const handleSubmit = useCallback(
- (e: React.FormEvent) => {
- e.preventDefault();
- if (text.trim()) {
- onSendMessage(text);
- setText('');
- }
- },
- [text, onSendMessage],
- );
- const handleKeyDown = useCallback(
- (e: React.KeyboardEvent) => {
- if (e.key === 'Enter' && !e.shiftKey && !e.nativeEvent.isComposing) {
- e.preventDefault();
- handleSubmit(e);
- }
- },
- [handleSubmit],
- );
- return (
- <form
- onSubmit={handleSubmit}
- className={`overflow-hidden rounded-lg border transition-colors ${disabled ? 'cursor-not-allowed' : 'focus-within:border-sky-400 hover:border-sky-400'} ${isDarkMode ? 'border-slate-700' : ''}`}
- aria-label="Chat input form">
- <div className="flex flex-col">
- <textarea
- ref={textareaRef}
- value={text}
- onChange={handleTextChange}
- onKeyDown={handleKeyDown}
- disabled={disabled}
- aria-disabled={disabled}
- rows={5}
- className={`w-full resize-none border-none p-2 focus:outline-none ${
- disabled
- ? isDarkMode
- ? 'cursor-not-allowed bg-slate-800 text-gray-400'
- : 'cursor-not-allowed bg-gray-100 text-gray-500'
- : isDarkMode
- ? 'bg-slate-800 text-gray-200'
- : 'bg-white'
- }`}
- placeholder="What can I help with?"
- aria-label="Message input"
- />
- <div
- className={`flex items-center justify-between px-2 py-1.5 ${
- disabled ? (isDarkMode ? 'bg-slate-800' : 'bg-gray-100') : isDarkMode ? 'bg-slate-800' : 'bg-white'
- }`}>
- <div className="flex gap-2 text-gray-500">{/* Icons can go here */}</div>
- {showStopButton ? (
- <button
- type="button"
- onClick={onStopTask}
- className="rounded-md bg-red-500 px-3 py-1 text-white transition-colors hover:bg-red-600">
- Stop
- </button>
- ) : (
- <button
- type="submit"
- disabled={isSendButtonDisabled}
- aria-disabled={isSendButtonDisabled}
- className={`rounded-md bg-[#19C2FF] px-3 py-1 text-white transition-colors hover:enabled:bg-[#0073DC] ${isSendButtonDisabled ? 'cursor-not-allowed opacity-50' : ''}`}>
- Send
- </button>
- )}
- </div>
- </div>
- </form>
- );
- }
|