All files / src/components/chat MessageInput.tsx

100% Statements 71/71
100% Branches 15/15
100% Functions 6/6
100% Lines 71/71

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 931x               1x 132x 132x 132x 132x 132x 132x 132x     132x 85x 85x 85x 85x 132x   132x 15x 15x 10x 10x 10x 15x   132x   30x 9x 9x 9x 30x   132x 7x 7x   132x 5x 5x   132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x   132x 132x 132x 132x 132x   132x 17x   115x   132x 132x   132x 132x 132x 132x 132x   132x 132x 132x 132x   132x
import React, { useState, useRef, useEffect } from 'react';
 
interface MessageInputProps {
  onSendMessage: (message: string) => void;
  disabled?: boolean;
  placeholder?: string;
}
 
export const MessageInput: React.FC<MessageInputProps> = ({ 
  onSendMessage, 
  disabled = false, 
  placeholder = "输入您的问题..." 
}) => {
  const [message, setMessage] = useState('');
  const [isComposing, setIsComposing] = useState(false);
  const textareaRef = useRef<HTMLTextAreaElement>(null);
 
  // Auto-resize textarea
  useEffect(() => {
    if (textareaRef.current) {
      textareaRef.current.style.height = 'auto';
      textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`;
    }
  }, [message]);
 
  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (message.trim() && !disabled) {
      onSendMessage(message.trim());
      setMessage('');
    }
  };
 
  const handleKeyDown = (e: React.KeyboardEvent) => {
    // Submit on Enter (but not Shift+Enter)
    if (e.key === 'Enter' && !e.shiftKey && !isComposing) {
      e.preventDefault();
      handleSubmit(e);
    }
  };
 
  const handleCompositionStart = () => {
    setIsComposing(true);
  };
 
  const handleCompositionEnd = () => {
    setIsComposing(false);
  };
 
  return (
    <div className="message-input-container">
      <form onSubmit={handleSubmit} className="message-input-form">
        <div className="input-wrapper">
          <textarea
            ref={textareaRef}
            value={message}
            onChange={(e) => setMessage(e.target.value)}
            onKeyDown={handleKeyDown}
            onCompositionStart={handleCompositionStart}
            onCompositionEnd={handleCompositionEnd}
            placeholder={placeholder}
            disabled={disabled}
            className="message-textarea"
            rows={1}
            maxLength={1000}
          />
          
          <button
            type="submit"
            disabled={disabled || !message.trim()}
            className="send-button"
            title="发送消息 (Enter)"
          >
            {disabled ? (
              <span className="send-icon loading">⏳</span>
            ) : (
              <span className="send-icon">↑</span>
            )}
          </button>
        </div>
        
        <div className="input-footer">
          <span className="char-count">
            {message.length} / 1000
          </span>
          <span className="input-hint">
            按 Enter 发送,Shift+Enter 换行
          </span>
        </div>
      </form>
    </div>
  );
};