```react
import { MessageInput } from '@ably/chat-react-ui-kit';
-import { useMessages } from '@ably/chat/react';
-
-// Basic usage
-const { sendMessage } = useMessages();
+import { Message } from '@ably/chat';
-const handleSendMessage = (text: string) => {
- console.log(`Sending message: ${text}`);
- sendMessage({ text });
+// Basic usage - onSent receives the sent Message object
+const handleMessageSent = (message: Message) => {
+ console.log(`Message sent with serial: ${message.serial}`);
};
```
@@ -362,40 +358,44 @@ import { Sidebar } from '@ably/chat-react-ui-kit';
import { RoomOptions } from '@ably/chat';
import { useState } from 'react';
-const [rooms, setRooms] = useState(['general', 'random']);
-const [activeRoom, setActiveRoom] = useState('general');
-const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);
-const [roomOptions] = useState({ occupancy: { enableEvents: true } });
-
-const addRoom = (name: string) => {
- console.log(`Adding room: ${name}`);
- setRooms(prev => prev.includes(name) ? prev : [...prev, name]);
-};
-
-const leaveRoom = (name: string) => {
- console.log(`Leaving room: ${name}`);
- setRooms(prev => prev.filter(n => n !== name));
- if (activeRoom === name) {
- setActiveRoom(rooms.length > 0 ? rooms[0] : undefined);
- }
-};
-
-const handleSetActiveRoom = (name?: string) => {
- console.log(`Setting active room to: ${name}`);
- setActiveRoom(name);
-};
+function SidebarExample() {
+ const [rooms, setRooms] = useState(['general', 'random']);
+ const [activeRoom, setActiveRoom] = useState('general');
+ const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);
+ const [roomOptions] = useState({ occupancy: { enableEvents: true } });
+
+ const addRoom = (name: string) => {
+ console.log(`Adding room: ${name}`);
+ setRooms(prev => prev.includes(name) ? prev : [...prev, name]);
+ };
+
+ const leaveRoom = (name: string) => {
+ console.log(`Leaving room: ${name}`);
+ setRooms(prev => prev.filter(n => n !== name));
+ if (activeRoom === name) {
+ setActiveRoom(rooms.length > 0 ? rooms[0] : undefined);
+ }
+ };
+
+ const handleSetActiveRoom = (name?: string) => {
+ console.log(`Setting active room to: ${name}`);
+ setActiveRoom(name);
+ };
- setIsSidebarCollapsed(prev => !prev)}
-/>
- ```
+ return (
+ setIsSidebarCollapsed(prev => !prev)}
+ />
+ );
+}
+```
Rooms are automatically attached when the Sidebar is mounted, and detached when the component unmounts.
@@ -453,48 +453,50 @@ import { ChatMessageList } from '@ably/chat-react-ui-kit';
import { Message } from '@ably/chat';
import { useState } from 'react';
-// Example with useState for messages
-const [messages, setMessages] = useState
```react
import { ChatMessage } from '@ably/chat-react-ui-kit';
-import { Message } from '@ably/chat';
+import { Message, MessageReactionType } from '@ably/chat';
import { useMessages } from '@ably/chat/react';
const { updateMessage, deleteMessage, sendReaction, deleteReaction } = useMessages();
@@ -538,19 +540,24 @@ const { updateMessage, deleteMessage, sendReaction, deleteReaction } = useMessag
message={message}
onEdit={(message: Message, newText: string) => {
console.log(`Editing message with serial: ${message.serial}, setting text to: ${newText}`);
- updateMessage(message.serial, { text: newText });
+ // Use message.copy() to create an updated message with the new text
+ const updated = message.copy({ text: newText, metadata: message.metadata, headers: message.headers });
+ updateMessage(message.serial, updated);
}}
onDelete={(message: Message) => {
console.log(`Deleting message with serial: ${message.serial}`);
- deleteMessage(message.serial);
+ // Pass an optional description for the deletion
+ deleteMessage(message.serial, { description: 'deleted by user' });
}}
onReactionAdd={(message: Message, emoji: string) => {
console.log(`Adding reaction ${emoji} to message with serial: ${message.serial}`);
- sendReaction(message.serial, { name: emoji });
+ // Include the reaction type (e.g., MessageReactionType.Distinct)
+ sendReaction(message.serial, { type: MessageReactionType.Distinct, name: emoji });
}}
onReactionRemove={(message: Message, emoji: string) => {
console.log(`Removing reaction ${emoji} from message with serial: ${message.serial}`);
- deleteReaction(message.serial, { name: emoji });
+ // Include the reaction type when removing
+ deleteReaction(message.serial, { type: MessageReactionType.Distinct, name: emoji });
}}
/>
```
@@ -624,17 +631,22 @@ The Avatar component is designed to integrate with the `AvatarProvider` to displ
```react
import { Avatar, useUserAvatar } from '@ably/chat-react-ui-kit';
-const { userAvatar } = useUserAvatar({
+
+function UserAvatarExample() {
+ const { userAvatar } = useUserAvatar({
clientId: 'user-123',
displayName: 'John Doe',
});
-
+ return (
+
+ );
+}
```
@@ -680,25 +692,30 @@ import { ParticipantList } from '@ably/chat-react-ui-kit';
import { useChatClient, usePresence, useTyping } from '@ably/chat/react';
import { useState } from 'react';
-// Integration with presence and typing hooks
-const { presenceData } = usePresence();
-const { currentlyTyping } = useTyping();
-const { clientId } = useChatClient();
-const [participantListOpen, setParticipantListOpen] = useState(false);
+function ParticipantListExample() {
+ const { presenceData } = usePresence();
+ const { currentlyTyping } = useTyping();
+ const { clientId } = useChatClient();
+ const [participantListOpen, setParticipantListOpen] = useState(false);
-const toggleParticipantList = () => {
- console.log('Toggling participant list');
- setParticipantListOpen(prev => !prev);
-};
+ const toggleParticipantList = () => {
+ console.log('Toggling participant list');
+ setParticipantListOpen(prev => !prev);
+ };
-{participantListOpen && (
-
-)}
+ return (
+ <>
+ {participantListOpen && (
+
+ )}
+ >
+ );
+}
```
diff --git a/src/pages/docs/chat/react-ui-kit/providers.mdx b/src/pages/docs/chat/react-ui-kit/providers.mdx
index 87519c7421..3748b3d711 100644
--- a/src/pages/docs/chat/react-ui-kit/providers.mdx
+++ b/src/pages/docs/chat/react-ui-kit/providers.mdx
@@ -87,8 +87,10 @@ const globalSettings = {
const roomSettings = {
'general': { allowMessageUpdatesOwn: true },
'announcements': {
- allowMessageUpdates: false,
- allowMessageDeletes: false,
+ allowMessageUpdatesOwn: false,
+ allowMessageUpdatesAny: false,
+ allowMessageDeletesOwn: false,
+ allowMessageDeletesAny: false,
},
};
@@ -123,7 +125,7 @@ const { getEffectiveSettings } = useChatSettings();
const roomSettings = getEffectiveSettings('general');
// Check if message editing is allowed in this room
-if (roomSettings.allowMessageUpdates) {
+if (roomSettings.allowMessageUpdatesOwn || roomSettings.allowMessageUpdatesAny) {
// Show edit button
}
```
@@ -328,15 +330,20 @@ The `useAvatar` hook provides access to the avatar context with comprehensive av
| Property | Description |
|----------|-------------|
-| `getAvatarForUser` | Get avatar for a user |
-| `getAvatarForRoom` | Get avatar for a room |
-| `setUserAvatar` | Set avatar for a user |
-| `setRoomAvatar` | Set avatar for a room |
-| `resetUserAvatar` | Reset avatar for a user |
-| `resetRoomAvatar` | Reset avatar for a room |
-| `exportAvatars` | Export all avatars as a JSON string |
-| `importAvatars` | Import avatars from a JSON string |
-| `onAvatarChange` | Register an avatar change callback |
+| `getAvatarForUser` | Get avatar for a user if it exists in cache (returns `AvatarData \| undefined`) |
+| `createAvatarForUser` | Create avatar for a user and add to cache (returns `AvatarData`) |
+| `getAvatarForRoom` | Get avatar for a room if it exists in cache (returns `AvatarData \| undefined`) |
+| `createAvatarForRoom` | Create avatar for a room and add to cache (returns `AvatarData`) |
+| `setUserAvatar` | Update an existing user avatar or create a new one |
+| `setRoomAvatar` | Update an existing room avatar or create a new one |
+| `getUserAvatars` | Get all cached user avatars |
+| `getRoomAvatars` | Get all cached room avatars |
+| `clearUserAvatars` | Clear all user avatars from cache |
+| `clearRoomAvatars` | Clear all room avatars from cache |
+| `clearAllAvatars` | Clear all avatars from cache |
+| `exportAvatars` | Export all avatar data for backup/migration |
+| `importAvatars` | Import avatar data from backup/migration |
+| `onAvatarChange` | Register a callback for avatar change events |
### Examples
@@ -345,13 +352,26 @@ You can use the `useAvatar` hook to manage user and room avatars in your chat ap
```react
-import { useState, useCallback } from 'react';
+import { useState, useEffect, useCallback } from 'react';
import { useAvatar } from '@ably/chat-react-ui-kit';
-// Basic usage
+// Basic usage - getAvatarForUser returns undefined if avatar doesn't exist
function UserAvatar({ clientId, displayName }) {
- const { getAvatarForUser } = useAvatar();
- const avatar = getAvatarForUser(clientId, displayName);
+ const { getAvatarForUser, createAvatarForUser } = useAvatar();
+ const [avatar, setAvatar] = useState(undefined);
+
+ // Use useEffect to avoid state mutations during render
+ useEffect(() => {
+ const existingAvatar = getAvatarForUser(clientId);
+ if (existingAvatar) {
+ setAvatar(existingAvatar);
+ } else {
+ const newAvatar = createAvatarForUser(clientId, displayName);
+ setAvatar(newAvatar);
+ }
+ }, [getAvatarForUser, createAvatarForUser, clientId, displayName]);
+
+ if (!avatar) return null;
return (
@@ -370,14 +390,23 @@ function UserAvatar({ clientId, displayName }) {
// Setting a user avatar
function UserAvatarManager() {
- const { getAvatarForUser, setUserAvatar } = useAvatar();
+ const { getAvatarForUser, createAvatarForUser, setUserAvatar } = useAvatar();
const [userId] = useState('user-123');
const [displayName] = useState('John Doe');
-
- const avatar = getAvatarForUser(userId, displayName);
-
- const handleAddUser = useCallback(() => {
- // When adding a new user, set their avatar with custom properties
+ const [avatar, setAvatar] = useState(undefined);
+
+ useEffect(() => {
+ const existingAvatar = getAvatarForUser(userId);
+ if (existingAvatar) {
+ setAvatar(existingAvatar);
+ } else {
+ const newAvatar = createAvatarForUser(userId, displayName);
+ setAvatar(newAvatar);
+ }
+ }, [getAvatarForUser, createAvatarForUser, userId, displayName]);
+
+ const handleUpdateAvatar = useCallback(() => {
+ // Update the user's avatar with custom properties
setUserAvatar(userId, {
color: 'bg-blue-500',
initials: 'JD',
@@ -385,6 +414,8 @@ function UserAvatarManager() {
});
}, [setUserAvatar, userId]);
+ if (!avatar) return null;
+
return (
@@ -403,10 +434,10 @@ function UserAvatarManager() {