2025-11-20 23:22:05 +01:00
|
|
|
import { Send } from 'lucide-react';
|
2025-12-02 23:46:54 +01:00
|
|
|
import { MESSAGE_MAX_LENGTH } from '../../constants';
|
2025-11-20 23:22:05 +01:00
|
|
|
|
|
|
|
|
/**
|
2025-12-02 23:46:54 +01:00
|
|
|
* Chat Input component with send button and character counter
|
2025-11-20 23:22:05 +01:00
|
|
|
*
|
|
|
|
|
* @param {string} value - Input value
|
|
|
|
|
* @param {function} onChange - Change handler for input
|
|
|
|
|
* @param {function} onSubmit - Submit handler for form
|
|
|
|
|
* @param {boolean} disabled - Whether input is disabled (e.g., when not connected)
|
|
|
|
|
* @param {string} placeholder - Placeholder text (default: "Write a message...")
|
|
|
|
|
* @param {string} className - Additional classes for the form
|
|
|
|
|
* @param {boolean} autoFocus - Whether to autofocus the input
|
|
|
|
|
*/
|
|
|
|
|
const ChatInput = ({
|
|
|
|
|
value,
|
|
|
|
|
onChange,
|
|
|
|
|
onSubmit,
|
|
|
|
|
disabled = false,
|
|
|
|
|
placeholder = 'Write a message...',
|
|
|
|
|
className = '',
|
|
|
|
|
autoFocus = false
|
|
|
|
|
}) => {
|
|
|
|
|
const handleSubmit = (e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
if (!value.trim() || disabled) return;
|
|
|
|
|
onSubmit(e);
|
|
|
|
|
};
|
|
|
|
|
|
2025-12-02 23:46:54 +01:00
|
|
|
const charCount = value.length;
|
|
|
|
|
const isNearLimit = charCount > MESSAGE_MAX_LENGTH * 0.8; // 80% of limit
|
|
|
|
|
const isOverLimit = charCount > MESSAGE_MAX_LENGTH;
|
|
|
|
|
|
2025-11-20 23:22:05 +01:00
|
|
|
return (
|
2025-12-02 23:46:54 +01:00
|
|
|
<div className="space-y-1">
|
|
|
|
|
<form onSubmit={handleSubmit} className={`flex space-x-2 ${className}`}>
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
value={value}
|
|
|
|
|
onChange={onChange}
|
|
|
|
|
placeholder={placeholder}
|
|
|
|
|
disabled={disabled}
|
|
|
|
|
autoFocus={autoFocus}
|
|
|
|
|
maxLength={MESSAGE_MAX_LENGTH}
|
|
|
|
|
className="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:ring-primary-500 focus:border-primary-500 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
|
|
|
/>
|
|
|
|
|
<button
|
|
|
|
|
type="submit"
|
|
|
|
|
disabled={disabled || !value.trim() || isOverLimit}
|
|
|
|
|
className="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
|
|
|
|
aria-label="Send message"
|
|
|
|
|
>
|
|
|
|
|
<Send className="w-5 h-5" />
|
|
|
|
|
</button>
|
|
|
|
|
</form>
|
|
|
|
|
|
|
|
|
|
{/* Character counter - show when approaching limit */}
|
|
|
|
|
{isNearLimit && (
|
|
|
|
|
<div className="text-right">
|
|
|
|
|
<span className={`text-xs ${isOverLimit ? 'text-red-600' : 'text-gray-500'}`}>
|
|
|
|
|
{charCount}/{MESSAGE_MAX_LENGTH}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
2025-11-20 23:22:05 +01:00
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default ChatInput;
|