+```javascript
+import { MessageReactionType } from '@ably/chat';
+
+const room = await ablyChatClient.rooms.get('room1', {
+ messages: {
+ defaultMessageReactionType: MessageReactionType.Unique,
+ },
+});
+```
+
+```swift
+let room = try await ablyChatClient.rooms.get(
+ name: "room1",
+ options: .init(
+ messages: .init(defaultMessageReactionType: .unique)
+ )
+)
+```
+
+```kotlin
+val room = ablyChatClient.rooms.get("room1") {
+ messages {
+ defaultMessageReactionType = MessageReactionType.Unique
+ }
+}
+```
+
+```react
+import { MessageReactionType } from '@ably/chat';
+import { ChatRoomProvider } from '@ably/chat/react';
+
+const roomOptions = {
+ messages: {
+ defaultMessageReactionType: MessageReactionType.Unique,
+ },
+};
+
+const MyComponent = () => {
+ return (
+
+
+
+ );
+};
+```
+
+
## Adding a message reaction
+
```javascript
@@ -87,52 +165,121 @@ room.messages.reactions.send(message,
count = 100,
)
```
+
+```react
+import { MessageReactionType } from '@ably/chat';
+import { useMessages } from '@ably/chat/react';
+
+const MyComponent = () => {
+ const { sendReaction } = useMessages();
+
+ const handleAddReaction = async (message) => {
+ try {
+ // Add a 👍 reaction using the default type
+ await sendReaction(message, { name: '👍' });
+
+ // The reaction can be anything, not just UTF-8 emojis:
+ await sendReaction(message, { name: ':like:' });
+ await sendReaction(message, { name: '+1' });
+
+ // Add a :love: reaction using the Unique type
+ await sendReaction(message, {
+ name: ':love:',
+ type: MessageReactionType.Unique,
+ });
+
+ // Add a ❤️ reaction with count 100 using the Multiple type
+ await sendReaction(message, {
+ name: '❤️',
+ type: MessageReactionType.Multiple,
+ count: 100,
+ });
+ } catch (error) {
+ console.error('Error adding reaction:', error);
+ }
+ };
+
+ return (
+
+
+
+ );
+};
+```
+
-## Types of message reactions
-
-Ably Chat supports three types of message reactions. They differ in how they are aggregated and what are the rules for adding and removing them.
-
-| Type | Description | Example | Similar to |
-| ---- | ----------- | ------- | --------- |
-| `Unique`, `reaction:unique.v1` | A user can react to a message only once, with a reaction of their choice. When a user reacts a second time their reaction is changed. | Can 👍 or ❤️ but not both or more than once. | iMessage, WhatsApp, Facebook Messenger |
-| `Distinct`, `reaction:distinct.v1` | A user can react to a message with each reaction at most once. | Can 👍 and ❤️ but each reaction only once. No 👍👍. | Slack |
-| `Multiple`, `reaction:multiple.v1` | A user can react to a message with any reactions as many times as they like. Optionally a `count` parameter can be set when reacting. Reacting again adds to the existing count.| Can 👍 10 times and ❤️ 100 times. | Claps on Medium |
+## Removing a message reaction
-Note that if adding two identical reactions of type `Distinct`, the second one will be accepted and broadcast as a raw reaction, but it will be ignored in the summary (aggregate). Similarly, when removing a reaction that doesn't exist (of any type), the operation will be accepted and broadcast as a raw reaction, but it will have no effect on the summary.
-
-### Configure the default reaction type
+
```javascript
-import { MessageReactionType } from '@ably/chat';
+// Remove a 👍 reaction using the default type
+await room.messages.reactions.delete(message, { name: '👍' });
-const room = await ablyChatClient.rooms.get('room1', {
- messages: {
- defaultMessageReactionType: MessageReactionType.Unique,
- },
+// Remove a :love: reaction using the Unique type
+await room.messages.reactions.delete(message, {
+ name: ':love:',
+ type: MessageReactionType.Unique,
});
-```
-```swift
-let room = try await ablyChatClient.rooms.get(
- name: "room1",
- options: .init(
- messages: .init(defaultMessageReactionType: .unique)
- )
-)
+// Remove a ❤️ reaction with count 50 using the Multiple type
+await room.messages.reactions.delete(message, {
+ name: '❤️',
+ type: MessageReactionType.Multiple,
+ count: 50,
+});
```
-```kotlin
-val room = ablyChatClient.rooms.get("room1") {
- messages {
- defaultMessageReactionType = MessageReactionType.Unique
+```react
+import { MessageReactionType } from '@ably/chat';
+import { useMessages } from '@ably/chat/react';
+
+const MyComponent = () => {
+ const { deleteReaction } = useMessages();
+
+ const handleRemoveReaction = async (message) => {
+ try {
+ // Remove a 👍 reaction using the default type
+ await deleteReaction(message, { name: '👍' });
+
+ // Remove a :love: reaction using the Unique type
+ await deleteReaction(message, {
+ name: ':love:',
+ type: MessageReactionType.Unique,
+ });
+
+ // Remove a ❤️ reaction with count 50 using the Multiple type
+ await deleteReaction(message, {
+ name: '❤️',
+ type: MessageReactionType.Multiple,
+ count: 50,
+ });
+ } catch (error) {
+ console.error('Error removing reaction:', error);
}
-}
+ };
+
+ return (
+
+
+
+ );
+};
```
@@ -151,6 +298,36 @@ interface Message {
}
}
+// example (in real use, it is unlikely that all reaction types are present):
+{
+ // ... other message fields omitted
+ reactions: {
+ unique: {
+ '👍': { total: 2, clientIds: ['clientA', 'clientB'] },
+ '❤️': { total: 1, clientIds: ['clientC'] },
+ },
+ distinct: {
+ '👍': { total: 2, clientIds: ['clientA', 'clientB'] },
+ '❤️': { total: 1, clientIds: ['clientA'] },
+ },
+ multiple: {
+ '👍': { total: 10, clientIds: {'clientA': 7, 'clientB': 3} },
+ '❤️': { total: 100, clientIds: {'clientA': 100} },
+ },
+ }
+}
+```
+
+```react
+interface Message {
+ // ... (other fields omitted)
+ reactions: {
+ unique: Ably.SummaryUniqueValues,
+ distinct: Ably.SummaryDistinctValues,
+ multiple: Ably.SummaryMultipleValues,
+ }
+}
+
// example (in real use, it is unlikely that all reaction types are present):
{
// ... other message fields omitted
@@ -181,7 +358,13 @@ Always call `Message.with(event)` when applying message events and reaction even
## Subscribing to message reactions
+
```javascript
@@ -189,6 +372,7 @@ room.messages.reactions.subscribe((event) => {
console.log("received reactions summary event", event);
});
```
+
```swift
room.messages.reactions.subscribe { event in
print("received reactions summary event: \(event)")
@@ -200,6 +384,20 @@ room.messages.reactions.subscribe { event ->
println("received reactions summary event: $event")
}
```
+
+```react
+import { useMessages } from '@ably/chat/react';
+
+const MyComponent = () => {
+ useMessages({
+ reactionsListener: (event) => {
+ console.log("received reactions summary event", event);
+ },
+ });
+
+ return ...;
+};
+```
The event is of type `reaction.summary`. `event.summary` is the received reactions summary and contains the following properties:
@@ -259,6 +457,47 @@ room.messages.reactions.subscribe { event ->
}
}
```
+
+```react
+import { useState, useEffect } from 'react';
+import { useMessages, Message } from '@ably/chat/react';
+
+const MyComponent = () => {
+ const [messages, setMessages] = useState
```javascript
@@ -298,9 +537,35 @@ val room = ablyChatClient.rooms.get("room1") {
}
}
```
+
+```react
+import { ChatRoomProvider } from '@ably/chat/react';
+
+const roomOptions = {
+ messages: {
+ messages: {
+ rawMessageReactions: true,
+ },
+ },
+};
+
+const MyComponent = () => {
+ return (
+
+
+
+ );
+};
+```
+
```javascript
@@ -332,9 +597,29 @@ room.messages.reactions.subscribeRaw { event ->
}
}
```
+
+```react
+import { MessageReactionEvents, useMessages } from '@ably/chat/react';
+
+const MyComponent = () => {
+ useMessages({
+ rawReactionsListener: (event) => {
+ if (event.type === MessageReactionEvents.Create) {
+ console.log("new reaction", event.reaction);
+ } else if (event.type === MessageReactionEvents.Delete) {
+ console.log("reaction removed", event.reaction);
+ }
+ },
+ });
+
+ return ...;
+};
+```
+
You should be aware of the following limitations: