diff --git a/docusaurus/docs/React/_docusaurus-components/GHComponentLink.jsx b/docusaurus/docs/React/_docusaurus-components/GHComponentLink.jsx index 844b95368..d719d528b 100644 --- a/docusaurus/docs/React/_docusaurus-components/GHComponentLink.jsx +++ b/docusaurus/docs/React/_docusaurus-components/GHComponentLink.jsx @@ -1,7 +1,14 @@ import React from 'react'; -const GHComponentLink = ({text, path}) => { - return {text} -} +const GHComponentLink = ({ text, as: As = React.Fragment, path, branch = 'master' }) => { + return ( + + {text} + + ); +}; export default GHComponentLink; diff --git a/docusaurus/docs/React/components/message-components/reactions.mdx b/docusaurus/docs/React/components/message-components/reactions.mdx index e0559e677..68189c27d 100644 --- a/docusaurus/docs/React/components/message-components/reactions.mdx +++ b/docusaurus/docs/React/components/message-components/reactions.mdx @@ -6,23 +6,19 @@ title: Reactions import GHComponentLink from '../../_docusaurus-components/GHComponentLink'; -The Stream Chat API provides built-in support for adding reactions to messages. The component library provides three default -components to enable reaction selection and display: - -- [`ReactionSelector`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Reactions/ReactionSelector.tsx) - allows - the connected user to select a reaction on a message +:::caution +If you're moving from older versions to `11.0.0` then make sure to read ["Reactions 11.0.0"](../../release-guides/reactions-v11.mdx) release guide to help you transition to the new implementation. +::: -- [`ReactionsList`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Reactions/ReactionsList.tsx) - displays - the reactions added to a message +The Stream Chat API provides built-in support for adding reactions to messages. The component library provides three default components to enable reaction selection and display: -- [`SimpleReactionsList`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Reactions/SimpleReactionsList.tsx) - displays - a minimal list of the reactions added to a message +- [`ReactionSelector`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Reactions/ReactionSelector.tsx) - allows the connected user to select a reaction on a message +- [`ReactionsList`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Reactions/ReactionsList.tsx) - displays the reactions added to a message +- [`SimpleReactionsList`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Reactions/SimpleReactionsList.tsx) - displays a minimal list of the reactions added to a message ## Basic Usage -By default, the `ReactionSelector` and `ReactionsList` components are included within `MessageSimple`. To render reaction UI within a -custom [Message UI](./message-ui.mdx) component, import both components (or `SimpleReactionsList` for a lightweight view) and render -conditionally. +By default, the `ReactionSelector` and `ReactionsList` components are included within `MessageSimple`. To render reaction UI within a custom [Message UI](./message-ui.mdx) component, import both components (or `SimpleReactionsList` for a lightweight view) and render conditionally. ```jsx const CustomMessage = () => { @@ -55,19 +51,14 @@ Be default, the `ReactionSelector` component provides the following reaction opt - `haha` - `wow` - `sad` -- `angry` +- `angry` - removed in `11.0.0` -The `defaultMinimalEmojis` data set that populates the default reaction options can be found in the -[emojiData](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Channel/emojiData.ts) file in the -component library. +The `defaultMinimalEmojis` data set that populates the default reaction options can be found in the file in the component library. -To override the default selection set, provide your own array of `MinimalEmoji` type objects and pass into the `reactionOptions` -prop on the `ReactionSelector` component. You can also override the default [handleReaction](./components/contexts/message-context.mdx#handlereaction) -function by adding the `handleReaction` prop. +To override the default selection set, provide your own array of `MinimalEmoji` type objects and pass into the `reactionOptions` prop on the `ReactionSelector` component. You can also override the default [`handleReaction`](../contexts/message-context.mdx#handlereaction) function by adding the `handleReaction` prop. :::caution -If custom `reactionOptions` are supplied to the `ReactionSelector` component, then the same data set needs to be delivered to the -`ReactionsList` component so the display for processed reactions has the same emoji objects. +If custom `reactionOptions` are supplied to the `ReactionSelector` component, then the same data set needs to be delivered to the `ReactionsList` component so the display for processed reactions has the same emoji objects. ::: ```jsx @@ -105,8 +96,7 @@ const CustomMessage = () => { ; ``` -To completely override the `ReactionSelector` and `ReactionsList` components in `MessageSimple`, pass your own custom components as props -to the [`Channel`](./components/core-components/channel.mdx). +To completely override the `ReactionSelector` and `ReactionsList` components in `MessageSimple`, pass your own custom components as props to the [`Channel`](../core-components/channel.mdx). ```jsx const CustomReactionSelector = (props) => { @@ -131,9 +121,9 @@ const CustomReactionsList = (props) => { ## ReactionSelector Props -### additionalEmojiProps +### additionalEmojiProps (removed in `11.0.0`) -Additional props to be passed to the [NimbleEmoji](https://github.com/missive/emoji-mart/blob/master/src/components/emoji/nimble-emoji.js) component from `emoji-mart`. +Additional props to be passed to the [`NimbleEmoji`](https://github.com/missive/emoji-mart/blob/v3.0.1/src/components/emoji/nimble-emoji.js) component from `emoji-mart`. | Type | | ------ | @@ -159,9 +149,9 @@ If true, shows the user's avatar with the reaction. Function that adds/removes a reaction on a message (overrides the function stored in `MessageContext`). -| Type | Default | -| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | -| (reactionType: string, event: React.BaseSyntheticEvent) => Promise | [MessageContextValue['handleReaction']](./components/contexts/message-context.mdx#handlereaction) | +| Type | Default | +| ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | +| (reactionType: string, event: React.BaseSyntheticEvent) => Promise | [MessageContextValue['handleReaction']](../contexts/message-context.mdx#handlereaction) | ### latest_reactions @@ -191,9 +181,10 @@ An object that keeps track of the count of each type of reaction on a message (o A list of the currently supported reactions on a message. -| Type | Default | -| ----- | --------------------------------------------------------------------------- | -| array | | +| Version | Type | Default | +| ------- | ----- | -------------------------------------------------------------------------------------------------------------- | +| >=4.0.0 | array | | +| ^11.0.0 | array | | ### reverse @@ -205,9 +196,9 @@ If true, adds a CSS class that reverses the horizontal positioning of the select ## ReactionsList Props -### additionalEmojiProps +### additionalEmojiProps (removed in `11.0.0`) -Additional props to be passed to the [NimbleEmoji](https://github.com/missive/emoji-mart/blob/master/src/components/emoji/nimble-emoji.js) component from `emoji-mart`. +Additional props to be passed to the [`NimbleEmoji`](https://github.com/missive/emoji-mart/blob/v3.0.1/src/components/emoji/nimble-emoji.js) component from `emoji-mart`. | Type | | ------ | @@ -217,9 +208,9 @@ Additional props to be passed to the [NimbleEmoji](https://github.com/missive/em Custom on click handler for an individual reaction in the list (overrides the function stored in `MessageContext`). -| Type | Default | -| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | -| (event: React.BaseSyntheticEvent) => Promise \| void | [MessageContextValue['onReactionListClick']](./components/contexts/message-context.mdx#onreactionlistclick) | +| Type | Default | +| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | +| (event: React.BaseSyntheticEvent) => Promise \| void | [MessageContextValue['onReactionListClick']](../contexts/message-context.mdx#onreactionlistclick) | ### own_reactions @@ -241,9 +232,10 @@ An object that keeps track of the count of each type of reaction on a message (o A list of the currently supported reactions on a message. -| Type | Default | -| ----- | --------------------------------------------------------------------------- | -| array | | +| Version | Type | Default | +| ------- | ----- | -------------------------------------------------------------------------------------------------------------- | +| >=4.0.0 | array | | +| ^11.0.0 | array | | ### reactions @@ -263,9 +255,9 @@ If true, adds a CSS class that reverses the horizontal positioning of the select ## SimpleReactionsList Props -### additionalEmojiProps +### additionalEmojiProps (removed in `11.0.0`) -Additional props to be passed to the [NimbleEmoji](https://github.com/missive/emoji-mart/blob/master/src/components/emoji/nimble-emoji.js) component from `emoji-mart`. +Additional props to be passed to the [`NimbleEmoji`](https://github.com/missive/emoji-mart/blob/v3.0.1/src/components/emoji/nimble-emoji.js) component from `emoji-mart`. | Type | | ------ | @@ -275,9 +267,9 @@ Additional props to be passed to the [NimbleEmoji](https://github.com/missive/em Function that adds/removes a reaction on a message (overrides the function stored in `MessageContext`). -| Type | Default | -| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | -| (reactionType: string, event: React.BaseSyntheticEvent) => Promise | [MessageContextValue['handleReaction']](./components/contexts/message-context.mdx#handlereaction) | +| Type | Default | +| ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | +| (reactionType: string, event: React.BaseSyntheticEvent) => Promise | [MessageContextValue['handleReaction']](../contexts/message-context.mdx#handlereaction) | ### own_reactions @@ -299,9 +291,10 @@ An object that keeps track of the count of each type of reaction on a message (o A list of the currently supported reactions on a message. -| Type | Default | -| ----- | --------------------------------------------------------------------------- | -| array | | +| Version | Type | Default | +| ------- | ----- | -------------------------------------------------------------------------------------------------------------- | +| >=4.0.0 | array | | +| ^11.0.0 | array | | ### reactions diff --git a/docusaurus/docs/React/guides/theming/reactions.mdx b/docusaurus/docs/React/guides/theming/reactions.mdx index cee774fb0..f49474a86 100644 --- a/docusaurus/docs/React/guides/theming/reactions.mdx +++ b/docusaurus/docs/React/guides/theming/reactions.mdx @@ -7,6 +7,10 @@ title: Reaction Selector and List import CustomReactionSelector from '../../assets/CustomReactionSelector.png'; import CustomReactionsList from '../../assets/CustomReactionsList.png'; +:::caution +If you're moving from older versions to `11.0.0` then make sure to read ["Reactions 11.0.0"](../../release-guides/reactions-v11.mdx) release guide to help you transition to the new implementation. +::: + In this example, we will demonstrate how to override the library's default reaction set, which can be found stored as the [`defaultMinimalEmojis`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Channel/emojiData.ts) variable. We will replace the default set with up and down arrows, simulating an up/down voting feature. @@ -14,8 +18,8 @@ variable. We will replace the default set with up and down arrows, simulating an ### Choose Your Reactions Under the hood, our `ReactionSelector`, `ReactionsList`, and `SimpleReactionsList` components render individual emoji objects -using the [`NimbleEmoji`](https://github.com/missive/emoji-mart/blob/master/src/components/emoji/nimble-emoji.js) component -from [emoji-mart](https://www.npmjs.com/package/emoji-mart). Therefore, the object type of our custom reactions needs to +using the [`NimbleEmoji`](https://github.com/missive/emoji-mart/blob/v3.0.1/src/components/emoji/nimble-emoji.js) component +from [`emoji-mart`](https://www.npmjs.com/package/emoji-mart). Therefore, the object type of our custom reactions needs to conform to `NimbleEmoji` props. `NimbleEmoji` accepts an `emoji` prop, which pertains to the object mapping of your custom reaction. The `emoji` prop has @@ -107,15 +111,12 @@ const customReactions = [ ``` :::caution -If custom `reactionOptions` are supplied to the selector component, then the same data set needs to be delivered to the -list component so the display for processed reactions has the same emoji objects. +If custom `reactionOptions` are supplied to the selector component, then the same data set needs to be delivered to the list component so the display for processed reactions has the same emoji objects. ::: ### The Final Code -Putting all the pieces together and building upon the [custom message](./message-ui.mdx#how-it-fits-together) -in the General Customization section, we are left with the following code for our [Message UI](../../components/message-components/message-ui.mdx) -component: +Putting all the pieces together and building upon the [custom message](./message-ui.mdx#how-it-fits-together) in the General Customization section, we are left with the following code for our [Message UI](../../components/message-components/message-ui.mdx) component: ```jsx import React, { useRef } from 'react'; @@ -186,9 +187,7 @@ export const CustomMessage = () => { {message.attachments && } - {hasReactions && ( - - )} + {hasReactions && } diff --git a/docusaurus/docs/React/release-guides/reactions-v11.mdx b/docusaurus/docs/React/release-guides/reactions-v11.mdx new file mode 100644 index 000000000..3f6462cef --- /dev/null +++ b/docusaurus/docs/React/release-guides/reactions-v11.mdx @@ -0,0 +1,252 @@ +--- +id: reactions-v11 +sidebar_position: 2 +title: Reactions 11.0.0 +keywords: [migration guide, upgrade, reactions, breaking changes, v11] +--- + +import GHComponentLink from '../_docusaurus-components/GHComponentLink'; + +## Introducing new reactions (with breaking changes) + +When it came to developer experience regarding customization of the reaction components our team noticed that our integrators generally strugled to make more advanced adjustments to reactions without having to rebuild the whole [component set](../components/message-components/reactions.mdx). The whole process has been quite unintuitive and that's why this update aims at making adjusting your reactions much easier. + +### Main reasons for a revamp + +- inability to reuse default (Stream supplied reactions) with your custom ones +- strong reliance on [`emoji-mart`](https://github.com/missive/emoji-mart) and inability to use completely custom reactions out of the box +- certain `additionalEmojiProps` did not work with Stream-supplied reactions + +```tsx +// not exported directly (hidden, leading to poor DX) +import { defaultMinimalEmojis } from 'stream-chat-react/dist/components/Channel/emojiData'; + +export const customReactions = [ + { + // relies on EmojiMart-supplied sprite sheet, "native" option does not work for Stream-supplied reactions + // you'd need to look up supported id's in stream-emoji.json under "emojis" key + id: 'bulb', + }, + // unsupported + { + id: 'rick_roll', + }, + // this wouldn't work + ...defaultMinimalEmojis, +]; +``` + +## New default setup and how it works + +SDK by default comes with five pre-defined reaction types (`haha`, `like`, `love`, `sad` and `wow`) which are newly rendered by component which utilises sprite sheet system and renders images for each reaction to make sure it works flawlessly on every system. Default reaction options are defined in and these options are reused for both [`ReactionSelector`](../components/message-components/reactions.mdx#reactionselector-props) and [`ReactionsList`](../components/message-components/reactions.mdx#reactionslist-props) (as well as [`SimpleReactionsList`](../components/message-components/reactions.mdx#simplereactionslist-props)). These options come by default from the ComponentContext but local component property will be prioritised if defined. This is how it works under the hood: + +```ts +contextReactionOptions = defaultReactionOptions; +// ... +const reactionOptions = propsReactionOptions ?? contextReactionOptions; +``` + +:::note +Beware that sixth reaction type `angry` has been removed in this update, if you need to re-enable it, follow [this guide](#re-enabling-angry-reaction). +::: + +## Custom reaction types and components + +It's possible to supply your own reaction types and components to represent such reactions - let's implement reaction of type `rick_roll` to render a Rick Roll GIF and define override for default type `love`: + +```tsx +import { Channel } from 'stream-chat-react'; + +const RickRollReaction = () => ( + +); + +const customReactionOptions = [ + { + Component: RickRollReaction, + type: 'rick_roll', + name: 'Rick Roll', + }, + { + Component: () => <>❤️ + type: 'love', + name: "Heart" + } +]; +``` + +And then you can pass these newly created options to [`Channel`](../components/core-components/channel.mdx) component which will be then propagated to `ReactionSelector` and `ReactionsList`: + +```tsx +{/*...*/} +``` + +## Emoji Mart integration + +If you're used to work with [EmojiMart emojis](https://github.com/missive/emoji-mart#-emoji-component) then integrating with new reaction system shouldn't be a big trouble as you can define how your components look and reach for context if you need to: + +```tsx +// arbitrary EmojiMartContext (does not come with the SDK) +import { useEmojiMartContext } from '../contexts'; + +const CustomLikeComponent = () => { + const { selectedSkinTones, selectedSet } = useEmojiMartContext(); + + // to use EmojiMart web components you'll need to go through initiation steps, see EmojiMart documentation + return ; +}; + +const reactionOptions = [ + { + type: 'like', + component: CustomLikeComponent, + name: 'EmojiMart like', + }, +]; + +// pass reaction options to component context (Channel) or to ReactionSelector and ReactionsList +``` + +## Use of different reaction components for the same reaction types for `ReactionSelector` and `ReactionsList` components + +If you need more fine-grain tuning and want to - for example - enable only a certain subset of clickable reactions but want to display the full set then you'd do something like this: + +```tsx +const JoyReaction = () => <>😂; +const CatReaction = () => <>🐈; +const ThumbsUpReaction = () => <>👍; +const SmileReaction = () => <>🙂; + +// subset of clickable options available to the user +const selectedReactionOptions = [ + { type: 'haha', Component: JoyReaction }, + { type: 'cat', Component: CatReaction }, +]; + +// set of all available options to be rendered +const completeReactionOptions = [ + { type: 'haha', Component: JoyReaction }, + { type: 'cat', Component: CatReaction }, + { type: '+1', Component: ThumbsUpReaction }, + { type: 'smile', Component: SmileReaction }, +]; +``` + +Or if you just want bigger icons for `ReactionsList` while `ReactionSelector` uses regular: + +```tsx +// arbitrary import (does not come with the SDK) +import { ReactionComponent } from './CustomReactions'; + +const selectorReactionOptions = [ + { + type: 'like', + component: ReactionComponent.Like, + name: 'Like', + }, +]; + +const listReactionOptions = [ + { + type: 'like', + // in this example it's just different size of the emoji + component: ReactionComponent.LikeMedium, + name: 'Like medium', + }, +]; +``` + +You can then apply these new options to `ReactionSelector` and `ReactionsList` directly: + +```tsx +import { ReactionSelector, ReactionsList, Channel } from 'stream-chat-react'; + +// ReactionSelector component requires forwarded reference +const CustomReactionSelector = forwardRef((props, ref) => ( + +)); + +const CustomReactionsList = (props) => ( + +); +``` + +And then pass them down to component context (`Channel`) component: + +```tsx + + {/*...*/} + +``` + +## Use of `SpriteImage` component + +:::note +We suggest using individual images per reaction type as multiple smaller requests is more bandwidth-friendly. Use this component only if you have no other choice. +::: + +If you have a sprite sheet of emojis and there's no other way for you to implement your reactions, you can utilise utility component which comes with the SDK: + +```tsx +import { SpriteImage } from 'stream-chat-react'; + +const SPRITE_URL = 'https://getstream.imgix.net/images/emoji-sprite.png'; + +const reactionOptions = [ + { + type: 'joy', + component: () => ( + // renders fallback initially and then image when it successfully loads + + ), + name: 'ROFL', + }, +]; + +// pass reaction options to component context (Channel) or to ReactionSelector and ReactionsList +``` + +## Transition from previous version of custom reactions + +### Default setup + +The transition is super easy: + +```tsx +import { defaultReactionOptions } from 'stream-chat-react'; + +// old custom options +const reactionOptions = [{ id: 'bulb' /* ...extra properties... */ }, { id: '+1' }, { id: 'joy' }]; + +// would newly become +const newReactionOptions = [ + { type: 'bulb', Component: () => <>💡, name: 'Bulb reaction' }, + { type: '+1', Component: () => <>👍 }, + { type: 'joy', Component: () => <>🤣, name: 'ROFL' }, + // reuse default ones if you want to + ...defaultReactionOptions, +]; +``` + +All of the extra options previously applied to `EmojiMart` emojis can now be directly applied to your custom components either manually or through your custom context. For more information see [EmojiMart integration](#emoji-mart-integration). + +### Re-enabling `angry` reaction + +For better compatibility with other SDKs we decided to consolidate default available types and remove `angry` type which was previously available only in the React SDK. Here's how you'd go about re-enabling it: + +```tsx +import { StreamEmoji, defaultReactionOptions } from 'stream-chat-react'; + +const reactionOptions = [ + ...defaultReactionOptions, + { type: 'angry', Component: () => , name: 'Angry' }, +]; + +// pass reaction options to component context (Channel) or to ReactionSelector and ReactionsList +``` diff --git a/src/components/Channel/Channel.tsx b/src/components/Channel/Channel.tsx index fa4c2c10b..e91afee3e 100644 --- a/src/components/Channel/Channel.tsx +++ b/src/components/Channel/Channel.tsx @@ -93,6 +93,10 @@ import { getVideoAttachmentConfiguration, } from '../Attachment/attachment-sizing'; import type { URLEnrichmentConfig } from '../MessageInput/hooks/useLinkPreviews'; +import { + defaultReactionOptions, + ReactionOptions, +} from '../../components/Reactions/reactionOptions'; type ChannelPropsForwardedToComponentContext< StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics @@ -159,6 +163,8 @@ type ChannelPropsForwardedToComponentContext< QuotedMessage?: ComponentContextValue['QuotedMessage']; /** Custom UI component to override the message input's quoted message preview, defaults to and accepts same props as: [QuotedMessagePreview](https://github.com/GetStream/stream-chat-react/blob/master/src/components/MessageInput/QuotedMessagePreview.tsx) */ QuotedMessagePreview?: ComponentContextValue['QuotedMessagePreview']; + /** Custom reaction options to be applied to ReactionSelector, ReactionList and SimpleReactionList components */ + reactionOptions?: ReactionOptions; /** Custom UI component to display the reaction selector, defaults to and accepts same props as: [ReactionSelector](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Reactions/ReactionSelector.tsx) */ ReactionSelector?: ComponentContextValue['ReactionSelector']; /** Custom UI component to display the list of reactions on a message, defaults to and accepts same props as: [ReactionsList](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Reactions/ReactionsList.tsx) */ @@ -180,8 +186,6 @@ type ChannelPropsForwardedToComponentContext< }; type ChannelPropsForwardedToEmojiContext = { - /** Custom UI component to override default `NimbleEmoji` from `emoji-mart` */ - Emoji?: EmojiContextValue['Emoji']; /** Custom prop to override default `facebook.json` emoji data set from `emoji-mart` */ emojiData?: EmojiMartData; /** Custom UI component to override default `NimbleEmojiIndex` from `emoji-mart` */ @@ -1037,6 +1041,7 @@ const ChannelInner = < PinIndicator: props.PinIndicator, QuotedMessage: props.QuotedMessage, QuotedMessagePreview: props.QuotedMessagePreview, + reactionOptions: props.reactionOptions ?? defaultReactionOptions, ReactionSelector: props.ReactionSelector, ReactionsList: props.ReactionsList, SendButton: props.SendButton, @@ -1047,12 +1052,11 @@ const ChannelInner = < TypingIndicator: props.TypingIndicator, VirtualMessage: props.VirtualMessage, }), - [], + [props.reactionOptions], ); const emojiContextValue: EmojiContextValue = useMemo( () => ({ - Emoji: props.Emoji, emojiConfig, EmojiIndex: props.EmojiIndex, EmojiPicker: props.EmojiPicker, diff --git a/src/components/Channel/__tests__/Channel.test.js b/src/components/Channel/__tests__/Channel.test.js index dc145ed0c..9bfba4818 100644 --- a/src/components/Channel/__tests__/Channel.test.js +++ b/src/components/Channel/__tests__/Channel.test.js @@ -548,20 +548,15 @@ describe('Channel', () => { emojis: {}, }; const CustomEmojiPicker = () =>
; - const CustomEmoji = () => ; - renderComponent( - { channel, chatClient, Emoji: CustomEmoji, emojiData, EmojiPicker: CustomEmojiPicker }, - (ctx) => { - context = ctx; - }, - ); + renderComponent({ channel, chatClient, emojiData, EmojiPicker: CustomEmojiPicker }, (ctx) => { + context = ctx; + }); await waitFor(() => { expect(context).toBeInstanceOf(Object); expect(context.emojiConfig.emojiData).toBe(emojiData); expect(context.EmojiPicker).toBe(CustomEmojiPicker); - expect(context.Emoji).toBe(CustomEmoji); }); }); diff --git a/src/components/Message/__tests__/MessageSimple.test.js b/src/components/Message/__tests__/MessageSimple.test.js index 2166d780c..e565acf3d 100644 --- a/src/components/Message/__tests__/MessageSimple.test.js +++ b/src/components/Message/__tests__/MessageSimple.test.js @@ -19,18 +19,16 @@ import { EditMessageForm, MessageInput as MessageInputMock } from '../../Message import { getReadStates } from '../../MessageList'; import { MML as MMLMock } from '../../MML'; import { Modal as ModalMock } from '../../Modal'; +import { defaultReactionOptions } from '../../Reactions'; import { ChannelActionProvider, ChannelStateProvider, ChatProvider, ComponentProvider, - EmojiProvider, TranslationProvider, } from '../../../context'; import { - emojiComponentMock, - emojiDataMock, generateChannel, generateMessage, generateReaction, @@ -75,9 +73,7 @@ async function renderMessageSimple({ return renderer( - + @@ -87,25 +83,17 @@ async function renderMessageSimple({ Attachment: AttachmentMock, // eslint-disable-next-line react/display-name Message: () => , + reactionOptions: defaultReactionOptions, ...components, }} > - - Object.keys(MESSAGE_ACTIONS)} - isMyMessage={() => true} - message={message} - threadList={false} - {...props} - /> - + Object.keys(MESSAGE_ACTIONS)} + isMyMessage={() => true} + message={message} + threadList={false} + {...props} + /> diff --git a/src/components/Message/__tests__/MessageText.test.js b/src/components/Message/__tests__/MessageText.test.js index 37325f71b..da1eb8b9b 100644 --- a/src/components/Message/__tests__/MessageText.test.js +++ b/src/components/Message/__tests__/MessageText.test.js @@ -25,6 +25,7 @@ import { } from '../../../mock-builders'; import { Attachment } from '../../Attachment'; +import { defaultReactionOptions } from '../../Reactions'; import { Message } from '../Message'; import { MessageOptions as MessageOptionsMock } from '../MessageOptions'; import { MessageSimple } from '../MessageSimple'; @@ -89,6 +90,7 @@ async function renderMessageText({ Emoji: EmojiComponentMock, // eslint-disable-next-line react/display-name Message: () => , + reactionOptions: defaultReactionOptions, }} > diff --git a/src/components/Reactions/ReactionSelector.tsx b/src/components/Reactions/ReactionSelector.tsx index 332dd16e9..685b17023 100644 --- a/src/components/Reactions/ReactionSelector.tsx +++ b/src/components/Reactions/ReactionSelector.tsx @@ -1,25 +1,21 @@ -import React, { Suspense, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import clsx from 'clsx'; import { isMutableRef } from './utils/utils'; import { AvatarProps, Avatar as DefaultAvatar } from '../Avatar'; -import { getStrippedEmojiData, ReactionEmoji } from '../Channel/emojiData'; import { useComponentContext } from '../../context/ComponentContext'; -import { useEmojiContext } from '../../context/EmojiContext'; import { useMessageContext } from '../../context/MessageContext'; -import type { NimbleEmojiProps } from 'emoji-mart'; import type { ReactionResponse } from 'stream-chat'; import type { DefaultStreamChatGenerics } from '../../types/types'; +import type { ReactionOptions } from './reactionOptions'; export type ReactionSelectorProps< StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics > = { - /** Additional props to be passed to the [NimbleEmoji](https://github.com/missive/emoji-mart/blob/master/src/components/emoji/nimble-emoji.js) component from `emoji-mart` */ - additionalEmojiProps?: Partial; /** Custom UI component to display user avatar, defaults to and accepts same props as: [Avatar](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Avatar/Avatar.tsx) */ Avatar?: React.ElementType; /** If true, shows the user's avatar with the reaction */ @@ -31,9 +27,9 @@ export type ReactionSelectorProps< /** An array of the own reaction objects to distinguish own reactions visually */ own_reactions?: ReactionResponse[]; /** An object that keeps track of the count of each type of reaction on a message */ - reaction_counts?: { [key: string]: number }; + reaction_counts?: Record; /** A list of the currently supported reactions on a message */ - reactionOptions?: ReactionEmoji[]; + reactionOptions?: ReactionOptions; /** If true, adds a CSS class that reverses the horizontal positioning of the selector */ reverse?: boolean; }; @@ -44,7 +40,6 @@ const UnMemoizedReactionSelector = React.forwardRef( ref: React.ForwardedRef, ) => { const { - additionalEmojiProps = {}, Avatar: propAvatar, detailedView = true, handleReaction: propHandleReaction, @@ -55,27 +50,22 @@ const UnMemoizedReactionSelector = React.forwardRef( reverse = false, } = props; - const { Avatar: contextAvatar } = useComponentContext('ReactionSelector'); - const { Emoji, emojiConfig } = useEmojiContext('ReactionSelector'); + const { + Avatar: contextAvatar, + reactionOptions: contextReactionOptions, + } = useComponentContext('ReactionSelector'); const { handleReaction: contextHandleReaction, message, } = useMessageContext('ReactionSelector'); - const { defaultMinimalEmojis, emojiData: fullEmojiData, emojiSetDef } = emojiConfig || {}; + const reactionOptions = propReactionOptions ?? contextReactionOptions; const Avatar = propAvatar || contextAvatar || DefaultAvatar; const handleReaction = propHandleReaction || contextHandleReaction; const latestReactions = propLatestReactions || message?.latest_reactions || []; const ownReactions = propOwnReactions || message?.own_reactions || []; const reactionCounts = propReactionCounts || message?.reaction_counts || {}; - const reactionOptions = propReactionOptions || defaultMinimalEmojis; - const reactionsAreCustom = !!propReactionOptions?.length; - - const emojiData = useMemo( - () => (reactionsAreCustom ? fullEmojiData : getStrippedEmojiData(fullEmojiData)), - [fullEmojiData, reactionsAreCustom], - ); const [tooltipReactionType, setTooltipReactionType] = useState(null); const [tooltipPositions, setTooltipPositions] = useState<{ @@ -165,29 +155,29 @@ const UnMemoizedReactionSelector = React.forwardRef(
)}
    - {reactionOptions.map((reactionOption: ReactionEmoji) => { - const latestUser = getLatestUserForReactionType(reactionOption.id); - const count = reactionCounts && reactionCounts[reactionOption.id]; + {reactionOptions.map(({ Component, name: reactionName, type: reactionType }) => { + const latestUser = getLatestUserForReactionType(reactionType); + const count = reactionCounts && reactionCounts[reactionType]; return ( -
  • +