← back to Dear Bubbe Nextjs
components/TextInput.tsx
94 lines
'use client'
import { useState, useRef, KeyboardEvent } from 'react'
interface TextInputProps {
onSend: (message: string) => void
disabled?: boolean
placeholder?: string
className?: string
}
export default function TextInput({
onSend,
disabled = false,
placeholder = "Type a message to Bubbe...",
className = ''
}: TextInputProps) {
const [message, setMessage] = useState('')
const [isSending, setIsSending] = useState(false)
const inputRef = useRef<HTMLTextAreaElement>(null)
const handleSend = async () => {
const trimmedMessage = message.trim()
if (!trimmedMessage || disabled || isSending) return
setIsSending(true)
setMessage('')
try {
await onSend(trimmedMessage)
} finally {
setIsSending(false)
// Refocus input after sending
setTimeout(() => {
inputRef.current?.focus()
}, 100)
}
}
const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
// Send on Enter, but allow Shift+Enter for new lines
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault()
handleSend()
}
}
const adjustTextareaHeight = () => {
const textarea = inputRef.current
if (textarea) {
textarea.style.height = 'auto'
const newHeight = Math.min(textarea.scrollHeight, 120) // Max 120px height
textarea.style.height = `${newHeight}px`
}
}
return (
<div className={`text-input-container ${className}`}>
<div className="text-input-wrapper">
<textarea
ref={inputRef}
value={message}
onChange={(e) => {
setMessage(e.target.value)
adjustTextareaHeight()
}}
onKeyDown={handleKeyDown}
placeholder={placeholder}
disabled={disabled || isSending}
className="text-input-field"
rows={1}
aria-label="Message input"
/>
<button
onClick={handleSend}
disabled={!message.trim() || disabled || isSending}
className="text-send-button"
aria-label="Send message"
>
{isSending ? (
<span className="sending-spinner">⏳</span>
) : (
<span className="send-icon">📨</span>
)}
</button>
</div>
<div className="text-input-hint">
Press Enter to send, Shift+Enter for new line
</div>
</div>
)
}