Complete chat system with message input and display components for messaging applications.
npm install @investtal/ui-chat-message-boxComplete chat system with message input and display components for messaging applications.
``bash`
bun add @ivtui/chat-message-box
Complete chat interface combining message list and input box.
`tsx
import { Chat } from "@ivtui/chat-message-box"
import type { ChatMessage } from "@ivtui/chat-message-box"
function ChatApp() {
const [messages, setMessages] = useState
{
id: "1",
content: "Hello!",
sender: { id: "user-2", name: "Jane", avatar: "..." },
timestamp: new Date(),
status: "read",
},
])
const handleSend = (text: string, html: string) => {
const newMessage: ChatMessage = {
id: Date.now().toString(),
content: text,
sender: { id: "user-1", name: "Me" },
timestamp: new Date(),
status: "sending",
}
setMessages([...messages, newMessage])
}
return (
$3
Display messages without input box.
`tsx
import { MessageList } from "@ivtui/chat-message-box"
import type { ChatMessage } from "@ivtui/chat-message-box"function Messages() {
return (
messages={messages}
currentUserId="user-1"
isLoading={false}
/>
)
}
`$3
`tsx
import { Message } from "@ivtui/chat-message-box"function SingleMessage() {
return (
message={{
id: "1",
content: "Hello!",
sender: { id: "user-1", name: "John" },
timestamp: new Date(),
status: "sent",
isCurrentUser: true,
}}
showAvatar={true}
showSenderName={true}
showTimestamp={true}
/>
)
}
`$3
`tsx
import { ChatMessageBox } from "@ivtui/chat-message-box"function ChatInput() {
const handleSend = (text: string, html: string) => {
console.log("Message:", text)
}
return (
onSend={handleSend}
placeholder="Type a message..."
/>
)
}
`Types
$3
`tsx
interface ChatMessage {
id: string
content: string
sender: ChatUser
timestamp: Date | string
status?: MessageStatus // "sending" | "sent" | "delivered" | "read" | "failed"
type?: MessageType // "text" | "image" | "file" | "voice" | "system"
isCurrentUser?: boolean
replyTo?: string // For future reply feature
}
`$3
`tsx
interface ChatUser {
id: string
name: string
avatar?: string
}
`$3
`tsx
interface ChatProps {
messages: ChatMessage[]
currentUserId: string
onSendMessage: (text: string, html: string) => void
isLoading?: boolean
onLoadMore?: () => void
messageBoxProps?: Partial
className?: string
emptyState?: React.ReactNode
}
`Real-time Chat Integration
$3
`tsx
import { Chat } from "@ivtui/chat-message-box"
import { useEffect, useState } from "react"function RealtimeChat() {
const [messages, setMessages] = useState([])
const [ws, setWs] = useState(null)
useEffect(() => {
const socket = new WebSocket("ws://your-server.com/chat")
socket.onmessage = (event) => {
const newMessage = JSON.parse(event.data)
setMessages(prev => [...prev, newMessage])
}
setWs(socket)
return () => socket.close()
}, [])
const handleSend = (text: string, html: string) => {
const message: ChatMessage = {
id:
temp-${Date.now()},
content: text,
sender: { id: "me", name: "Me" },
timestamp: new Date(),
status: "sending",
} setMessages(prev => [...prev, message])
ws?.send(JSON.stringify(message))
}
return (
messages={messages}
currentUserId="me"
onSendMessage={handleSend}
/>
)
}
`$3
`tsx
const handleSend = async (text: string) => {
const tempId = temp-${Date.now()} // Add optimistic message
const optimisticMessage: ChatMessage = {
id: tempId,
content: text,
sender: currentUser,
timestamp: new Date(),
status: "sending",
}
setMessages(prev => [...prev, optimisticMessage])
try {
// Send to server
const response = await fetch("/api/messages", {
method: "POST",
body: JSON.stringify({ content: text }),
})
const serverMessage = await response.json()
// Update with server data
setMessages(prev =>
prev.map(msg =>
msg.id === tempId ? { ...serverMessage, status: "sent" } : msg
)
)
} catch (error) {
// Mark as failed
setMessages(prev =>
prev.map(msg =>
msg.id === tempId ? { ...msg, status: "failed" } : msg
)
)
}
}
`Message Features
$3
`tsx
// Messages automatically show status icons for current user
{
status: "sending" // Clock icon, gray
status: "sent" // Single check, gray
status: "delivered" // Double check, gray
status: "read" // Double check, blue
status: "failed" // Warning icon, red
}
`$3
Automatically inserted between messages from different days:
- Today - "Today"
- Yesterday - "Yesterday"
- This year - "Jan 15"
- Other years - "Jan 15, 2024"
$3
Consecutive messages from the same sender are automatically grouped:
- First message: Shows avatar, sender name, timestamp
- Middle messages: Hidden avatar/name/timestamp
- Last message: Shows avatar, timestamp
Utilities
`tsx
import {
formatMessageTime, // Format time as "14:30"
formatDateSeparator, // Format date as "Today" / "Yesterday" / date
isSameDay, // Check if two dates are same day
} from "@ivtui/chat-message-box"
`Voice Recording
The component includes Facebook Messenger-style voice recording. See VOICE_RECORDING_API.md for details.
Future Features (Planned)
- Virtual scrolling for thousands of messages
- Infinite scroll with lazy loading
- Typing indicators
- Reply to messages
- File message previews
- Image message rendering
- Voice message playback
- Message reactions
- Read receipts with avatars
Storybook
Run Storybook to see all components and examples:
`bash
bun run storybook
`Stories available:
-
Chat/Chat - Full chat interface
- Chat/Message - Individual message bubblesStyling
The package uses Tailwind CSS for styling. Make sure Tailwind is configured in your project.
For custom styling, you can override classes via the
className` prop on any component.