npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@investtal/ui-chat-message-box

v2.0.1

Published

Complete chat system with message input and display components for messaging applications.

Downloads

229

Readme

@ivtui/chat-message-box

Complete chat system with message input and display components for messaging applications.

Features

Message Input (ChatMessageBox)

  • 📝 Minimal TipTap editor for text input
  • 😊 Emoji picker integration
  • 📎 File attachment support
  • 🎤 Voice recording
  • @ Mentions with autocomplete
  • / Slash commands
  • ⌨️ Keyboard shortcuts (Enter to send)

Message Display (New!)

  • 💬 Message bubbles with sender alignment
  • 👤 Avatars and sender names
  • 🕐 Timestamps with date formatting
  • ✓ Message status indicators (sending, sent, delivered, read, failed)
  • 📅 Date separators (Today, Yesterday, dates)
  • 📦 Automatic message grouping
  • 📜 Auto-scroll with scroll detection
  • 🎨 Tailwind CSS styling

Installation

bun add @ivtui/chat-message-box

Components

1. Chat (All-in-One Solution)

Complete chat interface combining message list and input box.

import { Chat } from "@ivtui/chat-message-box"
import type { ChatMessage } from "@ivtui/chat-message-box"

function ChatApp() {
  const [messages, setMessages] = useState<ChatMessage[]>([
    {
      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 (
    <div style={{ height: "600px" }}>
      <Chat
        messages={messages}
        currentUserId="user-1"
        onSendMessage={handleSend}
      />
    </div>
  )
}

2. MessageList (Message Display Only)

Display messages without input box.

import { MessageList } from "@ivtui/chat-message-box"
import type { ChatMessage } from "@ivtui/chat-message-box"

function Messages() {
  return (
    <MessageList
      messages={messages}
      currentUserId="user-1"
      isLoading={false}
    />
  )
}

3. Message (Single Message Bubble)

import { Message } from "@ivtui/chat-message-box"

function SingleMessage() {
  return (
    <Message
      message={{
        id: "1",
        content: "Hello!",
        sender: { id: "user-1", name: "John" },
        timestamp: new Date(),
        status: "sent",
        isCurrentUser: true,
      }}
      showAvatar={true}
      showSenderName={true}
      showTimestamp={true}
    />
  )
}

4. ChatMessageBox (Input Only)

import { ChatMessageBox } from "@ivtui/chat-message-box"

function ChatInput() {
  const handleSend = (text: string, html: string) => {
    console.log("Message:", text)
  }

  return (
    <ChatMessageBox
      onSend={handleSend}
      placeholder="Type a message..."
    />
  )
}

Types

ChatMessage

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
}

ChatUser

interface ChatUser {
  id: string
  name: string
  avatar?: string
}

Chat Props

interface ChatProps {
  messages: ChatMessage[]
  currentUserId: string
  onSendMessage: (text: string, html: string) => void
  isLoading?: boolean
  onLoadMore?: () => void
  messageBoxProps?: Partial<ChatMessageBoxProps>
  className?: string
  emptyState?: React.ReactNode
}

Real-time Chat Integration

WebSocket Example

import { Chat } from "@ivtui/chat-message-box"
import { useEffect, useState } from "react"

function RealtimeChat() {
  const [messages, setMessages] = useState<ChatMessage[]>([])
  const [ws, setWs] = useState<WebSocket | null>(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 (
    <div style={{ height: "100vh" }}>
      <Chat
        messages={messages}
        currentUserId="me"
        onSendMessage={handleSend}
      />
    </div>
  )
}

Optimistic Updates

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

Status Indicators

// 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
}

Date Separators

Automatically inserted between messages from different days:

  • Today - "Today"
  • Yesterday - "Yesterday"
  • This year - "Jan 15"
  • Other years - "Jan 15, 2024"

Message Grouping

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

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:

bun run storybook

Stories available:

  • Chat/Chat - Full chat interface
  • Chat/Message - Individual message bubbles

Styling

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.