← 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>
  )
}