@bernierllc/messaging-ui
v0.1.1
Published
React components for messaging interfaces with real-time chat features
Downloads
223
Readme
@bernierllc/messaging-ui
React components for messaging interfaces with real-time chat features.
Installation
npm install @bernierllc/messaging-uiUsage
Basic Chat Interface
import React, { useState } from 'react';
import {
ChatInterface,
User,
ChatRoom,
Message,
MessageData
} from '@bernierllc/messaging-ui';
const MyChatApp: React.FC = () => {
const [messages, setMessages] = useState<Message[]>([]);
const [rooms, setRooms] = useState<ChatRoom[]>([]);
const [users, setUsers] = useState<User[]>([]);
const currentUser: User = {
id: 'user-1',
name: 'John Doe',
status: 'online',
metadata: {}
};
const handleSendMessage = (messageData: MessageData) => {
const newMessage: Message = {
id: `msg-${Date.now()}`,
content: messageData.content,
type: messageData.type,
sender: currentUser,
roomId: messageData.roomId,
timestamp: new Date(),
reactions: [],
status: 'sending',
metadata: {}
};
setMessages(prev => [...prev, newMessage]);
// Simulate message being sent
setTimeout(() => {
setMessages(prev =>
prev.map(msg =>
msg.id === newMessage.id
? { ...msg, status: 'delivered' }
: msg
)
);
}, 1000);
};
const handleJoinRoom = (roomId: string) => {
console.log(`Joined room: ${roomId}`);
};
const handleLeaveRoom = (roomId: string) => {
console.log(`Left room: ${roomId}`);
};
const handleUserSelect = (user: User) => {
console.log(`Selected user: ${user.name}`);
};
return (
<div style={{ height: '100vh', width: '100%' }}>
<ChatInterface
currentUser={currentUser}
rooms={rooms}
messages={messages}
users={users}
onSendMessage={handleSendMessage}
onJoinRoom={handleJoinRoom}
onLeaveRoom={handleLeaveRoom}
onUserSelect={handleUserSelect}
/>
</div>
);
};
export default MyChatApp;Individual Components
MessageList
import { MessageList } from '@bernierllc/messaging-ui';
const MyMessageList: React.FC = () => {
const handleMessageReact = (messageId: string, reaction: string) => {
console.log(`React to ${messageId} with ${reaction}`);
};
const handleMessageReply = (message: Message) => {
console.log('Reply to message:', message);
};
const handleMessageEdit = (messageId: string, content: string) => {
console.log(`Edit message ${messageId}: ${content}`);
};
const handleMessageDelete = (messageId: string) => {
console.log(`Delete message ${messageId}`);
};
return (
<MessageList
messages={messages}
currentUser={currentUser}
onMessageReact={handleMessageReact}
onMessageReply={handleMessageReply}
onMessageEdit={handleMessageEdit}
onMessageDelete={handleMessageDelete}
hasMore={true}
onLoadMore={() => console.log('Load more messages')}
/>
);
};MessageInput
import { MessageInput } from '@bernierllc/messaging-ui';
const MyMessageInput: React.FC = () => {
const handleSendMessage = (content: string, attachments?: File[]) => {
console.log('Send message:', { content, attachments });
};
const handleTyping = (isTyping: boolean) => {
console.log('Typing status:', isTyping);
};
return (
<MessageInput
onSendMessage={handleSendMessage}
onTyping={handleTyping}
placeholder="Type a message..."
allowAttachments={true}
allowEmojis={true}
maxLength={1000}
/>
);
};UserList
import { UserList } from '@bernierllc/messaging-ui';
const MyUserList: React.FC = () => {
const handleUserSelect = (user: User) => {
console.log('Selected user:', user);
};
return (
<UserList
users={users}
currentUser={currentUser}
onUserSelect={handleUserSelect}
/>
);
};API Reference
Core Types
User
interface User {
id: string;
name: string;
avatar?: string;
status: 'online' | 'offline' | 'away' | 'busy';
lastSeen?: Date;
isTyping?: boolean;
metadata: Record<string, unknown>;
}Message
interface Message {
id: string;
content: string;
type: 'text' | 'image' | 'file' | 'system';
sender: User;
roomId: string;
timestamp: Date;
editedAt?: Date;
reactions: MessageReaction[];
attachments?: MessageAttachment[];
replyTo?: Message;
status: 'sending' | 'sent' | 'delivered' | 'read' | 'error';
metadata: Record<string, unknown>;
}ChatRoom
interface ChatRoom {
id: string;
name: string;
type: 'direct' | 'group' | 'channel';
participants: User[];
lastMessage?: Message;
unreadCount: number;
isActive: boolean;
createdAt: Date;
updatedAt: Date;
metadata: Record<string, unknown>;
}Components
ChatInterface
Complete chat interface with sidebar and message area.
Props:
currentUser: User- The current logged-in userrooms: ChatRoom[]- Array of available chat roomsmessages: Message[]- Array of messages to displayusers: User[]- Array of all usersonSendMessage: (message: MessageData) => void- Handle message sendingonJoinRoom: (roomId: string) => void- Handle room joiningonLeaveRoom: (roomId: string) => void- Handle room leavingonUserSelect: (user: User) => void- Handle user selectionloading?: boolean- Show loading stateerror?: string- Show error stateclassName?: string- Additional CSS classes
MessageList
Scrollable list of messages with actions.
Props:
messages: Message[]- Messages to displaycurrentUser: User- Current user for message ownershiponMessageReact: (messageId: string, reaction: string) => void- Handle reactionsonMessageReply: (message: Message) => void- Handle repliesonMessageEdit: (messageId: string, content: string) => void- Handle editingonMessageDelete: (messageId: string) => void- Handle deletionloading?: boolean- Show loading indicatorhasMore?: boolean- Whether more messages can be loadedonLoadMore?: () => void- Load more messagesclassName?: string- Additional CSS classes
MessageInput
Input field for typing and sending messages.
Props:
onSendMessage: (content: string, attachments?: File[]) => void- Handle message sendingonTyping: (isTyping: boolean) => void- Handle typing indicatorplaceholder?: string- Input placeholder textdisabled?: boolean- Disable inputmaxLength?: number- Maximum message length (default: 1000)allowAttachments?: boolean- Enable file attachments (default: true)allowEmojis?: boolean- Enable emoji picker (default: true)className?: string- Additional CSS classes
MessageBubble
Individual message display with reactions and actions.
Props:
message: Message- Message to displaycurrentUser: User- Current user for ownership checksshowTimestamp?: boolean- Show message timestamp (default: true)showStatus?: boolean- Show message status (default: true)onReact: (reaction: string) => void- Handle reactionsonReply: () => void- Handle reply actiononEdit: (content: string) => void- Handle edit actiononDelete: () => void- Handle delete actionclassName?: string- Additional CSS classes
UserList
List of users with status indicators.
Props:
users: User[]- Users to displaycurrentUser: User- Current user (excluded from list)onUserSelect: (user: User) => void- Handle user selectionclassName?: string- Additional CSS classes
RoomList
List of chat rooms with unread indicators.
Props:
rooms: ChatRoom[]- Rooms to displaycurrentUser: User- Current userselectedRoom?: ChatRoom | null- Currently selected roomonRoomSelect: (room: ChatRoom) => void- Handle room selectiononRoomLeave: (roomId: string) => void- Handle room leavingclassName?: string- Additional CSS classes
Supporting Components
UserAvatar- User avatar with status indicatorMessageStatus- Message delivery status indicatorMessageTimestamp- Formatted message timestampUnreadBadge- Unread message count badgeTypingIndicator- Shows when users are typingMessageReactions- Display and interact with message reactionsFileUpload- File attachment upload buttonEmojiPicker- Emoji selection interfaceSearchBar- Search input with clear functionality
Features
Real-time Messaging
- Live message updates
- Typing indicators
- User presence status
- Message delivery status
Rich Message Features
- Text messages with mentions and URLs
- File attachments (images, videos, audio, documents)
- Message reactions with emoji
- Reply to messages
- Edit and delete messages
- Message timestamps
User Interface
- Responsive design (mobile-friendly)
- Dark/light theme support
- Keyboard shortcuts
- Accessibility support
- Virtual scrolling for performance
Chat Management
- Multiple room types (direct, group, channel)
- Room creation and management
- User lists with online status
- Search functionality
- Message history with pagination
Styling
The components use CSS classes that can be styled with your preferred styling solution:
/* Main chat interface */
.chat-interface {
display: flex;
height: 100%;
}
.chat-sidebar {
width: 250px;
background: #f5f5f5;
}
.chat-main {
flex: 1;
display: flex;
flex-direction: column;
}
/* Message components */
.message-bubble {
padding: 8px 12px;
margin: 4px 0;
border-radius: 12px;
}
.message-bubble--own {
background: #007bff;
color: white;
margin-left: auto;
}
.message-bubble--other {
background: #e9ecef;
color: #333;
}
/* Input components */
.message-input {
padding: 16px;
border-top: 1px solid #dee2e6;
}
.message-textarea {
width: 100%;
border: none;
outline: none;
resize: none;
}
/* User components */
.user-avatar {
position: relative;
display: inline-block;
}
.user-status {
position: absolute;
bottom: 0;
right: 0;
width: 12px;
height: 12px;
border-radius: 50%;
border: 2px solid white;
}Integration Examples
With Socket.IO
import io from 'socket.io-client';
const socket = io('ws://localhost:3001');
const ChatApp: React.FC = () => {
// ... state management
useEffect(() => {
socket.on('message', (message: Message) => {
setMessages(prev => [...prev, message]);
});
socket.on('typing', (data: { userId: string; isTyping: boolean }) => {
// Update typing state
});
return () => {
socket.off('message');
socket.off('typing');
};
}, []);
const handleSendMessage = (messageData: MessageData) => {
socket.emit('sendMessage', messageData);
};
const handleTyping = (isTyping: boolean) => {
socket.emit('typing', { isTyping });
};
// ... render ChatInterface
};With Redux/Context
import { useContext } from 'react';
import { ChatContext } from './ChatContext';
const ChatApp: React.FC = () => {
const {
currentUser,
rooms,
messages,
users,
sendMessage,
joinRoom,
leaveRoom,
selectUser
} = useContext(ChatContext);
return (
<ChatInterface
currentUser={currentUser}
rooms={rooms}
messages={messages}
users={users}
onSendMessage={sendMessage}
onJoinRoom={joinRoom}
onLeaveRoom={leaveRoom}
onUserSelect={selectUser}
/>
);
};Accessibility
The components include ARIA labels, keyboard navigation, and screen reader support:
- Keyboard navigation with Tab, Enter, and Escape
- ARIA labels for interactive elements
- Screen reader announcements for new messages
- High contrast mode support
- Focus management
Performance
- Virtual scrolling for large message lists
- Debounced typing indicators
- Optimized re-renders with React.memo
- Efficient message grouping algorithms
- Lazy loading of message history
Browser Support
- Modern browsers (Chrome, Firefox, Safari, Edge)
- ES2020+ JavaScript features
- React 18+ required
- TypeScript support included
Contributing
This package is part of the BernierLLC tools ecosystem. For development guidelines, see the main repository documentation.
License
Copyright (c) 2025 Bernier LLC. All rights reserved.
This file is licensed to the client under a limited-use license. The client may use and modify this code only within the scope of the project it was delivered for. Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
