diff --git a/docusaurus/docs/React/assets/search-results-empty-theme-v2.png b/docusaurus/docs/React/assets/search-results-empty-theme.png similarity index 100% rename from docusaurus/docs/React/assets/search-results-empty-theme-v2.png rename to docusaurus/docs/React/assets/search-results-empty-theme.png diff --git a/docusaurus/docs/React/assets/search-results-inline-theme-v2.png b/docusaurus/docs/React/assets/search-results-inline-theme.png similarity index 100% rename from docusaurus/docs/React/assets/search-results-inline-theme-v2.png rename to docusaurus/docs/React/assets/search-results-inline-theme.png diff --git a/docusaurus/docs/React/assets/search-results-loading-theme-v2.png b/docusaurus/docs/React/assets/search-results-loading-theme.png similarity index 100% rename from docusaurus/docs/React/assets/search-results-loading-theme-v2.png rename to docusaurus/docs/React/assets/search-results-loading-theme.png diff --git a/docusaurus/docs/React/assets/search-results-popup-theme-v2.png b/docusaurus/docs/React/assets/search-results-popup-theme.png similarity index 100% rename from docusaurus/docs/React/assets/search-results-popup-theme-v2.png rename to docusaurus/docs/React/assets/search-results-popup-theme.png diff --git a/docusaurus/docs/React/basics/overview.mdx b/docusaurus/docs/React/basics/overview.mdx index 666e49ab4..490b83369 100644 --- a/docusaurus/docs/React/basics/overview.mdx +++ b/docusaurus/docs/React/basics/overview.mdx @@ -14,12 +14,13 @@ Use cases include team and social messaging, virtual events, livestream gaming, - Text input commands (ex: Giphy and @mentions) - Image and file uploads - Video playback +- Audio recording - Read state and typing indicators - Channel and message lists ## Where to get started -If you are new to our SDK it is best to go through a of our [tutorial](https://getstream.io/chat/react-chat/tutorial/). +If you are new to our SDK it is best to go through our [tutorial](https://getstream.io/chat/react-chat/tutorial/). After that, our [getting started page](./getting-started.mdx) is a great next step. @@ -32,4 +33,4 @@ If you are integrating our SDK, please pay attention to our [Theming](../theming A common pattern in the library is the use of context provider hooks. These custom hooks allow for effective value sharing between parent components and their children. This makes customization straightforward, as you can use our exported hooks in your custom components to receive the exact values needed, while also subscribing to context changes. -The left navigation will guide you to the various documentation sections for information on everything regarding our robust component library. Check out the instructions below for adding the library to your React project. +The left navigation will guide you to the various documentation sections for information on everything regarding our robust component library. Check out the instructions for adding the library to your React project. diff --git a/docusaurus/docs/React/components/contexts/channel-state-context.mdx b/docusaurus/docs/React/components/contexts/channel-state-context.mdx index c153e1a3b..54e761fef 100644 --- a/docusaurus/docs/React/components/contexts/channel-state-context.mdx +++ b/docusaurus/docs/React/components/contexts/channel-state-context.mdx @@ -18,7 +18,7 @@ const { channel, watchers } = useChannelStateContext(); ### acceptedFiles -A list of accepted file upload types. +The value is forwarded to the context from the `Channel` component [prop `acceptedFiles`](../../components/core-components/channel.mdx#acceptedfiles). | Type | | -------- | @@ -48,9 +48,24 @@ The configurations object for the currently active channel. | ------ | | object | +### channelUnreadUiState + +The read state maintained for use by components representing channel unread state (for example `UnreadMessagesSeparator`, `UnreadMessagesNotification`). + +| Property | Type | Description | +| --------------------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **last_read** | `Date` | Date when the channel was marked read the last time. | +| **unread_messages** | `number` | The count of unread messages in a given channel. Unread count refers only to foreign (not own) unread messages. | +| **first_unread_message_id** | `string` or `undefined` | The ID of the message that was marked unread (`notification.mark_unread` event). The value is available only when a message is marked unread. Therefore, cannot be relied on to place unread messages UI. | +| **last_read_message_id** | `string` or `undefined` | The ID of the message preceding the first unread message. | + +| Type | +| ---------------------- | +| `ChannelUnreadUiState` | + ### dragAndDropWindow -If true, chat users will be able to drag and drop file uploads to the entire channel window. +The value is forwarded to the context from the `Channel` component [prop `dragAndDropWindow`](../../components/core-components/channel.mdx#draganddropwindow). | Type | Default | | ------- | ------- | @@ -66,8 +81,7 @@ Number of milliseconds to debounce firing the URL enrichment queries when typing ### enrichURLForPreview -A global flag to toggle the URL enrichment and link previews in `MessageInput`. By default, the feature is disabled. It can be overridden on Thread and MessageList level through `additionalMessageInputProps` -or directly on `MessageInput` level through `urlEnrichmentConfig` prop. +The value is forwarded to the context from the `Channel` component [prop `enrichURLForPreview`](../../components/core-components/channel.mdx#enrichurlforpreview). | Type | Default | | ------- | ------- | @@ -91,18 +105,18 @@ Custom function to identify URLs in a string for later generation of link previe ### giphyVersion -The giphy version to use when displaying giphies. +The value is forwarded to the context from the `Channel` component [prop `giphyVersion`](../../components/core-components/channel.mdx#giphyversion). -| Type | -| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `'original'` \| `'fixed_height'` \| `'fixed_height_still'` \| `'fixed_height_downsampled'` \| `'fixed_width'` \| `'fixed_width_still'` \| `'fixed_width_downsampled'` | +| Type | Default | +| ------ | -------------- | +| string | 'fixed_height' | ### imageAttachmentSizeHandler -A custom function to provide size configuration for image attachments +The value is forwarded to the context from the `Channel` component [prop `imageAttachmentSizeHandler`](../../components/core-components/channel.mdx#imageattachmentsizehandler). -| Type | -| ---------------------------------------------------------------- | +| Type | +| ----------------------------------------------------------------- | | `(a: Attachment, e: HTMLElement) => ImageAttachmentConfiguration` | ### hasMore @@ -145,7 +159,7 @@ Boolean for the `channel` loading more messages. | ------- | | boolean | -### loadingMoreNewer? +### loadingMoreNewer Flag signalling whether newer messages are being loaded as the user scrolls down in the message list. Used internally by `VirtualizedMessageList`. @@ -155,7 +169,7 @@ Flag signalling whether newer messages are being loaded as the user scrolls down ### maxNumberOfFiles -The maximum number of attachments allowed per `message`, defaults to the Stream Chat API maximum. +The value is forwarded to the context from the `Channel` component [prop `maxNumberOfFiles`](../../components/core-components/channel.mdx#maxnumberoffiles). | Type | Default | | ------ | ------- | @@ -179,7 +193,7 @@ Array of [message objects](https://getstream.io/chat/docs/javascript/message_for ### multipleUploads -Whether to allow multiple attachment uploads on a message. +The value is forwarded to the context from the `Channel` component [prop `multipleUploads`](../../components/core-components/channel.mdx#multipleuploads). | Type | Default | | ------- | ------- | @@ -209,21 +223,6 @@ Custom function to react to link preview dismissal. See the guide [Link Previews | ------------------------------------ | | `(linkPreview: LinkPreview) => void` | -### channelUnreadUiState - -The read state maintained for use by components representing channel unread state (for example `UnreadMessagesSeparator`, `UnreadMessagesNotification`). - -| Property | Type | Description | -|-----------------------------|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **last_read** | `Date` | Date when the channel was marked read the last time. | -| **unread_messages** | `number` | The count of unread messages in a given channel. Unread count refers only to foreign (not own) unread messages. | -| **first_unread_message_id** | `string` or `undefined` | The ID of the message that was marked unread (`notification.mark_unread` event). The value is available only when a message is marked unread. Therefore, cannot be relied on to place unread messages UI. | -| **last_read_message_id** | `string` or `undefined` | The ID of the message preceding the first unread message. | - -| Type | -|-----------------------| -| `ChannelUnreadUiState` | - ### pinnedMessages The messages that are pinned in the `channel`. @@ -258,7 +257,7 @@ Flag signalling whether the scroll to the bottom is prevented. Used internally b ### shouldGenerateVideoThumbnail -You can turn on/off thumbnail generation for video attachments +The value is forwarded to the context from the `Channel` component [prop `shouldGenerateVideoThumbnail`](../../components/core-components/channel.mdx#shouldgeneratevideothumbnail). | Type | | --------- | @@ -306,7 +305,7 @@ Flag signalling whether the scroll to the bottom is prevented in thread. Used in ### videoAttachmentSizeHandler -A custom function to provide size configuration for video attachments +The value is forwarded to the context from the `Channel` component [prop `videoAttachmentSizeHandler`](../../components/core-components/channel.mdx#videoattachmentsizehandler). | Type | | ----------------------------------------------------------------- | diff --git a/docusaurus/docs/React/components/contexts/chat-context.mdx b/docusaurus/docs/React/components/contexts/chat-context.mdx index 3ac710535..fd54d3fe8 100644 --- a/docusaurus/docs/React/components/contexts/chat-context.mdx +++ b/docusaurus/docs/React/components/contexts/chat-context.mdx @@ -18,7 +18,7 @@ const { client, setActiveChannel } = useChatContext(); ### client -The `StreamChat` client instance. Any methods from the `stream-chat-js` API interface can be run off this object. +The value is forwarded to the context from the `Chat` component [prop `client`](../../components/core-components/chat.mdx#client). | Type | | ------ | @@ -49,7 +49,7 @@ The `queryInProgress` values are: - `null` - at least one channels page has been loaded and there is no query in progress at the moment | Type | -|----------------------| +| -------------------- | | `ChannelsQueryState` | ### closeMobileNav @@ -62,8 +62,7 @@ The function to close mobile navigation. ### customClasses -Object containing custom CSS classnames to override the library's default container CSS. See [CSS and Theming](../../guides/theming/css-and-theming.mdx) -for implementation assistance. +The value is forwarded to the context from the `Chat` component [prop `customClasses`](../../components/core-components/chat.mdx#customclasses) | Type | | ------ | @@ -120,25 +119,15 @@ You can override the default behavior by pulling it from context and then utiliz ### theme -Deprecated and to be removed in a future major release. Use the `customStyles` prop to adjust CSS variables and [customize the theme](../../guides/theming/css-and-theming.mdx#css-variables) of your app. +The value is forwarded to the context from the `Chat` component [prop `theme`](../../components/core-components/chat.mdx#theme) -| Type | -| ----- | -| Theme | - -### themeVersion - -Stream chat theme version 2 has been introduced with the release of stream-chat-react v10.0.0. This flag is used internally by some UI components of the SDK and the integrators shouldn't need to use it. The value is extracted from a CSS variable `--str-chat__theme-version`. You can set it to values `'1'` or `'2'` in your stylesheets and import the corresponding v2 stylesheet from `stream-chat-react/dist`. Find out more about benefits that the theme version 2 brings to the integrators with [the theming guide](../../theming/introduction.mdx). - -| Type | Default | -| -------------- | ------- | -| `'1'` \| `'2'` | `'1'` | +| Type | +| ------ | +| string | ### useImageFlagEmojisOnWindow -Windows 10 does not support country flag emojis out of the box. It chooses to render these emojis as characters instead. -Stream Chat can override this behavior by loading a custom web font that will render images instead (PNGs or SVGs depending -on the platform). Set this prop to true if you want to use these custom emojis for Windows users. +The value is forwarded to the context from the `Chat` component [prop `useImageFlagEmojisOnWindow`](../../components/core-components/chat.mdx#useimageflagemojisonwindow). | Type | Default | | ------- | ------- | diff --git a/docusaurus/docs/React/components/contexts/component-context.mdx b/docusaurus/docs/React/components/contexts/component-context.mdx index 3968c483a..0dedce6ab 100644 --- a/docusaurus/docs/React/components/contexts/component-context.mdx +++ b/docusaurus/docs/React/components/contexts/component-context.mdx @@ -36,14 +36,6 @@ Custom UI component to display a attachment previews in `MessageInput`. | --------- | ---------------------------------------------------------------------------------------------- | | component | | -### AutocompleteSuggestionHeader - -Custom UI component to override the default suggestion header component. - -| Type | Default | -| --------- | ------------------------------------------------------------------------ | -| component | | - ### AutocompleteSuggestionItem Custom UI component to override the default suggestion Item component. @@ -346,11 +338,11 @@ Custom UI component to display the header of a `Thread`. ### ThreadInput -Custom UI component to replace the `MessageInput` of a `Thread`. For the applications using [theme version 1](../../guides/theming/css-and-theming.mdx), the default is `MessageInputSmall`. Applications using [theme version 2](../../theming/introduction.mdx) will use `MessageInputFlat` by default. +Custom UI component to replace the `MessageInput` of a `Thread`. The component uses `MessageInputFlat` by default. -| Type | Default | -| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| component | / | +| Type | Default | +| --------- | ------------------------------------------------------------------------------------ | +| component | | ### ThreadStart diff --git a/docusaurus/docs/React/components/core-components/channel.mdx b/docusaurus/docs/React/components/core-components/channel.mdx index a852f5209..ad0cc3b35 100644 --- a/docusaurus/docs/React/components/core-components/channel.mdx +++ b/docusaurus/docs/React/components/core-components/channel.mdx @@ -6,7 +6,7 @@ title: Channel import GHComponentLink from '../../_docusaurus-components/GHComponentLink'; The `Channel` component is a React Context provider that wraps all the logic, functionality, and UI for an individual chat channel. -It provides five separate contexts to its children: +It provides four separate contexts to its children: - [`ChannelStateContext`](../contexts/channel-state-context.mdx) - stateful data (ex: `messages` or `members`) - [`ChannelActionContext`](../contexts/channel-action-context.mdx) - action handlers (ex: `sendMessage` or `openThread`) @@ -142,14 +142,6 @@ Custom UI component to display an attachment previews in `MessageInput`. | --------- | ---------------------------------------------------------------------------------------------- | | component | | -### AutocompleteSuggestionHeader - -Custom UI component to override the default suggestion header component. - -| Type | Default | -| --------- | ------------------------------------------------------------------------ | -| component | | - ### AutocompleteSuggestionItem Custom UI component to override the default suggestion Item component. @@ -439,14 +431,6 @@ export const MessageInput = (props: MessageInputProps) => { | ------- | ------- | | boolean | true | -### markReadOnMount - -Configuration parameter to mark the active channel as read when mounted (opened). By default, the channel is marked read on mount. - -| Type | Default | -| ------- | ------- | -| boolean | true | - ### Input Custom UI component handling how the message input is rendered. @@ -479,6 +463,14 @@ Custom UI component to render while the `MessageList` is loading new messages. | --------- | ------------------------------------------------------------------------------- | | component | | +### markReadOnMount + +Configuration parameter to mark the active channel as read when mounted (opened). By default, the channel is marked read on mount. + +| Type | Default | +| ------- | ------- | +| boolean | true | + ### maxNumberOfFiles The maximum number of attachments allowed per message, defaults to the Stream Chat API maximum. @@ -691,11 +683,11 @@ Custom UI component to display the header of a `Thread`. ### ThreadInput -Custom UI component to replace the `MessageInput` of a `Thread`. For the applications using [theme version 1](../../guides/theming/css-and-theming.mdx), the default is `MessageInputSmall`. Applications using [theme version 2](../../theming/introduction.mdx) will use `MessageInputFlat` by default. +Custom UI component to replace the `MessageInput` of a `Thread`. The component uses `MessageInputFlat` by default. -| Type | Default | -| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| component | / | +| Type | Default | +| --------- | ------------------------------------------------------------------------------------ | +| component | | ### ThreadStart diff --git a/docusaurus/docs/React/components/core-components/chat.mdx b/docusaurus/docs/React/components/core-components/chat.mdx index 0740a33e8..91d0a015d 100644 --- a/docusaurus/docs/React/components/core-components/chat.mdx +++ b/docusaurus/docs/React/components/core-components/chat.mdx @@ -46,30 +46,55 @@ const channel = client.channel('messaging', { ### customClasses -Object containing custom CSS classnames to override the library's default container CSS. See [CSS and Theming](../../guides/theming/css-and-theming.mdx) -for implementation assistance. +Object containing custom CSS classnames to override the library's default container CSS. Many of the high level React components in the library come with predefined CSS container classes that inject basic display styling. +To remove or replace these wrapper classes entirely, the `Chat` component takes a `customClasses` prop. This prop accepts a mapping of overridable container classnames. + +In the below example we will replace two of the default container classes, `str-chat` (maps to the `chat` key) and +`str-chat-channel` (maps to the `channel`) key. Once replaced, add whatever styles you want in your own stylesheets. + +```tsx +const customClasses: CustomClasses = { + chat: 'custom-chat-class', + channel: 'custom-channel-class', +}; + +const App = () => ( + + + + + + + + + + + +); +``` -| Type | -| ------ | -| object | +The accepted object keys and the default classnames they override are as follows: -### customStyles +- chat - `str-chat` +- chatContainer - `str-chat__container` +- channel - `str-chat-channel` +- channelList - `str-chat-channel-list` +- message - `str-chat__li str-chat__li--${groupStyles}` +- messageList - `str-chat__list` +- thread - `str-chat__thread` +- threadList - `str-chat__list--thread` +- virtualMessage - `str-chat__virtual-list-message-wrapper` +- virtualizedMessageList - `str-chat__virtual-list` -Object containing custom styles to override the default CSS variables. See [CSS and Theming](../../guides/theming/css-and-theming.mdx) -for implementation assistance. +:::caution +Be careful overriding the default styles on the `VirtualizedMessageList` component, as our defaults handle much of the logic +that makes the list UI perform optimally. +::: | Type | | ------ | | object | -### darkMode - -If true, toggles the CSS variables to the default dark mode color palette. - -| Type | Default | -| ------- | ------- | -| boolean | false | - ### defaultLanguage Sets the default fallback language for UI component translation, defaults to 'en' for English. @@ -126,11 +151,11 @@ Here, the list will take the whole width of the screen on small devices once the ### theme -Deprecated and to be removed in a future major release. Use the `customStyles` prop to adjust CSS variables and [customize the theme](../../guides/theming/css-and-theming.mdx#css-variables) of your app. +Used for injecting className/s to the `Channel` and `ChannelList` components. -| Type | -| ----- | -| Theme | +| Type | +| ------ | +| string | ### useImageFlagEmojisOnWindows @@ -139,7 +164,7 @@ Stream Chat can override this behavior by loading a custom web font that will re on the platform). Set this prop to true if you want to use these custom emojis for Windows users. :::caution -If you're moving from older versions to `11.0.0` then make sure to import related stylesheet from `stream-chat-react/css/v2/emoji-replacement.css` as it has been removed from our main stylesheet to reduce final bundle size for integrators who do not wish to use this feature. +If you're moving from older versions to `11.0.0` then make sure to import related stylesheet from `stream-chat-react/css/emoji-replacement.css` as it has been removed from our main stylesheet to reduce final bundle size for integrators who do not wish to use this feature. ::: | Type | Default | diff --git a/docusaurus/docs/React/components/core-components/thread.mdx b/docusaurus/docs/React/components/core-components/thread.mdx index fc7873e96..7b419f463 100644 --- a/docusaurus/docs/React/components/core-components/thread.mdx +++ b/docusaurus/docs/React/components/core-components/thread.mdx @@ -179,11 +179,11 @@ If true, displays the thread at 100% width of its parent container, useful for m ### Input -Custom thread input UI component used to override the optional `Input` value stored in `ComponentContext` or the default. For the applications using [theme version 1](../../guides/theming/css-and-theming.mdx), the default is `MessageInputSmall`. Applications using [theme version 2](../../theming/introduction.mdx) will use `MessageInputFlat` by default. +Custom UI component to replace the `MessageInput` of a `Thread`. The component uses `MessageInputFlat` by default. -| Type | Default | -| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| component | / | +| Type | Default | +| --------- | ------------------------------------------------------------------------------------ | +| component | | ### Message diff --git a/docusaurus/docs/React/components/message-components/attachment.mdx b/docusaurus/docs/React/components/message-components/attachment.mdx index 6da230237..27f06ed86 100644 --- a/docusaurus/docs/React/components/message-components/attachment.mdx +++ b/docusaurus/docs/React/components/message-components/attachment.mdx @@ -110,7 +110,7 @@ The following section details how the width and height of images and videos uplo #### Maximum size -You can control the maximum width and height of images and videos with the [`--str-chat__attachment-max-width`](../../theming/component-variables.mdx) CSS variable (available only in [theme-v2](../../theming/introduction.mdx)). The value of this variable must be a value that can be computed to a valid pixel value using the [`getComputedStyle`](https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle) method (for example: `300px`, `10rem`, `calc(300px - var(--margin))`, but not `100%`). If you provide an invalid value, the image and video sizing can break, which can lead to scrolling issues inside the message list (for example the message list isn't scrolled to the bottom when you open a channel). +You can control the maximum width and height of images and videos with the [`--str-chat__attachment-max-width`](../../theming/component-variables.mdx) CSS variable. The value of this variable must be a value that can be computed to a valid pixel value using the [`getComputedStyle`](https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle) method (for example: `300px`, `10rem`, `calc(300px - var(--margin))`, but not `100%`). If you provide an invalid value, the image and video sizing can break, which can lead to scrolling issues inside the message list (for example the message list isn't scrolled to the bottom when you open a channel). If you set an invalid value to the variable, you'll see a warning on the browser's console: @@ -124,8 +124,6 @@ For example if an image has `max-width` and `max-height` set to `300px` and the #### Aspect ratio -The following description is applicable for [theme-v2](../../theming/introduction.mdx). - The SDK will try to display images and videos with their original aspect ratio, however this isn't always guaranteed (in those cases a cropped image will be displayed). Three notable exceptions are: 1. if a message contains multiple lines of texts and/or multiple attachments, the image/video might be stretched to its `max-width` diff --git a/docusaurus/docs/React/components/message-components/message-ui.mdx b/docusaurus/docs/React/components/message-components/message-ui.mdx index 48023cc61..e8ad602d3 100644 --- a/docusaurus/docs/React/components/message-components/message-ui.mdx +++ b/docusaurus/docs/React/components/message-components/message-ui.mdx @@ -59,34 +59,7 @@ const CustomMessage = () => { `MessageSimple` and `FixedHeightMessage` are both designed to be guides to help build a custom Message UI component. At a high level, these pre-built, default components wrap a subset of composable components that each serve specific logic and design-based purposes. -There is a different order in which components are stacked inside the `MessageSimple` component depending on the [`themeVersion`](../contexts/chat-context.mdx/#themeversion). - -For example, if we strip `MessageSimple` down to its core pieces, the component resembles the following snippet with the `themeVersion` `'1'`: - -```jsx -
- - -
- -
- - -
-
- - - -
- -
- -
-
-
-``` - -The `themeVersion` `'2'` markup is a bit different: +If we strip `MessageSimple` down to its core pieces, the component resembles the following snippet: ```jsx
@@ -308,11 +281,10 @@ Function that flags a message (overrides the function stored in `MessageContext` Function that marks the message and all the following messages as unread in a channel. (overrides the function stored in `MessageContext`). -| Type | Default | -| ----------------------------------------------------------- | ------------------------------------------------------------------------------- | +| Type | Default | +| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------- | | (event: React.BaseSyntheticEvent) => Promise \| void | [MessageContextValue['handleMarkUnread']](../contexts/message-context.mdx#handleMarkUnread) | - ### handleMute Function that mutes the sender of a message (overrides the function stored in `MessageContext`). diff --git a/docusaurus/docs/React/components/message-input-components/input-ui.mdx b/docusaurus/docs/React/components/message-input-components/input-ui.mdx index 67b40760b..52e664e9c 100644 --- a/docusaurus/docs/React/components/message-input-components/input-ui.mdx +++ b/docusaurus/docs/React/components/message-input-components/input-ui.mdx @@ -51,10 +51,6 @@ For example, if we strip `MessageInputFlat` down to its core pieces, the compone
``` -:::note -`ImageDropzone` and `FileUploadButton` are imported from ['react-file-utils'](https://www.npmjs.com/package/react-file-utils). -::: - We recommend building an Input UI component in a similar way. You can mix and match any of the UI subcomponents and arrange in a layout that meets your design specifications. All of these UI subcomponents are exported by the library and may be used within your custom Input UI component. Each subcomponent consumes the `MessageInputContext` and requires no/minimal props to run. diff --git a/docusaurus/docs/React/components/utility-components/avatar.mdx b/docusaurus/docs/React/components/utility-components/avatar.mdx index 4ef2d7874..3236cb522 100644 --- a/docusaurus/docs/React/components/utility-components/avatar.mdx +++ b/docusaurus/docs/React/components/utility-components/avatar.mdx @@ -3,48 +3,38 @@ id: avatar title: Avatar --- -The `Avatar` component displays a user's image, with fallback to the first letter of the optional name prop. +The `Avatar` component displays an image, with fallback to the first letter of the optional name prop. ## Basic Usage A typical use case for the `Avatar` component would be to import and use in your custom components that will completely override a header component, preview component, or similar. -**Example 1** - Here's an example of using the `Avatar` component within a custom preview component: +Here's an example of using the `Avatar` component within a custom preview component: ```tsx import { Avatar } from 'stream-chat-react'; const YourCustomChannelPreview = (props) => { return ( - ; -
Other channel info needed in the preview
- ) +
+ +
Other channel info needed in the preview
+
+ ); }; - -``` - -**Example 2** - a basic example with rounded shape: - -```tsx -import { Avatar } from './Avatar'; -const image = 'https://pbs.twimg.com/profile_images/897621870069112832/dFGq6aiE_400x400.jpg'; -const name = 'roy'; - -; +; ``` ## UI Customization -You can also take advantage of the `Avatar` props on the `ChannelHeader` and `ChannelList` components to override just that aspect of these components specifically, see the example below. +You can also take advantage of the `Avatar` prop on the `ChannelHeader` and `ChannelList` components to override just that aspect of these components specifically, see the example below. -**Example 3** - an example of overriding just the `Avatar` component in the default `ChannelPreviewMessenger` component. +An example of overriding just the `Avatar` component in the default `ChannelPreviewMessenger` component. ```tsx const CustomAvatar = (props) => { - return ; + return ; }; } />; @@ -52,9 +42,17 @@ const CustomAvatar = (props) => { ## Props +### className + +Custom class that will be merged with the default class. + +| Type | +| ------------------- | +| string \| undefined | + ### image -The image URL or default is an image of the first initial of the name if there is one. +The image URL. If the image fails to load the default is an image of the first initial of the name if there is one. | Type | Default | | -------------- | ------------------------- | @@ -62,7 +60,7 @@ The image URL or default is an image of the first initial of the name if there i ### name -An optional name of the image, used for title tag fallback. +Used to extract a first letter to create the image fallback. | Type | | -------------- | @@ -70,7 +68,7 @@ An optional name of the image, used for title tag fallback. ### onClick -The click event handler. +The click event handler applied to the root `div` of the component. | Type | | ----------------------------------------- | @@ -78,31 +76,15 @@ The click event handler. ### onMouseOver -The mouseOver event handler. +The mouseOver event handler applied to the root `div` of the component. | Type | | ----------------------------------------- | | (event: React.BaseSyntheticEvent) => void | -### shape - -The shape of the avatar image. - -| Type | Default | -| --------------------------------- | ------- | -| 'circle' \| 'rounded' \| 'square' | circle | - -### size - -The size in pixels of the avatar image. - -| Type | Default | -| ------ | ------- | -| number | 32px | - ### user -The entire user object for the chat user displayed in the component. +The entire user object for the chat user represented by the Avatar component. This props is not used by the default `Avatar` component. | Type | | ------ | diff --git a/docusaurus/docs/React/components/utility-components/channel-search.mdx b/docusaurus/docs/React/components/utility-components/channel-search.mdx index f94d07744..2302988c1 100644 --- a/docusaurus/docs/React/components/utility-components/channel-search.mdx +++ b/docusaurus/docs/React/components/utility-components/channel-search.mdx @@ -11,14 +11,10 @@ import ImageInactiveSearchBarNoAppMenu from '../../assets/inactive-searchbar-no- import ImageInactiveSearchBarWithAppMenu from '../../assets/inactive-searchbar-with-app-menu.png'; import ImageActiveSearchBarNoText from '../../assets/active-searchbar-no-text.png'; import ImageActiveSearchBarWithText from '../../assets/active-searchbar-with-text.png'; -import ImageSearchResultsInlineThemeV2 from '../../assets/search-results-inline-theme-v2.png'; -import ImageSearchResultsPopupThemeV2 from '../../assets/search-results-popup-theme-v2.png'; -import ImageSearchResultsInlineThemeV1 from '../../assets/search-results-inline-theme-v1.png'; -import ImageSearchResultsPopupThemeV1 from '../../assets/search-results-popup-theme-v1.png'; -import ImageSearchResultsLoadingThemeV2 from '../../assets/search-results-loading-theme-v2.png'; -import ImageSearchResultsLoadingThemeV1 from '../../assets/search-results-loading-theme-v1.png'; -import ImageSearchResultsEmptyThemeV2 from '../../assets/search-results-empty-theme-v2.png'; -import ImageSearchResultsEmptyThemeV1 from '../../assets/search-results-empty-theme-v1.png'; +import ImageSearchResultsInlineTheme from '../../assets/search-results-inline-theme.png'; +import ImageSearchResultsPopupTheme from '../../assets/search-results-popup-theme.png'; +import ImageSearchResultsLoadingTheme from '../../assets/search-results-loading-theme.png'; +import ImageSearchResultsEmptyTheme from '../../assets/search-results-empty-theme.png'; `ChannelSearch` is a UI component that searches for chat users and displays the results in a list. It can be used standalone or in the `ChannelList` via the `showChannelSearch` prop (default is false). The input searches for users by default, but you can utilize the `searchForChannels` prop to also search for `channels`. Completely override the querying via the `searchFunction` prop. @@ -42,18 +38,14 @@ Selection of a search result will set the active channel with the selected user, ``` -## ChannelSearch according to theme version - The `ChannelSearch` component renders 2 components: 1. the search input 2. the search results list -If opted in the use of [theme version 2](../../theming/introduction.mdx), the `ChannelSearch` will render a more complex search input component called [`SearchBar`](./#searchbar-component). Otherwise, the [`SearchInput`](./#searchinput-component) is rendered. - -### Search input vs.SearchResults state +### Search input and SearchResults state -The input naturally transitions between 3 states regardless of theme version: +The input naturally transitions between 3 states: | Input state | Input | Search results | | ------------- | -------------------------------- | -------------- | @@ -143,23 +135,13 @@ The default styling of the first two states are as follows: border items={[ { - image: ImageSearchResultsLoadingThemeV1, - caption: Search results list content when loading (theme v1), - alt: 'Image of search results list content when loading', - }, - { - image: ImageSearchResultsEmptyThemeV1, - caption: Empty search results (theme v1), - alt: 'Image of empty search results', - }, - { - image: ImageSearchResultsLoadingThemeV2, - caption: Search results list content when loading (theme v2), + image: ImageSearchResultsLoadingTheme, + caption: Search results list content when loading, alt: 'Image of search results list content when loading', }, { - image: ImageSearchResultsEmptyThemeV2, - caption: Empty search results (theme v2), + image: ImageSearchResultsEmptyTheme, + caption: Empty search results, alt: 'Image of empty search results', }, ]} @@ -173,24 +155,14 @@ The search results can be rendered in place of the channel list or above the cha border items={[ { - image: ImageSearchResultsInlineThemeV1, - caption: Search results displayed inline (theme v1), - alt: 'Image of search results displayed inline (theme v1)', - }, - { - image: ImageSearchResultsPopupThemeV1, - caption: Search results displayed floating above the channel list (theme v1), - alt: 'Image of search results displayed floating above the channel list (theme v1)', - }, - { - image: ImageSearchResultsInlineThemeV2, - caption: Search results displayed inline (theme v2), - alt: 'Image of search results displayed inline (theme v2)', + image: ImageSearchResultsInlineTheme, + caption: Search results displayed inline, + alt: 'Image of search results displayed inline', }, { - image: ImageSearchResultsPopupThemeV2, - caption: Search results displayed floating above the channel list (theme v2), - alt: 'Image of search results displayed floating above the channel list (theme v2)', + image: ImageSearchResultsPopupTheme, + caption: Search results displayed floating above the channel list, + alt: 'Image of search results displayed floating above the channel list', }, ]} /> @@ -245,7 +217,7 @@ const { client } = useChatContext(); ### AppMenu -Application menu / drop-down to be displayed when clicked on [`MenuIcon`](./#menuicon). Prop is consumed only by the [`SearchBar` component](./#searchbar). The `SearchBar` component is only available with the use of the [theming v2](../../theming/introduction.mdx). No default component is provided by the SDK. The library does not provide any CSS for `AppMenu`. Consult the customization tutorial on how to [add AppMenu to your application](../../guides/customization/channel-search.mdx/#adding-menu). The component is passed a prop `close`, which is a function that can be called to hide the app menu (e.g. on menu item selection). +Application menu / drop-down to be displayed when clicked on [`MenuIcon`](./#menuicon). Prop is consumed only by the [`SearchBar` component](./#searchbar). No default component is provided by the SDK. The library does not provide any CSS for `AppMenu`. Consult the customization tutorial on how to [add AppMenu to your application](../../guides/customization/channel-search.mdx/#adding-menu). The component is passed a prop `close`, which is a function that can be called to hide the app menu (e.g. on menu item selection). | Type | Default | | --------------------- | ----------- | @@ -261,7 +233,7 @@ The type of `channel` to create on user result selection. ### ClearInputIcon -Custom icon component used as a content of the button used to clear the search input. Prop is consumed only by the [`SearchBar` component](./#searchbar). The `SearchBar` component is rendered with `themeVersion` `'2'` only. +Custom icon component used as a content of the button used to clear the search input. Prop is consumed only by the [`SearchBar` component](./#searchbar). | Type | Default | | --------------------- | --------------------------------------------------------------- | @@ -285,7 +257,7 @@ Disables execution of the search queries and makes the search text input element ### ExitSearchIcon -Custom icon component used as a content of the button used to exit the search UI. Prop is consumed only by the [`SearchBar` component](./#searchbar). The `SearchBar` component is rendered with `themeVersion` `'2'` only. +Custom icon component used as a content of the button used to exit the search UI. Prop is consumed only by the [`SearchBar` component](./#searchbar). | Type | Default | | --------------------- | -------------------------------------------------------------------- | @@ -293,7 +265,7 @@ Custom icon component used as a content of the button used to exit the search UI ### MenuIcon -Custom icon component used as a content of the button used to invoke the [`AppMenu`](./#appmenu). Prop is consumed only by the [`SearchBar` component](./#searchbar). The `SearchBar` component is rendered with `themeVersion` `'2'` only. The menu icon button is displayed only if `AppMenu` component has been passed to `ChannelSearch` props. +Custom icon component used as a content of the button used to invoke the [`AppMenu`](./#appmenu). Prop is consumed only by the [`SearchBar` component](./#searchbar). The menu icon button is displayed only if `AppMenu` component has been passed to `ChannelSearch` props. | Type | Default | | --------------------- | ------------------------------------------------------------------ | @@ -345,7 +317,7 @@ Display search results as an absolutely positioned popup, defaults to false and ### SearchBar -Custom component to be rendered instead of the default . This component is displayed only if `themeVersion` is `'2'`. With the theme version 1 only the `SearchInput` is rendered. The default `SearchBar` component is a composite of multiple buttons and a search input. You can find more information about its features in an [above section](./#searchbar-component). +Custom component to be rendered instead of the default . The default `SearchBar` component is a composite of multiple buttons and a search input. You can find more information about its features in an [above section](./#searchbar-component). | Type | Default | | -------------------------------------- | ----------------------------------------------------------------------- | diff --git a/docusaurus/docs/React/components/utility-components/indicators.mdx b/docusaurus/docs/React/components/utility-components/indicators.mdx index 183e859c4..24562c45c 100644 --- a/docusaurus/docs/React/components/utility-components/indicators.mdx +++ b/docusaurus/docs/React/components/utility-components/indicators.mdx @@ -186,14 +186,6 @@ Custom UI component to display user's avatar. | --------- | ---------------------------------------------------------- | | component | | -### avatarSize - -The size in pixels of the avatar image. - -| Type | Default | -| ------ | ------- | -| number | 32px | - ### threadList Boolean that signals whether the typing indicator is in a `Thread`. diff --git a/docusaurus/docs/React/guides/customization/suggestion-list.mdx b/docusaurus/docs/React/guides/customization/suggestion-list.mdx index 9b9c582dc..891a839b7 100644 --- a/docusaurus/docs/React/guides/customization/suggestion-list.mdx +++ b/docusaurus/docs/React/guides/customization/suggestion-list.mdx @@ -105,7 +105,7 @@ const CustomSuggestionItem = (props) => { if (!('native' in item) && 'id' in item) { children = ( <> - + {item.name ?? item.id} ); diff --git a/docusaurus/docs/React/guides/customization/system-message.mdx b/docusaurus/docs/React/guides/customization/system-message.mdx index 681dc31e8..9a2c08b72 100644 --- a/docusaurus/docs/React/guides/customization/system-message.mdx +++ b/docusaurus/docs/React/guides/customization/system-message.mdx @@ -42,7 +42,7 @@ const CustomSystemMessage = (props: EventComponentProps) => {
Actor: - + {user?.name}
diff --git a/docusaurus/docs/React/guides/theming/actions/attachment-actions.mdx b/docusaurus/docs/React/guides/theming/actions/attachment-actions.mdx index 80aa8c506..9fa839dfd 100644 --- a/docusaurus/docs/React/guides/theming/actions/attachment-actions.mdx +++ b/docusaurus/docs/React/guides/theming/actions/attachment-actions.mdx @@ -106,7 +106,7 @@ const CustomAttachment: React.FC = (props) => ( To add our `attachmentActions` to an uploaded image and trigger the render of the `CustomAttachmentActions` component, we provide custom logic to override the `MessageInput` component's default submit handling behavior. For a detailed, -step-by-step example, see the [Input Submit Handler](../../override-submit-handler.mdx) custom code example. +step-by-step example, see the [Input Submit Handler](../../../customization/override_submit_handler) custom code example. Simply put, if an `image` type message attachment exists, we update the `attachments` array on the `message` object by adding the `attachmentActions`. diff --git a/docusaurus/docs/React/guides/theming/message-ui.mdx b/docusaurus/docs/React/guides/theming/message-ui.mdx index 52e092be8..d846e42ac 100644 --- a/docusaurus/docs/React/guides/theming/message-ui.mdx +++ b/docusaurus/docs/React/guides/theming/message-ui.mdx @@ -36,7 +36,7 @@ To see our changes we'll need to pass this component down to either `Channel` or ![](../../assets/custom-message-ui-0.png) -You can see that all of the messages are now on one side and we have no idea who's the message coming from, let's adjust that with the help of some CSS, and to render the name of the sender we'll need to access `user` property of the `message` object. +You can see that all the messages are now on one side and we have no idea who's the message coming from, let's adjust that with the help of some CSS, and to render the name of the sender we'll need to access `user` property of the `message` object. Our message will be on the right and the message of the other senders will be on the left side of the screen. diff --git a/docusaurus/docs/React/hooks/message-hooks.mdx b/docusaurus/docs/React/hooks/message-hooks.mdx index ea0e8921e..3e3d8d19c 100644 --- a/docusaurus/docs/React/hooks/message-hooks.mdx +++ b/docusaurus/docs/React/hooks/message-hooks.mdx @@ -207,7 +207,7 @@ const MyCustomReactionsList = () => { }; ``` -This function limits the number of loaded reactions to 1200. To customize this behavior, provide [your own loader function](../message-components/reactions.mdx#handlefetchreactions) instead. +This function limits the number of loaded reactions to 1200. To customize this behavior, provide [your own loader function](../components/message-components/reactions.mdx#handlefetchreactions) instead. ### useRetryHandler diff --git a/docusaurus/docs/React/release-guides/upgrade-to-v12.mdx b/docusaurus/docs/React/release-guides/upgrade-to-v12.mdx new file mode 100644 index 000000000..bc99b9411 --- /dev/null +++ b/docusaurus/docs/React/release-guides/upgrade-to-v12.mdx @@ -0,0 +1,251 @@ +--- +id: upgrade-to-v12 +title: Upgrade to v12 +keywords: [migration guide, upgrade, v12, breaking changes] +--- + +## Avatar changes + +The `Avatar` styles are applied through CSS from the version 12 upwards. Therefore, the following changes were applied: + +1. Props `shape` and `size` were removed. Subsequently, the class `str-chat__avatar--${shape}` was removed. + +2. Another class we removed is `str-chat__avatar-image--loaded` that was applied to `img` element in the `Avatar` component. + +3. New prop `className` has been added to `Avatar`. Integrators can now optionally apply custom styles to custom classes. + +4. There have also been added new classes to `Avatar` root `div` in different components: + +| Component | `Avatar` root CSS class | +| ------------------------------------------- | ----------------------------------------- | +| `ChannelHeader` | `str-chat__avatar--channel-header` | +| `ChannelPreviewMessenger` | `str-chat__avatar--channel-preview` | +| `MessageStatus` | `str-chat__avatar--message-status` | +| `ReactionsList` | `stream-chat__avatar--reaction` | +| `QuotedMessage` | `str-chat__avatar--quoted-message-sender` | +| `SearchResultItem` | `str-chat__avatar--channel-preview` | +| `UserItem` rendered by `SuggestionListItem` | `str-chat__avatar--autocomplete-item` | + +5. As a consequence of the `Avatar` props changes, the `TypingIndicator` prop `avatarSize` have been removed as well. + +:::important +**Action required**
+1 Migrate CSS applied to `.str-chat__avatar--${shape}` or re-apply the class through `Avatar` `className` prop.
+2 Migrate CSS applied to `.str-chat__avatar-image--loaded` to `.str-chat__avatar-image` class.
+3 If needed, apply custom styles to newly added classes based on the component that renders the `Avatar`.
+::: + +## Removal of deprecated components + +### Attachment rendering utility functions + +The attachment rendering functions were replaced with their component equivalents: + +:::important +**Action required**
+Replace the render functions in your custom components with container components alternatives. +::: + +| Rendering function | Component equivalent | +| --------------------------------- | ---------------------------- | +| `renderAttachmentWithinContainer` | `AttachmentWithinContainer` | +| `renderAttachmentActions` | `AttachmentActionsContainer` | +| `renderGallery` | `GalleryContainer` | +| `renderImage` | `ImageContainer` | +| `renderCard` | `CardContainer` | +| `renderAudio` | `AudioContainer` | +| `renderMedia` | `MediaContainer` | + +## Change import of default styles + +Until now, it was possible to import two stylesheets as follows: + +``` +import 'stream-chat-react/dist/css/v2/index.css'; +``` + +The legacy stylesheet has been removed from the SDK bundle, and therefore it is only possible to import one stylesheet from now on: + +``` +import 'stream-chat-react/dist/css/v2/index.css'; +``` + +:::important +**Action required**
+Make sure you are importing the default styles correctly as `import 'stream-chat-react/dist/css/v2/index.css';` +::: + +## Removal of legacy styles + +With the version 10 of `stream-chat-react` new stylesheet has been introduced. The stylesheet used previously became a legacy stylesheet. Legacy stylesheet had often times CSS classes and SDK components, that were not supported with the new stylesheet. Now, the legacy stylesheet and corresponding CSS classes and SDK component are being removed. + +:::caution +These changes will impact you only, if you have imported the CSS as one of the following (you have used the legacy styles): + +``` +import 'stream-chat-react/css/index.css'; +``` + +``` +import '@stream-io/stream-chat-css/dist/css/index.css'; +``` + +::: + +### Removal of themeVersion from ChatContext + +Supporting two stylesheet lead to introduction of a flag `themeVersion` into the `ChatContext`. This flag is no more necessary and has been removed from the context value. + +:::important +**Action required**
+Make sure you are not using `themeVersion in your custom components. +::: + +### Removal of styles related Chat props + +With legacy stylesheet we have removed legacy approach to applying styles via component props. Two `Chat` component props were removed as a consequence: + +- `customStyles` +- `darkMode` + +Also associated parts of code were removed: + +- `Theme` type +- `useCustomStyles` hook + +:::important +**Action required**
+1 The styles applied through `customStyles` should be applied through custom CSS. +2 Theme (not only dark theme) can be through `Chat` prop `theme` instead of `darkMode` +::: + +### Removal from ComponentContext + +- `AutocompleteSuggestionHeader` - the up-to-date SDK markup does not count with a header in the `ChatAutoComplete` suggestion list + +:::important +**Action required**
+Make sure you are passing these custom components to the `Channel` component. +::: + +### Removal of legacy components + +The following components are not available anymore as they were related to legacy stylesheet and are not used by the latest SDK components. + +:::important +**Action required**
+1 Remove imports of these components from `stream-chat-react` in your custom components.
+2 If importing `SendIconV2` rename it to `SendIcon`.
+3 Remove the listed classes if used in your CSS. +::: + +| Component | Details | Removed CSS classes | +| ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | +| `ChatDown` | used to be rendered as the default for `LoadingErrorIndicator` by `ChannelListMessenger` (the default `ChannelList` UI component). The default is now a null component (renders `null`) | `str-chat__down` and `str-chat__down-main` | +| `DefaultSuggestionListHeader` | rendered only with legacy stylesheet in the `ChatAutoComplete`. As a consequence the `AutocompleteSuggestionHeader` prop has been removed from `Channel` props | | +| Icons rendered `Message` component when legacy styles applied | `ReplyIcon`, `DeliveredCheckIcon`, `ErrorIcon` | | +| Icons rendered `MessageInput` component when legacy styles applied | `EmojiIconLarge`, `EmojiIconSmall`, `FileUploadIcon`, `FileUploadIconFlat`, `SendIconV1` (`SendIconV2` renamed to `SendIcon`) | | +| `MessageInputSmall` | Used to be rendered in `Thread`, but was deprecated since v10 and replaced by `MessageInputFlat` | all the classes starting with `str-chat__small-message-input` | +| `UploadsPreview` | Used to be rendered in `MessageInput` but was deprecated since v10 and replaced with `AttachmentPreviewList` | | +| `FilePreviewer` was rendered by `UploadsPreview` | Used by component removed from the SDK | | +| `ImagePreviewer` was rendered by `UploadsPreview` | Used by component removed from the SDK | | +| `AttachmentIcon` | Not used by the SDK | | +| `PictureIcon` | Not used by the SDK | | +| `FileUploadButton` | Not used by the SDK | | +| `ImageUploadButton` | Not used by the SDK | | +| `ThumbnailPlaceholder` | Not used by the SDK | | +| `Thumbnail` | Not used by the SDK | | + +### Removal of legacy attachment file icons + +The `FileIcon` component does not accept argument `version` anymore. This parameter used to determine the file icon set. There were two sets - version `'1'` and `'2'`. The icons of version `'1'` have been rendered with legacy stylesheets in the SDK components. The icons displayed under the version `'1'` have been removed now. + +:::important +**Action required**
+Remove prop `version` if the `FileIcon` is used in your custom components. +::: + +### Removal of legacy CSS classes + +We have removed classes that were used in the legacy CSS stylesheet only and thus are redundant. We recommend to use classes that were already available previously and are used by the SDK stylesheet: + +:::important +**Action required**
+Replace the removed classes with their alternatives in the custom CSS. +::: + +| Component | Class removed | Class to be used instead | +| ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | +| `MediaContainer` | `str-chat__attachment-media` | `str-chat__attachment` | +| suggestion list in `ReactTextAreaAutocomplete` | `rta__autocomplete` | `str-chat__suggestion-list-container` | +| `Avatar` root `
` | `str-chat__avatar--circle`, `str-chat__avatar--square`, `str-chat__avatar--rounded` | `str-chat__avatar` possibly combined with custom class | +| `Avatar` element `` | `str-chat__avatar-image--loaded` | +| `Channel` root `
` | `str-chat-channel` | `str-chat__channel` | +| `ChannelHeader` root `
` | `str-chat__header-livestream` | `str-chat__channel-header` | +| `ChannelHeader` root `
` children | `str-chat__header-livestream-left` | `str-chat__channel-header-end` | +| `ChannelHeader` root `
` children | `str-chat__header-livestream-left--title` | `str-chat__channel-header-title` | +| `ChannelHeader` root `
` children | `str-chat__header-livestream-left--subtitle` | `str-chat__channel-header-subtitle` | +| `ChannelHeader` root `
` children | `str-chat__header-livestream-left--members` | `str-chat__channel-header-info` | +| `ChannelList` root `
` | `str-chat-channel-list` | `str-chat__channel-list` | +| `ChannelPreviewMessenger` root `
` children | `str-chat__channel-preview-messenger--right` | `str-chat__channel-preview-end` | +| `SearchResults` root `
` children | `str-chat__channel-search-container` | `str-chat__channel-search-result-list` | +| `SuggestionList` (rendered by `ChatAutoComplete`) container `
` | `str-chat__emojisearch` | `str-chat__suggestion-list-container` | +| `SuggestionList` (rendered by `ChatAutoComplete`) root `
` | `str-chat__emojisearch__list` | `str-chat__suggestion-list` | +| `SuggestionListItem` (rendered by `SuggestionList`) root `
` | `str-chat__emojisearch__item` | `str-chat__suggestion-list-item` | +| `EmojiPicker` root `
` | `str-chat__emojiselect-wrapper` (only applied with legacy styles) | `str-chat__message-textarea-emoji-picker` | +| `EmojiPicker` button | `str-chat__input-flat-emojiselect` (only applied with legacy styles) | `str-chat__emoji-picker-button` | +| `Emoji` (rendered by `Message`) | `inline-text-emoji` | the `

` element has been removed, no substitute class | +| `MessageRepliesCountButton` (rendered by `Message`) root `

` | `str-chat__message-simple-reply-button` | `str-chat__message-replies-count-button-wrapper` | +| `Message` wrapper `
` around `MessageStatus` & `MessageTimestamp` | `str-chat__message-data`, `str-chat__message-simple-data` | `str-chat__message-metadata` | +| `QuotedMessage` root `
` | `quoted-message` | `str-chat__quoted-message-preview` | +| `QuotedMessage` bubble | `quoted-message-inner` | `str-chat__quoted-message-bubble` | +| `EditMessageForm` | `str-chat__edit-message-form-options` | no alternative | +| `EditMessageForm` | `str-chat__fileupload-wrapper` | no alternative | +| `EditMessageForm` | `str-chat__input-fileupload` | no alternative | +| `MessageInputFlat` root `
` | all classes starting with `str-chat__input-flat` | see the current implementation of `MessageInputFlat` | +| `QuotedMessagePreviewHeader` (rendered by `QuotedMessagePreviewHeader`) root `
` | `quoted-message-preview-header` | `str-chat__quoted-message-preview-header` | +| `QuotedMessagePreviewHeader` (rendered by `QuotedMessagePreviewHeader`) child ` + ); +}; + +// further down the line, add the JumpToMessage to the component tree as a child of `Channel` +// ... +return ( + + + + + + +); +``` + +| Type | +| -------------------------------------- | +| `(messageId: string) => Promise` | + +### loadMore + +The function to load next page/batch of `messages` (used for pagination). + +| Type | +| -------- | +| function | + +### loadMoreNewer + +The function to load next page/batch of `messages` (used for pagination). + +| Type | +| ------------------------------------ | +| (limit?: number) => Promise | + +### loadMoreThread + +The function to load next page/batch of `messages` in a currently active/open `Thread` (used for pagination). + +| Type | +| -------- | +| function | + +### markRead + +Throttled function that executes the API request and updates the local channel read state for own user. The behavior can be configured via the single `options` parameter of type `MarkReadWrapperOptions`. The `options` parameter has the following structure: + +| Field | Type | Optional | Description | +|------------------------|-----------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `updateChannelUiUnreadState` | `boolean` | yes | Signal, whether the `channelUnreadUiState` should be updated. The local state update is prevented when the Channel component is mounted. This is in order to keep the UI indicating the original unread state, when the user opens a channel. If the value for `updateChannelUiUnreadState` is not provided, the state is updated. | + | + +| Type | +| -------- | +| `(options?: MarkReadWrapperOptions) => void` | + +### onMentionsClick + +Custom action handler function to execute when @mention is clicked, takes a DOM click event object and an array of mentioned users. + +| Type | +| -------- | +| function | + +### onMentionsHover + +The function to execute when @mention is hovered in a `message`, takes a DOM click event object and an array of mentioned users. + +| Type | +| -------- | +| function | + +### openThread + +The function to execute when replies count button is clicked, takes the parent message of the `Thread` to be opened and optionally a DOM click event. + +| Type | +| -------- | +| function | + +### removeMessage + +The function to remove a `message` from `MessageList`, handled by the `Channel` component. Takes a `message` object. + +| Type | +| -------- | +| function | + +### retrySendMessage + +The function to resend a `message`, handled by the `Channel` component. + +| Type | +| -------- | +| function | + +### sendMessage + +The function to send a `message` on `Channel`. Takes a `message` object with the basic message information as the first argument, and custom data as the second argument. + +| Type | +| -------- | +| function | + +### setQuotedMessage + +The function to send a `QuotedMessage` on a `Channel`, take a `message` object. + +| Type | +| -------- | +| function | + +### updateMessage + +The function to update a `message` on `Channel`, takes a `message` object. + +| Type | +| -------- | +| function | diff --git a/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/channel-list-context.mdx b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/channel-list-context.mdx new file mode 100644 index 000000000..d2ddf659a --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/channel-list-context.mdx @@ -0,0 +1,113 @@ +--- +id: channel_list_context +title: ChannelListContext +--- + +The context value is provided by `ChannelListContextProvider` which wraps the contents rendered by [`ChannelList`](../core-components/channel-list.mdx). It exposes API that the default and custom components rendered by `ChannelList` can take advantage of. The components that can consume the context are customizable via `ChannelListProps`: + +- `Avatar` - component used to display channel image +- `ChannelSearch` - renders channel search input and results +- `EmptyStateIndicator` - rendered when the channels query returns and empty array +- `LoadingErrorIndicator` - rendered when the channels query fails +- `LoadingIndicator`- rendered during the channels query +- `List` - component rendering `LoadingErrorIndicator`, `LoadingIndicator`, `EmptyStateIndicator`, `Paginator` and the list of channel `Preview` components +- `Paginator` - takes care of requesting to load more channels into the list (pagination) +- `Preview` - renders the information of a channel in the channel list + +## Basic Usage + +Access the API from context with our custom hook: + +```jsx +import { useChannelListContext } from 'stream-chat-react'; + +export const CustomComponent = () => { + const { channels, setChannels } = useChannelListContext(); + // component logic ... + return( + {/* rendered elements */} + ); +} +``` + +## Value + +### channels + +State representing the array of loaded channels. Channels query is executed by default only within the [`ChannelList` component](../core-components/channel-list.mdx) in the SDK. + +| Type | +|-------------| +| `Channel[]` | + +### setChannels + +Sets the list of `Channel` objects to be rendered by `ChannelList` component. One have to be careful, when to call `setChannels` as the first channels query executed by the `ChannelList` overrides the whole [`channels` state](#channels). In that case it is better to subscribe to `client` event `channels.queried` and only then set the channels. +In the following example, we have a component that sets the active channel based on the id in the URL. It waits until the first channels page is loaded, and then it sets the active channel. If the channel is not present on the first page, it performs additional API request with `getChannel()`: + +```tsx +import { useEffect } from 'react'; +import { useNavigate, useParams } from 'react-router-dom'; +import { ChannelList, ChannelListMessenger, ChannelListMessengerProps, getChannel, useChannelListContext, useChatContext } from 'stream-chat-react'; + +const DEFAULT_CHANNEL_ID = 'general'; +const DEFAULT_CHANNEL_TYPE = 'messaging'; + +const List = (props: ChannelListMessengerProps) => { + const { channelId } = useParams(); + const navigate = useNavigate(); + const { client, channel, setActiveChannel } = useChatContext(); + const { setChannels } = useChannelListContext(); + + useEffect(() => { + if (!channelId) return navigate(`/${DEFAULT_CHANNEL_ID}`); + + if (channel?.id === channelId || !client) return; + + let subscription: { unsubscribe: () => void } | undefined; + if(!channel?.id || channel?.id !== channelId) { + subscription = client.on('channels.queried', (event: Event) => { + const loadedChannelData = event.queriedChannels?.channels.find((response) => response.channel.id === channelId); + + if (loadedChannelData) { + setActiveChannel(client.channel( DEFAULT_CHANNEL_TYPE, channelId)); + subscription?.unsubscribe(); + return; + } + + return getChannel({client, id: channelId, type: DEFAULT_CHANNEL_TYPE}).then((newActiveChannel) => { + setActiveChannel(newActiveChannel); + setChannels((channels) => { + return ([newActiveChannel, ...channels.filter((ch) => ch.data?.cid !== newActiveChannel.data?.cid)]); + }); + }); + }); + } + + return () => { + subscription?.unsubscribe(); + }; + }, [channel?.id, channelId, setChannels, client, navigate, setActiveChannel]); + + return ; +}; + + + +const Sidebar = () => { + return ( + // ... + + // ... +} +``` + +| Type | +|---------------------------------------| +| `Dispatch>` | diff --git a/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/channel-state-context.mdx b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/channel-state-context.mdx new file mode 100644 index 000000000..c153e1a3b --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/channel-state-context.mdx @@ -0,0 +1,337 @@ +--- +id: channel_state_context +title: ChannelStateContext +--- + +The `ChannelStateContext` is a one of the context providers exposed in the [`Channel`](../core-components/channel.mdx) component and is consumable by all of the `Channel` children components. +The context provides all the state properties and logic for a `channel`, and you can access these by calling the `useChannelStateContext` custom hook. + +## Basic Usage + +Pull values from context with our custom hook: + +```jsx +const { channel, watchers } = useChannelStateContext(); +``` + +## Values + +### acceptedFiles + +A list of accepted file upload types. + +| Type | +| -------- | +| string[] | + +### channel + +The currently active `StreamChat` `channel` instance to be loaded into the `Channel` component and referenced by its children. + +| Type | +| ------ | +| object | + +### channelCapabilities + +The allowed channel permissions for the currently connected user. + +| Type | +| ------ | +| object | + +### channelConfig + +The configurations object for the currently active channel. + +| Type | +| ------ | +| object | + +### dragAndDropWindow + +If true, chat users will be able to drag and drop file uploads to the entire channel window. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### debounceURLEnrichmentMs: + +Number of milliseconds to debounce firing the URL enrichment queries when typing. The default value is 1500(ms). See the guide [Link Previews in Message Input](../../../guides/customization/link-previews) for more. + +| Type | Default | +| ------ | ------- | +| number | 1500 | + +### enrichURLForPreview + +A global flag to toggle the URL enrichment and link previews in `MessageInput`. By default, the feature is disabled. It can be overridden on Thread and MessageList level through `additionalMessageInputProps` +or directly on `MessageInput` level through `urlEnrichmentConfig` prop. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### error + +Error object (if any) in loading the `channel`, otherwise null. + +| Type | +| ------ | +| object | + +### findURLFn + +Custom function to identify URLs in a string for later generation of link previews. See the guide [Link Previews in Message Input](../../../guides/customization/link-previews) for more. + +| Type | +| ---------------------------- | +| `(text: string) => string[]` | + +### giphyVersion + +The giphy version to use when displaying giphies. + +| Type | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `'original'` \| `'fixed_height'` \| `'fixed_height_still'` \| `'fixed_height_downsampled'` \| `'fixed_width'` \| `'fixed_width_still'` \| `'fixed_width_downsampled'` | + +### imageAttachmentSizeHandler + +A custom function to provide size configuration for image attachments + +| Type | +| ---------------------------------------------------------------- | +| `(a: Attachment, e: HTMLElement) => ImageAttachmentConfiguration` | + +### hasMore + +If the channel has more, older, messages to paginate through. + +| Type | +| ------- | +| boolean | + +### hasMoreNewer + +If the channel has more, newer, messages to paginate through. + +| Type | +| ------- | +| boolean | + +#### highlightedMessageId + +Value is used internally for jump-to-message logic. Once the user "jumped" to the message, the message with the given ID is highlighted by manipulating its styles attribute. + +| Type | +| ------ | +| string | + +### loading + +Boolean for the `channel` loading state. + +| Type | +| ------- | +| boolean | + +### loadingMore + +Boolean for the `channel` loading more messages. + +| Type | +| ------- | +| boolean | + +### loadingMoreNewer? + +Flag signalling whether newer messages are being loaded as the user scrolls down in the message list. Used internally by `VirtualizedMessageList`. + +| Type | +| ------- | +| boolean | + +### maxNumberOfFiles + +The maximum number of attachments allowed per `message`, defaults to the Stream Chat API maximum. + +| Type | Default | +| ------ | ------- | +| number | 10 | + +### members + +Members of this `channel` (members are permanent, watchers are users who are online right now). + +| Type | +| -------- | +| object[] | + +### messages + +Array of [message objects](https://getstream.io/chat/docs/javascript/message_format/?language=javascript). + +| Type | +| -------- | +| object[] | + +### multipleUploads + +Whether to allow multiple attachment uploads on a message. + +| Type | Default | +| ------- | ------- | +| boolean | true | + +### mutes + +An array of muted users for a `channel`. + +| Type | +| -------- | +| object[] | + +### notifications + +Temporary notifications added to the `MessageList` on specific user/message actions. + +| Type | +| -------------------------------------------------------- | +| {id: string, text: string, type: 'success' \| 'error'}[] | + +### onLinkPreviewDismissed + +Custom function to react to link preview dismissal. See the guide [Link Previews in Message Input](../../../guides/customization/link-previews) for more. + +| Type | +| ------------------------------------ | +| `(linkPreview: LinkPreview) => void` | + +### channelUnreadUiState + +The read state maintained for use by components representing channel unread state (for example `UnreadMessagesSeparator`, `UnreadMessagesNotification`). + +| Property | Type | Description | +|-----------------------------|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **last_read** | `Date` | Date when the channel was marked read the last time. | +| **unread_messages** | `number` | The count of unread messages in a given channel. Unread count refers only to foreign (not own) unread messages. | +| **first_unread_message_id** | `string` or `undefined` | The ID of the message that was marked unread (`notification.mark_unread` event). The value is available only when a message is marked unread. Therefore, cannot be relied on to place unread messages UI. | +| **last_read_message_id** | `string` or `undefined` | The ID of the message preceding the first unread message. | + +| Type | +|-----------------------| +| `ChannelUnreadUiState` | + +### pinnedMessages + +The messages that are pinned in the `channel`. + +| Type | +| -------- | +| object[] | + +### quotedMessage + +An inline message reply to another message. + +| Type | +| ------ | +| object | + +### read + +The read state for each `channel` member. + +| Type | +| ------ | +| object | + +### suppressAutoscroll + +Flag signalling whether the scroll to the bottom is prevented. Used internally by `MessageList` and `VirtualizedMessageList` components. + +| Type | +| ------- | +| boolean | + +### shouldGenerateVideoThumbnail + +You can turn on/off thumbnail generation for video attachments + +| Type | +| --------- | +| `boolean` | + +### thread + +The parent message for a `thread`, if there is one, otherwise null. + +| Type | +| ------ | +| object | + +### threadHasMore + +Boolean showing if there are more messages available in current active `thread`, set to false when the end of pagination is reached. + +| Type | +| ------- | +| boolean | + +### threadLoadingMore + +If the thread is currently loading more messages. + +| Type | +| ------- | +| boolean | + +### threadMessages + +Array of messages within a `thread`. + +| Type | +| -------- | +| object[] | + +### threadSuppressAutoscroll + +Flag signalling whether the scroll to the bottom is prevented in thread. Used internally by `MessageList` and `VirtualizedMessageList` components. + +| Type | +| ------- | +| boolean | + +### videoAttachmentSizeHandler + +A custom function to provide size configuration for video attachments + +| Type | +| ----------------------------------------------------------------- | +| `(a: Attachment, e: HTMLElement) => VideoAttachmentConfiguration` | + +### watcherCount + +The number of watchers on the `channel`. + +| Type | +| ------ | +| number | + +### watchers + +An array of users who are currently watching the `channel`. + +| Type | +| -------- | +| object[] | + +### watcher_count + +The number of watchers on the `channel`. + +| Type | +| ------ | +| number | diff --git a/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/chat-context.mdx b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/chat-context.mdx new file mode 100644 index 000000000..3ac710535 --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/chat-context.mdx @@ -0,0 +1,145 @@ +--- +id: chat_context +title: ChatContext +--- + +The `ChatContext` is exposed by the [`Chat`](../core-components/chat.mdx) component. Since `Chat` wraps the entire chat application, all other components in the library +have access to the values stored in this context. You can access the context values by calling the `useChatContext` custom hook. + +## Basic Usage + +Pull values from context with our custom hook: + +```jsx +const { client, setActiveChannel } = useChatContext(); +``` + +## Values + +### client + +The `StreamChat` client instance. Any methods from the `stream-chat-js` API interface can be run off this object. + +| Type | +| ------ | +| object | + +### channel + +The currently active channel, which populates the [`Channel`](../core-components/channel.mdx) component. + +| Type | +| ------- | +| Channel | + +### channelsQueryState + +Exposes API that: + +- indicates, whether and what channels query has been triggered within [`ChannelList` component](../core-components/channel-list.mdx) by its channels pagination controller - `queryInProgress` of type `ChannelQueryState` +- allows to set the `queryInProgress` state with `setQueryInProgress` state setter +- keeps track of error response from the channels query - `error` +- allows to set the `error` state with `setError` + +The `queryInProgress` values are: + +- `uninitialized` - the initial state before the first channels query is triggered +- `reload` - the initial channels query (loading the first page) is in progress +- `load-more` - loading the next page of channels +- `null` - at least one channels page has been loaded and there is no query in progress at the moment + +| Type | +|----------------------| +| `ChannelsQueryState` | + +### closeMobileNav + +The function to close mobile navigation. + +| Type | +| -------- | +| function | + +### customClasses + +Object containing custom CSS classnames to override the library's default container CSS. See [CSS and Theming](../../guides/theming/css-and-theming.mdx) +for implementation assistance. + +| Type | +| ------ | +| object | + +### getAppSettings + +The callback function used to get available client-side app settings, includes image and file upload config. + +| Type | +| -------- | +| function | + +### latestMessageDatesByChannel + +Object containing the date of the latest message sent by the current user by channels (this is used to detect if slow mode countdown should be started) + +| Type | +| ----------------------- | +| { [key: string]: Date } | + +### mutes + +An array of users that have been muted by the connected user. + +| Type | +| ------ | +| Mute[] | + +### navOpen + +When the screen width is at a mobile breakpoint, whether the mobile navigation menu is open. + +| Type | Default | +| ------- | ------- | +| boolean | true | + +### openMobileNav + +The function to open mobile navigation. + +| Type | +| -------- | +| function | + +### setActiveChannel + +A function to set the currently active channel. This is used in the `ChannelList` component to navigate between channels. +You can override the default behavior by pulling it from context and then utilizing the function. + +| Type | +| -------- | +| function | + +### theme + +Deprecated and to be removed in a future major release. Use the `customStyles` prop to adjust CSS variables and [customize the theme](../../guides/theming/css-and-theming.mdx#css-variables) of your app. + +| Type | +| ----- | +| Theme | + +### themeVersion + +Stream chat theme version 2 has been introduced with the release of stream-chat-react v10.0.0. This flag is used internally by some UI components of the SDK and the integrators shouldn't need to use it. The value is extracted from a CSS variable `--str-chat__theme-version`. You can set it to values `'1'` or `'2'` in your stylesheets and import the corresponding v2 stylesheet from `stream-chat-react/dist`. Find out more about benefits that the theme version 2 brings to the integrators with [the theming guide](../../theming/introduction.mdx). + +| Type | Default | +| -------------- | ------- | +| `'1'` \| `'2'` | `'1'` | + +### useImageFlagEmojisOnWindow + +Windows 10 does not support country flag emojis out of the box. It chooses to render these emojis as characters instead. +Stream Chat can override this behavior by loading a custom web font that will render images instead (PNGs or SVGs depending +on the platform). Set this prop to true if you want to use these custom emojis for Windows users. + +| Type | Default | +| ------- | ------- | +| boolean | false | diff --git a/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/component-context.mdx b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/component-context.mdx new file mode 100644 index 000000000..3968c483a --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/component-context.mdx @@ -0,0 +1,409 @@ +--- +id: component_context +title: ComponentContext +--- + +import GHComponentLink from '../../_docusaurus-components/GHComponentLink'; + +The `ComponentContext` is a one of the context providers exposed by the [`Channel`](../core-components/channel.mdx) component and is +consumable by all the children of `Channel`. This context provides UI component override options for maximum customization. +All UI overrides that target children of the `Channel` component should be placed as `Channel` component props in order to be injected into the `ComponentContext`. +The `ComponentContext` also exposes the hook `useComponentContext`. + +## Basic Usage + +Pull values from context with our custom hook: + +```jsx +const { Attachment, Avatar, Message } = useComponentContext(); +``` + +## Values + +### Attachment + +Custom UI component to display attachment in an individual message. + +| Type | Default | +| --------- | ---------------------------------------------------------------------- | +| component | | + +### AttachmentPreviewList + +Custom UI component to display a attachment previews in `MessageInput`. + +| Type | Default | +| --------- | ---------------------------------------------------------------------------------------------- | +| component | | + +### AutocompleteSuggestionHeader + +Custom UI component to override the default suggestion header component. + +| Type | Default | +| --------- | ------------------------------------------------------------------------ | +| component | | + +### AutocompleteSuggestionItem + +Custom UI component to override the default suggestion Item component. + +| Type | Default | +| --------- | ------------------------------------------------------------------- | +| component | | + +### AutocompleteSuggestionList + +Custom UI component to override the default List component that displays suggestions. + +| Type | Default | +| --------- | ------------------------------------------------------------------- | +| component | | + +### Avatar + +Custom UI component to display a user's avatar. + +| Type | Default | +| --------- | ---------------------------------------------------------- | +| component | | + +### BaseImage + +Custom UI component to display image resp. a fallback in case of load error, in `` element. The default resp. custom (from `ComponentContext`) `BaseImage` component is rendered by: + +- - single image attachment in message list +- - group of image attachments in message + list +- - image + uploads preview in message input (composer) + +The `BaseImage` component accepts the same props as `` element. + +The [default `BaseImage` component](../../utility-components/base-image) tries to load and display an image and if the load fails, then an SVG image fallback is applied to the `` element as a CSS mask targeting attached `str-chat__base-image--load-failed` class. + +| Type | Default | +| --------- | ----------------------------------------------------------------- | +| component | | + +### CooldownTimer + +Custom UI component to display the slow mode cooldown timer. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------ | +| component | | + +### CustomMessageActionsList + +Custom UI component to render set of buttons to be displayed in the . + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------------------------- | +| component | | + +### DateSeparator + +Custom UI component for date separators. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------- | +| component | | + +### EditMessageInput + +Custom UI component to override default edit message input. + +| Type | Default | +| --------- | ---------------------------------------------------------------------------------- | +| component | | + +### EmojiIcon + +Custom UI component for emoji button in input. + +| Type | Default | +| --------- | ----------------------------------------------------------------------- | +| component | | + +### EmptyStateIndicator + +Custom UI component to be displayed when the `MessageList` is empty. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------------------- | +| component | | + +### FileUploadIcon + +Custom UI component for file upload icon. + +| Type | Default | +| --------- | ----------------------------------------------------------------------- | +| component | | + +### GiphyPreviewMessage + +Custom UI component to render a Giphy preview in the `VirtualizedMessageList`. + +| Type | Default | +| --------- | ----------------------------------------------------------------------------------------- | +| component | | + +### HeaderComponent + +Custom UI component to render at the top of the `MessageList`. + +| Type | Default | +| --------- | ------- | +| component | none | + +### Input + +Custom UI component handling how the message input is rendered. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------ | +| component | | + +### LinkPreviewList + +Custom component to render link previews in `MessageInput`. + +| Type | Default | +| --------- | ----------------------------------------------------------------------------------- | +| component | | + +### LoadingErrorIndicator + +Custom UI component to be shown if the channel query fails. + +| Type | Default | +| --------- | ----------------------------------------------------------------------------------------- | +| component | | + +### LoadingIndicator + +Custom UI component to render while the `MessageList` is loading new messages. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------- | +| component | | + +### Message + +Custom UI component to display a message in the standard `MessageList`. + +| Type | Default | +| --------- | ------------------------------------------------------------------------- | +| component | | + +### MessageDeleted + +Custom UI component for a deleted message. + +| Type | Default | +| --------- | --------------------------------------------------------------------------- | +| component | | + +### MessageListNotifications + +Custom UI component that displays message and connection status notifications in the `MessageList`. + +| Type | Default | +| --------- | ---------------------------------------------------------------------------------------------------------- | +| component | | + +### MessageNotification + +Custom UI component to display a notification when scrolled up the list and new messages arrive. + +| Type | Default | +| --------- | ----------------------------------------------------------------------------------------- | +| component | | + +### MessageOptions + +Custom UI component for message options popup. + +| Type | Default | +| --------- | --------------------------------------------------------------------------- | +| component | | + +### MessageRepliesCountButton + +Custom UI component to display message replies. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------------------- | +| component | | + +### MessageStatus + +Custom UI component to display message delivery status. + +| Type | Default | +| --------- | ------------------------------------------------------------------------- | +| component | | + +### MessageSystem + +Custom UI component to display system messages. + +| Type | Default | +| --------- | ---------------------------------------------------------------------------------- | +| component | | + +### MessageTimestamp + +Custom UI component to display a timestamp on a message. This does not include a timestamp for edited messages. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------- | +| component | | + +See also [`Timestamp`](#timestamp). + +### MessageBouncePrompt + +Custom UI component for the content of the modal dialog for messages that got bounced by the moderation rules. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------------- | +| component | | + +### ModalGallery + +Custom UI component for viewing message's image attachments. + +| Type | Default | +| --------- | ----------------------------------------------------------------------- | +| component | | + +### PinIndicator + +Custom UI component to override default pinned message indicator. + +| Type | Default | +| --------- | ---------------------------------------------------------------- | +| component | | + +### QuotedMessage + +Custom UI component to override quoted message UI on a sent message. + +| Type | Default | +| --------- | ------------------------------------------------------------------------- | +| component | | + +### QuotedMessagePreview + +Custom UI component to override the message input's quoted message preview. + +| Type | Default | +| --------- | -------------------------------------------------------------------------------------------- | +| component | | + +### ReactionSelector + +Custom UI component to display the reaction selector. + +| Type | Default | +| --------- | --------------------------------------------------------------------------------- | +| component | | + +### ReactionsList + +Custom UI component to display the list of reactions on a message. + +| Type | Default | +| --------- | --------------------------------------------------------------------------- | +| component | | + +### SendButton + +Custom UI component for send button. + +| Type | Default | +| --------- | ------------------------------------------------------------------- | +| component | | + +### ThreadHead + +Custom UI component to be displayed at the beginning of a thread. By default, it is the thread parent message. It is composed of [Message](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Message/Message.tsx) context provider component and [ThreadStart](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Thread/ThreadStart.tsx) component. The latter can be customized by passing custom component to `Channel` props. The `ThreadHead` component defaults to and accepts the same props as [MessageSimple](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Message/MessageSimple.tsx). + +| Type | Default | +| --------- | ------------------------------------------------------------------ | +| component | | + +### ThreadHeader + +Custom UI component to display the header of a `Thread`. + +| Type | Default | +| --------- | ----------------------------------------------------------------------- | +| component | | + +### ThreadInput + +Custom UI component to replace the `MessageInput` of a `Thread`. For the applications using [theme version 1](../../guides/theming/css-and-theming.mdx), the default is `MessageInputSmall`. Applications using [theme version 2](../../theming/introduction.mdx) will use `MessageInputFlat` by default. + +| Type | Default | +| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| component | / | + +### ThreadStart + +Custom UI component to display the start of a threaded `MessageList`. + +| Type | Default | +| --------- | ---------------------------------------------------------------------- | +| component | | + +### Timestamp + +Custom UI component to display a date used in timestamps. It's used internally by the default `MessageTimestamp`, and to display a timestamp for edited messages. + +| Type | Default | +| --------- | ----------------------------------------------------------------- | +| component | | + +### TriggerProvider + +Optional context provider that lets you override the default autocomplete triggers. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------------------ | +| component | | + +### TypingIndicator + +Custom UI component for the typing indicator. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------- | +| component | | + +### UnreadMessagesNotification + +Custom UI component that indicates a user is viewing unread messages. It disappears once the user scrolls to `UnreadMessagesSeparator`. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------------------------- | +| component | | + +### UnreadMessagesSeparator + +Custom UI component inserted before the first message marked unread. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------------------- | +| component | | + +### VirtualMessage + +Custom UI component to display a message in the `VirtualizedMessageList`. + +| Type | Default | +| --------- | ------------------------------------------------------------------------- | +| component | | diff --git a/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/message-bounce-context.mdx b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/message-bounce-context.mdx new file mode 100644 index 000000000..851a668f6 --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/message-bounce-context.mdx @@ -0,0 +1,151 @@ +--- +id: message_bounce_context +title: MessageBounceContext +--- + +The `MessageBounceContext` is available inside the modal rendered by the default message component for messages that got bounced by the moderation rules. This context provides callbacks that can be used to deal with the bounced message. + +## Basic Usage + +In most cases when using the default Message UI component implementation you are not going to deal with the `MessageBounceContext` directly. However if you are customizing the Message UI component, or providing a custom `MessageBouncePrompt`, the callbacks provided by this context come in handy. + +Get values from context with our custom hook: + +```jsx +const { message, handleEdit, handleSend, handleDelete } = useMessageBounceContext(); +``` + +Use these callbacks to implement your custom `MessageBouncePrompt`. Normally this component displays three options: edit the message before sending it again, send the message again without changes (this can be useful if you are using the "Bounce then flag" moderation flow), and delete the message. + +```jsx +import { useMessageBounceContext } from 'stream-chat-react'; + +function MyCustomMessageBouncePrompt({ onClose }) { + const { message, handleEdit, handleSend, handleDelete } = useMessageBounceContext(); + return ( + <> +

Your message is in violation of our community rules.

+

Message id: "{message.id}"

+ + {/* ... */} + + ); +} +``` + +Then override the default `MessageBouncePrompt` component with your custom one: + +```jsx + + + + + + + + +``` + +## Usage in a Custom Message UI component + +When implementing your own Message component from scratch, you should consider implementing UI for bounced messages, especially if you are using one of the moderation flows with message bouncing ("Bounce", "Bounce then flag", or "Bounce then block"). + +To do that, first check if the message is bounced: + +```jsx +import { useMessageContext, isMessageBounced } from 'stream-chat-react'; + +function CustomMessage() { + const { message } = useMessageContext(); + const isBounced = isMessageBounced(message); + // ... +} +``` + +Then, display custom UI in case the message is bounced. Don't forget to wrap the UI with the `MessageBounceProvider`, so that it has access to the callbacks used to deal with the bounced message: + +```jsx +import { useMessageContext, isMessageBounced, MessageBounceProvider } from 'stream-chat-react'; + +function MyCustomMessage() { + const { message } = useMessageContext(); + const isBounced = isMessageBounced(message); + + return ( +
+ {/* ... */} + + + {isBounced && ( + + + + )} +
+ ); +} + +function MyCustomMessageBouncePrompt({ onClose }) { + const { message, handleEdit, handleSend, handleDelete } = useMessageBounceContext(); + return ( + <> + + {/* ... */} + + ); +} +``` + +It only makes sense to render `MessageBounceProvider` in the context of a bounced message, so you'll see a warning in the browser console if you try to render it for any other type of message. + +Implementing a custom Message UI component from scratch is a larger topic, covered by the [Message UI Customization](../../guides/theming/message-ui.mdx) guide. + +## Values + +### message + +The object representing the message that got bounced. + +| Type | +| ------------- | +| StreamMessage | + +### handleEdit + +Call this function to switch the bounced message into editing mode. + +| Type | +| ----------------- | +| ReactEventHandler | + +### handleSend + +Call this function to try sending the bounced message again without changes. + +| Type | +| ----------------- | +| ReactEventHandler | + +### handleDelete + +Call this function to remove the bounced message from the message list. + +| Type | +| ----------------- | +| ReactEventHandler | diff --git a/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/message-context.mdx b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/message-context.mdx new file mode 100644 index 000000000..0d8ac7962 --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/message-context.mdx @@ -0,0 +1,409 @@ +--- +id: message_context +title: MessageContext +--- + +import MessageActionsBoxWithCustomAction from '../../assets/message-actions-box-custom-actions.png'; + +The `MessageContext` is established within the [`Message`](../message-components/message.mdx) component. It provides data to the +[Message UI](../message-components/message-ui.mdx) component and its children. Use the values stored within this context to build +a custom Message UI component. You can access the context values by calling the `useMessageContext` custom hook. + +## Basic Usage + +Pull values from context with our custom hook: + +```jsx +const { message, threadList } = useMessageContext(); +``` + +## Values + +### actionsEnabled + +If true, actions such as edit, delete, flag, etc. are enabled on the message. + +| Type | Default | +| ------- | ------- | +| boolean | true | + +### additionalMessageInputProps + +Additional props to be passed to the underlying [`MessageInput`](../message-input-components/message-input.mdx) component that's rendered +while editing. + +| Type | +| ------ | +| object | + +### autoscrollToBottom + +Call this function to keep message list scrolled to the bottom when the message list container scroll height increases (only available in the `VirtualizedMessageList`). An example use case is that upon user's interaction with the application, a new element appears below the last message. In order to keep the newly rendered content visible, the `autoscrollToBottom` function can be called. The container, however, is not scrolled to the bottom, if already scrolled up more than 4px from the bottom. + +| Type | +| ---------- | +| () => void | + +### clearEditingState + +When called, this function will exit the editing state on the message. + +| Type | +| ------------------------------------------ | +| (event?: React.BaseSyntheticEvent) => void | + +### customMessageActions + +An object containing custom message actions (key) and function handlers (value). The key is used as a display text inside the button. Therefore, it should not be cryptic but rather bear the end user in mind when formulating it. + +```jsx +const customActions = { + 'Copy text': (message) => { + navigator.clipboard.writeText(message.text || ''); + }, +}; + +; +``` + +Custom action item "Copy text" in the message actions box: + +Image of a custom action item "Copy text" in the message actions box + +| Type | +| ------ | +| object | + +### editing + +If true, the message toggles to an editing state. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### endOfGroup + +When true, the message is the last one in a group sent by a specific user (only used in the `VirtualizedMessageList`). + +| Type | +| ------- | +| boolean | + +### firstOfGroup + +When true, the message is the first one in a group sent by a specific user (only used in the `VirtualizedMessageList`). + +| Type | +| ------- | +| boolean | + +### formatDate + +Overrides the default date formatting logic, has access to the original date object. + +| Type | +| ---------------------- | +| (date: Date) => string | + +### getMessageActions + +Function that returns an array of the allowed actions on a message by the currently connected user. + +| Type | +| ------------------------- | +| () => MessageActionsArray | + +### groupedByUser + +If true, group messages sent by each user (only used in the `VirtualizedMessageList`). + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### groupStyles + +An array of potential styles to apply to a grouped message (ex: top, bottom, single). + +| Type | Options | +| -------- | ----------------------------------------------- | +| string[] | '' \| 'middle' \| 'top' \| 'bottom' \| 'single' | + +### handleAction + +Function that calls an action on a message. + +| Type | +| ----------------------------------------------------------------------------------------------------- | +| (dataOrName?: string \| FormData, value?: string, event?: React.BaseSyntheticEvent) => Promise | + +### handleDelete + +Function that removes a message from the current channel. + +| Type | +| ----------------------------------------------------------- | +| (event: React.BaseSyntheticEvent) => Promise \| void | + +### handleEdit + +Function that edits a message. + +| Type | +| ----------------------------------------------------------- | +| (event: React.BaseSyntheticEvent) => Promise \| void | + +### handleFetchReactions + +Function that loads the reactions for a message. + +| Type | +| ------------------------------------- | +| () => Promise \ | + +This function limits the number of loaded reactions to 1200. To customize this behavior, you can pass [a custom `ReactionsList` component](../message-components/reactions.mdx#handlefetchreactions). + +### handleFlag + +Function that flags a message. + +| Type | +| ----------------------------------------------------------- | +| (event: React.BaseSyntheticEvent) => Promise \| void | + +### handleMarkUnread + +Function that marks the message and all the following messages as unread in a channel. + +| Type | +| ----------------------------------------------------------- | +| (event: React.BaseSyntheticEvent) => Promise \| void | + +### handleMute + +Function that mutes the sender of a message. + +| Type | +| ----------------------------------------------------------- | +| (event: React.BaseSyntheticEvent) => Promise \| void | + +### handleOpenThread + +Function that opens a [`Thread`](../core-components/thread.mdx) on a message. + +| Type | +| ----------------------------------------------------------- | +| (event: React.BaseSyntheticEvent) => Promise \| void | + +### handlePin + +Function that pins a message in the current channel. + +| Type | +| ----------------------------------------------------------- | +| (event: React.BaseSyntheticEvent) => Promise \| void | + +### handleReaction + +Function that adds/removes a reaction on a message. + +| Type | +| ------------------------------------------------------------------------- | +| (reactionType: string, event: React.BaseSyntheticEvent) => Promise | + +### handleRetry + +Function that retries sending a message after a failed request (overrides the function stored in `ChannelActionContext`). + +| Type | +| ------------------------------------------ | +| (message: StreamMessage) => Promise | + +### highlighted + +Whether to highlight and focus the message on load. + +| Type | +| ------- | +| boolean | + +### initialMessage + +When true, signifies the message is the parent message in a thread list. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### isMyMessage + +Function that returns whether or not a message belongs to the current user. + +| Type | +| ------------- | +| () => boolean | + +### isReactionEnabled (deprecated) + +If true, sending reactions is enabled in the currently active channel. + +| Type | Default | +| ------- | ------- | +| boolean | true | + +### lastReceivedId + +The latest message ID in the current channel. + +| Type | +| ------ | +| string | + +### message + +The `StreamChat` message object, which provides necessary data to the underlying UI components. + +| Type | +| ------ | +| object | + +### messageListRect + +DOMRect object linked to the parent `MessageList` component. + +| Type | +| ------- | +| DOMRect | + +### mutes + +An array of users that have been muted by the connected user. + +| Type | Default | +| ------ | ----------------------------------------------------------- | +| Mute[] | [ChannelStateContext['mutes']](./channel-state-context.mdx) | + +### onMentionsClickMessage + +Function that runs on click of an @mention in a message. + +| Type | +| ----------------------------------------------------------- | +| (event: React.BaseSyntheticEvent) => Promise \| void | + +### onMentionsHoverMessage + +Function that runs on hover of an @mention in a message. + +| Type | +| ----------------------------------------------------------- | +| (event: React.BaseSyntheticEvent) => Promise \| void | + +### onReactionListClick + +Function that runs on click of the reactions list component. + +| Type | +| ----------------------------------------------------------- | +| (event: React.BaseSyntheticEvent) => Promise \| void | + +### onUserClick + +Function that runs on click of a user avatar. + +| Type | +| ----------------------------------------------------------- | +| (event: React.BaseSyntheticEvent) => Promise \| void | + +### onUserHover + +Function that runs on hover of a user avatar. + +| Type | +| ----------------------------------------------------------- | +| (event: React.BaseSyntheticEvent) => Promise \| void | + +### pinPermissions + +The user roles allowed to pin messages in various channel types (deprecated in favor of `channelCapabilities`). + +| Type | Default | +| ------ | ------------------------------------------------------------------------- | +| object | | + +### reactionSelectorRef + +Ref to be placed on the reaction selector component. + +| Type | +| --------------------------------------- | +| React.MutableRefObject | + +### readBy + +An array of users that have read the current message. + +| Type | +| ----- | +| array | + +### renderText + +Custom function to render message text content. + +| Type | Default | +| -------- | ------------------------------------------------------------------------------ | +| function | | + +### setEditingState + +Function to toggle the editing state on a message. + +| Type | +| ----------------------------------------------------------- | +| (event: React.BaseSyntheticEvent) => Promise \| void | + +### showDetailedReactions + +When true, show the reactions list component. + +| Type | +| ------- | +| boolean | + +### sortReactionDetails + +Comparator function to sort the list of reacted users. Should have the same signature as an array's `sort` method. + +| Type | Default | +| ---------------------------------------------------------- | ------------------ | +| (this: ReactionResponse, that: ReactionResponse) => number | alphabetical order | + +### sortReactions + +Comparator function to sort reactions. Should have the same signature as an array's `sort` method. + +| Type | Default | +| -------------------------------------------------------- | ------------------ | +| (this: ReactionSummary, that: ReactionSummary) => number | alphabetical order | + +### threadList + +If true, indicates that the current `MessageList` component is part of a `Thread`. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### unsafeHTML + +If true, renders HTML instead of markdown. Posting HTML is only supported server-side. + +| Type | Default | +| ------- | ------- | +| boolean | false | diff --git a/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/message-input-context.mdx b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/message-input-context.mdx new file mode 100644 index 000000000..2cfc44b4f --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/message-input-context.mdx @@ -0,0 +1,535 @@ +--- +id: message_input_context +title: MessageInputContext +--- + +The `MessageInputContext` is established within the [`MessageInput`](../message-input-components/message-input.mdx) component. +The value is the combination of the `MessageInputProps`, `MessageInputState` (returned by the `useMessageInputState` hook), and `cooldownTimerState` (returned by the `useCooldownTimer hook`). +It provides data to the [Input UI](../message-input-components/input-ui.mdx) component and its children. Use the values stored +within this context to build a custom Input UI component. You can access the context values by calling the `useMessageInputContext` +custom hook. + +## Basic Usage + +Pull values from context with our custom hook: + +```jsx +const { autocompleteTriggers, handleSubmit } = useMessageInputContext(); +``` + +## Values + +### additionalTextareaProps + +Additional props to be passed to the underlying `AutoCompleteTextarea` component, [available props](https://www.npmjs.com/package/react-textarea-autosize). + +| Type | +| ------ | +| object | + +### attachments + +An array of attachments added to the current message. + +| Type | +| ------------ | +| Attachment[] | + +### autocompleteTriggers + +A mapping of the current triggers permitted in the currently active channel. + +| Type | Default Triggers | +| ------ | ---------------- | +| object | `/` - commands | +| | `@` - mentions | +| | `:` - emojis | + +### cancelURLEnrichment + +Function cancels all the scheduled or in-progress URL enrichment queries and resets the state. + +| Type | +| ---------- | +| () => void | + +### clearEditingState + +Function to clear the editing state while editing a message. + +| Type | +| ---------- | +| () => void | + +### closeCommandsList + +Function to manually close the list of supported slash commands. + +| Type | +| ---------- | +| () => void | + +### closeEmojiPicker + +Function to close the `EmojiPicker` component. + +| Type | +| ------------------------------------------- | +| React.MouseEventHandler | + +### closeEmojiPickerOnClick + +If true, picking an emoji from the `EmojiPicker` component will close the picker. + +| Type | +| ------- | +| boolean | + +### closeMentionsList + +Function to manually close the list of potential users to mention. + +| Type | +| ---------- | +| () => void | + +### cooldownInterval + +If slow mode is enabled, the required wait time between messages for each user. + +| Type | +| ------ | +| number | + +### cooldownRemaining + +If slow mode is enabled, the amount of time remaining before the connected user can send another message. + +| Type | +| ------ | +| number | + +### disabled + +If true, disables the text input. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### disableMentions + +If true, the suggestion list will not display and autocomplete @mentions. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### dismissLinkPreview + +Function called when a single link preview is dismissed. + +| Type | +| ---------------------------------- | +| (linkPreview: LinkPreview) => void | + +### doFileUploadRequest + +Function to override the default file upload request. + +| Type | +| ----------------------------------------------------------------------------- | +| (file: FileUpload['file'], channel: Channel) => Promise | + +### doImageUploadRequest + +Function to override the default image upload request. + +| Type | +| ------------------------------------------------------------------------------ | +| (file: ImageUpload['file'], channel: Channel) => Promise | + +### emojiIndex + +Custom class constructor to override default `NimbleEmojiIndex` from ['emoji-mart'](https://www.npmjs.com/package/emoji-mart). + +| Type | Default | +| ----------- | -------------------------------------------------------------------- | +| constructor | [ComponentContext['EmojiIndex']](./component-context.mdx#emojiindex) | + +### emojiPickerIsOpen + +If true, signifies the `EmojiPicker` component is currently open. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### emojiPickerRef + +React mutable ref placed on the `EmojiPicker` container `div`. + +| Type | +| --------------------------------------- | +| React.MutableRefObject | + +### errorHandler + +Custom error handler function to be called with a file/image upload fails. + +| Type | +| ------------------------------------------------------------------------------------------------- | +| (error: Error, type: string, file: (FileUpload \| ImageUpload)['file'] & { id?: string }) => void | + +### fileOrder + +The order in which file attachments have been added to the current message. + +| Type | +| -------- | +| string[] | + +### fileUploads + +A mapping of the file attachments added to the current message. + +| Type | +| ---------------------------- | +| { [id: string]: FileUpload } | + +### findAndEnqueueURLsToEnrich + +A function responsible for initiating URL discovery and their subsequent enrichment. It is available only if link preview rendering is enabled. Link previews are disabled by default. + +| Type | +| ------------------------------------------------- | +| (text: string, mode?: SetLinkPreviewMode) => void | + +### focus + +If true, focuses the text input on component mount. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### grow + +If true, expands the text input vertically for new lines. + +| Type | Default | +| ------- | ------- | +| boolean | true | + +### handleChange + +Function that runs onChange to the underlying `textarea` component. + +| Type | +| ---------------------------------------------- | +| React.ChangeEventHandler | + +### handleEmojiKeyDown + +Opens the `EmojiPicker` component on Enter or Spacebar key down. + +| Type | +| -------------------------------------------- | +| React.KeyboardEventHandler | + +### handleSubmit + +Function that runs onSubmit to the underlying `textarea` component. + +| Type | +| ---------------------------------------------------------------------- | +| (event: React.BaseSyntheticEvent, customMessageData?: Message) => void | + +### hideSendButton + +Allows to hide MessageInput's send button. Used by `MessageSimple` to hide the send button in `EditMessageForm`. Received from `MessageInputProps`. + +| Type | Default | +|---------|---------| +| boolean | false | + +### imageOrder + +The order in which image attachments have been added to the current message. + +| Type | +| -------- | +| string[] | + +### imageUploads + +A mapping of the image attachments added to the current message. + +| Type | +| ----------------------------- | +| { [id: string]: ImageUpload } | + +### insertText + +Function to insert text into the value of the underlying `textarea` component. + +| Type | +| ------------------------------ | +| (textToInsert: string) => void | + +### isUploadEnabled + +If true, file uploads are enabled in the currently active channel. + +| Type | Default | +| ------- | ------- | +| boolean | true | + +### linkPreviews + +A Map of `LinkPreview` objects (a union type of `LinkPreviewState` and `OGAttachment`) indexed by string representing link URL. The link URL value is provided by `OGAttachment.og_scrape_url`. + +| Type | +| -------------------------- | +| Map | + +### shouldSubmit + +Currently, `Enter` is the default submission key and `Shift`+`Enter` is the default combination for the new line. +If specified, this function overrides the default behavior specified previously. + +| Type | +| --------------------------------- | +| (event: KeyboardEvent) => boolean | + +### maxFilesLeft + +The maximum number of allowed uploads minus the current number of uploads. + +| Type | +| ------ | +| number | + +### maxRows + +Max number of rows the underlying `textarea` component is allowed to grow. + +| Type | Default | +| ------ | ------- | +| number | 10 | + +### mentionAllAppUsers + +If true, the suggestion list will search all app users for an @mention, not just current channel members/watchers. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### mentioned_users + +An array of users mentioned in the current message. + +| Type | +| -------------- | +| UserResponse[] | + +### mentionQueryParams + +Object containing filters/sort/options overrides for an @mention user query. + +| Type | +| ------ | +| object | + +### message + +If provided, the existing message will be edited on submit. + +| Type | +| ------ | +| object | + +### noFiles + +If true, disables file uploads for all attachments except for those with type 'image'. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### numberOfUploads + +The number of file uploads on the current message. + +| Type | +| ------ | +| number | + +### onPaste + +Function that runs onPaste to the underlying `textarea` component. + +| Type | +| ----------------------------------------------------------- | +| (event: React.ClipboardEvent) => void | + +### onSelectEmoji + +Function that runs on select of an emoji in the `EmojiPicker` component. + +| Type | +| -------------------------- | +| (emoji: EmojiData) => void | + +### onSelectUser + +Function that runs on select of a user in the suggestion list following an @mention. + +| Type | +| ---------------------------- | +| (item: UserResponse) => void | + +### openCommandsList + +Function to manually open the list of supported slash commands. + +| Type | +| ---------- | +| () => void | + +### openEmojiPicker + +Function to open the `EmojiPicker` component. + +| Type | +| ----------------------------------------- | +| React.MouseEventHandler | + +### openMentionsList + +Function to manually open the list of potential users to mention. + +| Type | +| ---------- | +| () => void | + +### overrideSubmitHandler + +Function to override the default submit handler. + +| Type | +| --------------------------------------------- | +| (message: object, channelCid: string) => void | + +### parent + +When replying in a thread, the parent message object. + +| Type | +| ------ | +| object | + +### publishTypingEvent + +If true, triggers typing events on text input keystroke. + +| Type | Default | +| ------- | ------- | +| boolean | true | + +### removeFile + +Function to remove a file from the `fileUploads` mapping. + +| Type | +| -------------------- | +| (id: string) => void | + +### removeImage + +Function to remove an image from the `imageUploads` mapping. + +| Type | +| -------------------- | +| (id: string) => void | + +### setCooldownRemaining + +React state hook function that sets the `cooldownRemaining` value. + +| Type | +| --------------------------------------------- | +| React.Dispatch> | + +### setText + +Function that overrides and sets the text value of the underlying `textarea` component. + +| Type | +| ---------------------- | +| (text: string) => void | + +### showCommandsList + +If true, show the list of supported slash commands above the text input. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### showMentionsList + +If true, show the list of potential users to mention above the text input. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### text + +The current input value of the underlying `textarea` component. + +| Type | +| ------ | +| string | + +### textareaRef + +React mutable ref placed on the underlying `textarea` component. + +| Type | +| -------------------------------------------- | +| React.MutableRefObject | + +### uploadFile + +Function to upload a file to the `fileUploads` mapping. + +| Type | +| -------------------- | +| (id: string) => void | + +### uploadImage + +Function to upload an image. + +| Type | +| -------------------- | +| (id: string) => void | + +### uploadNewFiles + +Function to upload an array of files to the `fileUploads` and `imageUploads` mappings. + +| Type | +| ----------------------------------- | +| (files: FileList \| File[]) => void | + +### useMentionsTransliteration + +If true, will use an optional dependency to support transliteration in the input for mentions. See: https://github.com/sindresorhus/transliterate + +| Type | Default | +| ------- | ------- | +| boolean | false | diff --git a/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/message-list-context.mdx b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/message-list-context.mdx new file mode 100644 index 000000000..77b7fcbfb --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/message-list-context.mdx @@ -0,0 +1,52 @@ +--- +id: message_list_context +title: MessageListContext +--- + +The context value is provided by `MessageListContextProvider` which wraps the contents rendered by [`MessageList`](../core-components/message-list.mdx). It exposes API that the default and custom components rendered by `MessageList` can take advantage of. The components that can consume the context are: + +- `EmptyStateIndicator` - rendered when there are no messages in the channel. The [`component can be customized`](./component-context.mdx#emptystateindicator). +- `LoadingIndicator` - rendered while loading more messages to the channel. The [`component can be customized`](./component-context.mdx#loadingindicator). +- `MessageListNotifications` - component rendering application notifications. The [`component can be customized`](./component-context.mdx#messagelistnotifications). +- `MessageNotification` - component used to display a single notification message in `MessageListNotifications`. The [`component can be customized`](./component-context.mdx#messagenotification). +- `TypingIndicator` - component indicating that another user is typing a message in a given channel. The [`component can be customized`](./component-context.mdx#typingindicator). +- `Message` and its children - component to render a message. The [`component can be customized`](./component-context.mdx#message). +- `DateSeparator` - component rendered to separate messages posted on different dates. The [`component can be customized`](./component-context.mdx#dateseparator). +- `MessageSystem` - component to display system messages in the message list. The [`component can be customized`](./component-context.mdx#messagesystem). +- `HeaderComponent` - component to be displayed before the oldest message in the message list. The [`component can be customized`](./component-context.mdx#headercomponent). +- `UnreadMessagesNotification` - custom UI component that indicates a user is viewing unread messages. It disappears once the user scrolls to `UnreadMessagesSeparator`. The [`component can be customized`](./component-context.mdx#unreadmessagesnotification). +- `UnreadMessagesSeparator` - component to be displayed before the oldest message in the message list. The [`component can be customized`](./component-context.mdx#unreadmessagesseparator). + +## Basic Usage + +Pull the value from context with our custom hook: + +```jsx +import { useMessageListContext } from 'stream-chat-react'; + +export const CustomComponent = () => { + const { listElement, scrollToBottom } = useMessageListContext(); + // component logic ... + return( + {/* rendered elements */} + ); +} +``` + +## Value + +### listElement + +The scroll container within which the messages and typing indicator are rendered. You may want to perform scroll-to-bottom operations based on the `listElement`'s scroll state. + +| Type | +|--------------------------| +| `HTMLDivElement \| null` | + +### scrollToBottom + +Function that scrolls the `listElement` to the bottom. + +| Type | +|--------------| +| `() => void` | diff --git a/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/translation-context.mdx b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/translation-context.mdx new file mode 100644 index 000000000..2581f1f6b --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/translation-context.mdx @@ -0,0 +1,45 @@ +--- +id: translation_context +title: TranslationContext +--- + +The component library uses the [`i18next`](https://www.npmjs.com/package/i18next) dependency to create a `Streami18n` +class constructor that handles language translation. The `TranslationContext` stores the resulting values and allows +children of the `Chat` component to auto translate library text based on the connected user's set languages. +You can access the context values by calling the `useTranslationContext` custom hook. + +## Basic Usage + +Pull values from context with our custom hook: + +```jsx +const { t } = useTranslationContext(); + +
{t('This message will be translated.')}
; +``` + +## Values + +### t + +Function that translates text into the connected user's set language. + +| Type | +| -------- | +| function | + +### tDateTimeParser + +Function that parses date times. + +| Type | Default | +| -------- | ------- | +| function | Day.js | + +### userLanguage + +Value to set the connected user's language (ex: 'en', 'fr', 'ru', etc), which auto translates text fields in the library. + +| Type | Default | +| ------ | ------- | +| string | 'en' | diff --git a/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/typing-context.mdx b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/typing-context.mdx new file mode 100644 index 000000000..5770fbc0d --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/components/contexts/typing-context.mdx @@ -0,0 +1,25 @@ +--- +id: typing_context +title: TypingContext +--- + +The `TypingContext` is established by the `Channel` component and exposes the `useTypingContext` hook. The stored value is an +object of users currently typing in a single channel, with key as the user ID and value as the user details object. + +## Basic Usage + +Pull the value from context with our custom hook: + +```jsx +const { typing } = useTypingContext(); +``` + +## Value + +### typing + +The users currently typing in a single channel, with key as the user ID and value as the user details object. + +| Type | +| ------ | +| object | diff --git a/docusaurus/react_versioned_docs/version-11.x.x/components/core-components/channel-list.mdx b/docusaurus/react_versioned_docs/version-11.x.x/components/core-components/channel-list.mdx new file mode 100644 index 000000000..7c58fa1a7 --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/components/core-components/channel-list.mdx @@ -0,0 +1,544 @@ +--- +id: channel_list +title: ChannelList +--- + +import CodeBlock from '@theme/CodeBlock'; + +import GHComponentLink from '../../_docusaurus-components/GHComponentLink'; + +The `ChannelList` component queries an array of `channel` objects from the Stream Chat API and displays as a customizable list +in the UI. It accepts props for [`filters`](#filters), [`sort`](#sort) and [`options`](#options), which allows you to tailor +your request to the [Query Channels](https://getstream.io/chat/docs/javascript/query_channels/?language=javascript) API. The +response array from this API is then rendered in a list and loaded into the DOM. + +```jsx +const channels = await client.queryChannels(filters, sort, options); +``` + +The `ChannelList` component also comes pre-built with navigation functionality. The click of a list item sets the active +`channel` object and loads the [`Channel`](./channel.mdx) component. + +## Basic Usage + +The `ChannelList` does not have any required props, but in order to refine channel query results we recommend providing +values for [`filters`](#filters), [`sort`](#sort) and [`options`](#options). + +:::caution +By default when channels query does not have any filter it will match all the channels in your application. While this might be convenient during the development, you most likely want to have at least some basic filtering. + +**At a minimum, the filter should include `{members: { $in: [userID] }}` .** +::: + +```jsx +const filters = { members: { $in: [ 'jimmy', 'buffet' ] } } +const sort = { last_message_at: -1 }; +const options = { limit: 10 } + + + + + + + + +``` + +## UI Customization + +`ChannelList` UI is determined by two of its props, `List` and `Preview`. The `List` prop allows you to customize the container +in which the array of channels is rendered. The `Preview` prop dictates the design and click functionality of an individual +channel in the list. If not provided via props, these UI components default to +[`ChannelListMessenger`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/ChannelList/ChannelListMessenger.tsx) +and [`ChannelPreviewMessenger`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/ChannelPreview/ChannelPreviewMessenger.tsx). + +To customize the container and list item UI for your `ChannelList`, provide custom component overrides. Your custom components +will receive the same props as the defaults. + +```jsx +const CustomListContainer = (props) => { + // render custom list container here +}; + +const CustomListItem = (props) => { + // render custom list item here +}; + + + + + + + +; +``` + +In cases where the customizations provided by `Preview` are not enough, e.g. grouping channels under sections based on some +dynamic channel data, the `renderChannels` may be a good fit as all loaded channels are passed as an argument to the function. + +```jsx +const renderChannels = (loadedChannels, ChannelPreview) => { + const groups = groupBy(loadedChannels, 'some_custom_channel_data'); + return renderGroups(groups); // inside renderGroups you have have headings, etc... +} + + + + + + + +; +``` + +## Event Listeners + +In order to handle the requisite, dynamic nature of the `ChannelList`, a variety of +[event listeners](https://getstream.io/chat/docs/javascript/event_listening/?language=javascript) are added on component mount. +Many of these event listeners accept custom handler functions, allowing you to override the library's default event response behavior. + +Each custom handler accepts the same function arguments. Through a combination of pulling updated data off the event object and +re-setting the list state, you can customize behavior and UI. + +- `setChannels` - state setter for the `channels` value which populates the list in the DOM +- `event` - event object returned from each corresponding event listener + +| [Event Type](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) | Default Behavior | Custom Handler | +| ----------------------------------------------------------------------------------------- | ------------------------------------------------ | --------------------------------------------- | +| `channel.deleted` | Removes channel from list | [onChannelDeleted](#onchanneldeleted) | +| `channel.hidden` | Removes channel from list | [onChannelHidden](#onchannelhidden) | +| `channel.truncated` | Updates the channel | [onChannelTruncated](#onchanneltruncated) | +| `channel.updated` | Updates the channel | [onChannelUpdated](#onchannelupdated) | +| `channel.visible` | Adds channel to list | [onChannelVisible](#onchannelvisible) | +| `connection.recovered` | Forces a component render | N/A | +| `message.new` | Moves channel to top of list | [onMessageNewHandler](#onmessagenewhandler) | +| `notification.added_to_channel` | Moves channel to top of list and starts watching | [onAddedToChannel](#onaddedtochannel) | +| `notification.message_new` | Moves channel to top of list and starts watching | [onMessageNew](#onmessagenew) | +| `notification.removed_from_channel` | Removes channel from list | [onRemovedFromChannel](#onremovedfromchannel) | +| `user.presence.changed` | Updates the channel | N/A | + +## Customizing Event Handlers + +The event type the `ChannelList` reacts to and its corresponding behavior can be overridden using the appropriate prop. Let's look at an example of customizing the ChannelList component to only display [frozen channels](https://getstream.io/chat/docs/javascript/freezing_channels/). + +```tsx +const filters = { + members: { $in: ['dan'] }, + frozen: true +} + + +``` + +The `notification.message_new` event occurs when a message is received on a channel that is not loaded but the current user is a member of. +The default behavior when this event occurs is to query the channel the message is received on, then add the channel to the top of the list, irrespective of `filters`. +Thus, if a new message appears in an unfrozen channel of which the current user is a member, it will be added to the list. This may not be the desired behavior since the list is only supposed to show frozen channels. + +In this case, you can replace the default functionality by providing a custom `onMessageNew` function as a prop to the `ChannelList` component. +`onMessageNew` receives two parameters when called, `setChannels`, a setter function for the internal `channels` state, and `event`, the `Event` object received for the `notification.message_new` event. +These parameters can be used to create a function that achieves the desired custom behavior. + +```tsx +const filters = { + members: { $in: ['dan'] }, + frozen: true, +}; + +const customOnMessageNew = async (setChannels, event) => { + const eventChannel = event.channel; + + // If the channel isn't frozen, then don't add it to the list. + if (!eventChannel?.id || !eventChannel.frozen) return; + + try { + const newChannel = client.channel(eventChannel.type, eventChannel.id); + await newChannel.watch(); + setChannels((channels) => [newChannel, ...channels]); + } catch (error) { + console.log(error); + } +}; + +; +``` + +Similarly, events other than `notification.message_new` can be handled as per application requirements. + +## Props + +### additionalChannelSearchProps + +Additional props to be passed to the underlying [`ChannelSearch`](../utility-components/channel-search.mdx) component. + +| Type | +| ------ | +| object | + +### allowNewMessagesFromUnfilteredChannels + +When the client receives `message.new`, `notification.message_new`, and `notification.added_to_channel` events, we automatically push +that channel to the top of the list. If the channel doesn't currently exist in the list, we grab the channel from `client.activeChannels` +and push it to the top of the list. You can disable this behavior by setting this prop to false, which will prevent channels not in the +list from incrementing the list. + +| Type | Default | +| ------- | ------- | +| boolean | true | + +### Avatar + +Custom UI component to display the user's avatar. + +| Type | Default | +| --------- | ---------------------------------------------------------- | +| component | | + +### channelRenderFilterFn + +Optional function to filter channels prior to loading in the DOM. Do not use any complex or async logic that would delay the +loading of the `ChannelList`. We recommend using a pure function with array methods like filter/sort/reduce. + +| Type | +| ---------------------------------- | +| (channels: Channel[]) => Channel[] | + +### ChannelSearch + +Custom UI component to display search results. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------- | +| component | | + +### customActiveChannel + +Set a channel (with this ID) to active and force it to move to the top of the list. + +| Type | +| ------ | +| string | + +### customQueryChannels + +Custom function that handles the channel pagination. + +Takes parameters: + +| Parameter | Description | +|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `currentChannels` | The state of loaded `Channel` objects queried thus far. Has to be set with `setChannels` (see below). | +| `queryType` | A string indicating, whether the channels state has to be reset to the first page ('reload') or newly queried channels should be appended to the `currentChannels`. | +| `setChannels` | Function that allows us to set the channels state reflected in `currentChannels`. | +| `setHasNextPage` | Flag indicating whether there are more items to be loaded from the API. Should be infered from the comparison of the query result length and the query options limit. | + +The function has to: +1. build / provide own query filters, sort and options parameters +2. query and append channels to the current channels state +3. update the `hasNext` pagination flag after each query with `setChannels` function + +An example below implements a custom query function that uses different filters sequentially once a preceding filter is exhausted: + +```ts +import uniqBy from "lodash.uniqby"; +import throttle from 'lodash.throttle'; +import {useCallback, useRef} from 'react'; +import {ChannelFilters, ChannelOptions, ChannelSort, StreamChat} from 'stream-chat'; +import { + CustomQueryChannelParams, + useChatContext, +} from 'stream-chat-react'; + +const DEFAULT_PAGE_SIZE = 30 as const; + +export const useCustomQueryChannels = () => { + const { client } = useChatContext(); + const filters1: ChannelFilters = { + member_count: { $gt: 10 }, + members: { $in: [client.user?.id || ''] }, + type: 'messaging', + }; + const filters2: ChannelFilters = { members: { $in: [client.user?.id || ''] }, type: 'messaging' }; + const options: ChannelOptions = { limit: 10, presence: true, state: true }; + const sort: ChannelSort = { last_message_at: -1, updated_at: -1 }; + + const filtersArray = [filters1, filters2]; + const appliedFilterIndex = useRef(0); + + const customQueryChannels = useCallback( + throttle( + async ({ + currentChannels, + queryType, + setChannels, + setHasNextPage, + }: CustomQueryChannelParams) => { + const offset = queryType === 'reload' ? 0 : currentChannels.length; + + const newOptions = { + limit: options.limit ?? DEFAULT_PAGE_SIZE, + offset, + ...options, + }; + + const filters = filtersArray[appliedFilterIndex.current]; + const channelQueryResponse = await client.queryChannels(filters, sort || {}, newOptions); + + const newChannels = + queryType === 'reload' + ? channelQueryResponse + : uniqBy([...currentChannels, ...channelQueryResponse], 'cid'); + + setChannels(newChannels); + + const lastPageForCurrentFilter = channelQueryResponse.length < newOptions.limit; + const isLastPageForAllFilters = + lastPageForCurrentFilter && appliedFilterIndex.current === filtersArray.length - 1; + + setHasNextPage(!isLastPageForAllFilters); + if (lastPageForCurrentFilter) { + appliedFilterIndex.current += 1; + } + }, + 500, + { leading: true, trailing: false }, + ), + [client, filtersArray], + ); + + return customQueryChannels; +}; +``` + +It is recommended to control for duplicate requests by throttling the custom function calls. + +| Type | +|---------------------------------------------------------------------------------------------------| +| | + +### EmptyStateIndicator + +Custom UI component for rendering an empty list. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------------------- | +| component | | + +### filters + +An object containing channel query filters, check our [query parameters docs](https://getstream.io/chat/docs/javascript/query_channels/?language=javascript#query-parameters) +for more information. + +| Type | +| ------ | +| object | + +### List + +Custom UI component to display the container for the queried channels. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------------- | +| component | | + +### LoadingErrorIndicator + +Custom UI component to display the loading error indicator. + +| Type | Default | +| --------- | ---------------------------------------------------------------- | +| component | | + +### LoadingIndicator + +Custom UI component to display the loading state. + +| Type | Default | +| --------- | ----------------------------------------------------------------------------- | +| component | | + +### lockChannelOrder + +When true, channels won't dynamically sort by most recent message. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### onAddedToChannel + +Function to override the default behavior when a user is added to a channel. + +| Type | +| -------- | +| function | + +### onChannelDeleted + +Function to override the default behavior when a channel is deleted. + +| Type | +| -------- | +| function | + +### onChannelHidden + +Function to override the default behavior when a channel is hidden. + +| Type | +| -------- | +| function | + +### onChannelTruncated + +Function to override the default behavior when a channel is truncated. + +| Type | +| -------- | +| function | + +### onChannelUpdated + +Function to override the default behavior when a channel is updated. + +| Type | +| -------- | +| function | + +### onChannelVisible + +Function to override the default channel visible behavior. + +| Type | +| -------- | +| function | + +### onMessageNew + +Function to override the default behavior when a message is received on a channel not being watched. + +| Type | +| -------- | +| function | + +### onMessageNewHandler + +Function to override the default behavior when a message is received on a channel being watched. Handles `message.new` event. + +| Type | +|-------------------------------------------------------------------------------------------------------------------------------------| +| `(setChannels: React.Dispatch>>>, event: Event) => void` | + +### onRemovedFromChannel + +Function to override the default behavior when a user gets removed from a channel. + +| Type | +| -------- | +| function | + +### options + +An object containing channel query options, check our [query parameters docs](https://getstream.io/chat/docs/javascript/query_channels/?language=javascript#query-parameters) +for more information. + +| Type | +| ------ | +| object | + +### Paginator + +Custom UI component to handle channel pagination logic. + +| Type | Default | +| --------- | ---------------------------------------------------------------------------------- | +| component | | + +### Preview + +Custom UI component to display the channel preview in the list. + +| Type | Default | +| --------- | ---------------------------------------------------------------------------------------------------- | +| component | | + +### recoveryThrottleIntervalMs + +Custom interval during which the recovery channel list queries will be prevented. This is to avoid firing unnecessary queries during internet connection fluctuation. Recovery channel query is triggered upon internet connection recovery and leads to complete channel list reload with pagination offset 0. The minimum throttle interval is 2000ms. The default throttle interval is 5000ms. + +The channel list recovery mechanism described here (applying `recoveryThrottleIntervalMs`) **is activated only if the `StreamChat` client's channel list recovery mechanism is disabled**. The `StreamChat` recovery mechanism can be disabled when initiating the client instance through the `options` parameter: + +```typescript jsx +import { StreamChat } from 'stream-chat'; +import { ChannelList, Chat } from 'stream-chat-react'; + +// ... get apiKey, filters, sort, options + +const client = new StreamChat(apiKey, {recoverStateOnReconnect: false}); +const App = () => ( + + {/** ... */} + + {/** ... */} + +); + +``` + +| Type | Default | +|--------|---------| +| number | 5000 | + +### renderChannels + +Function to override the default behavior when rendering channels, so this function is called instead of rendering the Preview directly. + +| Type | +| -------- | +| function | + +### sendChannelsToList + +If true, sends the list's currently loaded channels to the `List` component as the `loadedChannels` prop. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### setActiveChannelOnMount + +If true, sets the most recent channel received from the query as active on component mount. If set to `false` no channel is set as active on mount. + +| Type | Default | +| ------- | ------- | +| boolean | true | + +### showChannelSearch + +If true, renders the [`ChannelSearch`](./#channelsearch) component above the [`List`](./#list) component. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### sort + +An object containing channel query sort parameters. Check our [query parameters docs](https://getstream.io/chat/docs/javascript/query_channels/?language=javascript#query-parameters) +for more information. + +| Type | +| ------ | +| object | + +### watchers + +An object containing query parameters for fetching channel watchers. + +| Type | +| ------------------------------------- | +| `{ limit?: number; offset?: number }` | diff --git a/docusaurus/react_versioned_docs/version-11.x.x/components/core-components/channel.mdx b/docusaurus/react_versioned_docs/version-11.x.x/components/core-components/channel.mdx new file mode 100644 index 000000000..b975f86e6 --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/components/core-components/channel.mdx @@ -0,0 +1,762 @@ +--- +id: channel +title: Channel +--- + +import GHComponentLink from '../../_docusaurus-components/GHComponentLink'; + +The `Channel` component is a React Context provider that wraps all the logic, functionality, and UI for an individual chat channel. +It provides four separate contexts to its children: + +- [`ChannelStateContext`](../contexts/channel-state-context.mdx) - stateful data (ex: `messages` or `members`) +- [`ChannelActionContext`](../contexts/channel-action-context.mdx) - action handlers (ex: `sendMessage` or `openThread`) +- [`ComponentContext`](../contexts/component-context.mdx) - custom component UI overrides (ex: `Avatar` or `Message`) +- [`TypingContext`](../contexts/typing-context.mdx) - object of currently typing users (i.e., `typing`) + +:::note +The `Channel` component renders an individual `channel` object. For detailed information regarding `channel` objects and their +functionality, check out the [JavaScript docs](https://getstream.io/chat/docs/javascript/creating_channels/) on our website. +::: + +## Basic Usage + +The `Channel` component does not inject any UI, so its implementation is fairly simple and can be handled in one of two ways, both +with and without a `ChannelList` component. If you are using a `ChannelList`, do not add a `channel` object as a prop on `Channel`. +However, in the absence of a `ChannelList`, the `channel` prop is required. By default, the `ChannelList` sets the active `channel` +object, which is then injected it into the `ChannelStateContext`, so manual prop passing is not required. + +**Example 1** - without `ChannelList` + +```jsx + + + + + + +``` + +**Example 2** - with `ChannelList` + +```jsx + + + + + + + +``` + +Any child of the `Channel` component has access to the contexts referenced above. Each context can be accessed with +one of our custom hooks, which must be imported individually. + +```jsx +const { messages } = useChannelStateContext(); +const { sendMessage } = useChannelActionContext(); +const { Avatar } = useComponentContext(); +const { typing } = useTypingContext(); +``` + +## Registering custom components + +In case you would like to customize parts of your chat application, you can do that by passing custom components to `Channel` component props. All the title-cased props are reserved for the custom components overriding the SDK defaults. The list of all customizable components - the component context - can be found in the [`ComponentContext` documentation](../contexts/component-context.mdx). + +**Example of registering custom Avatar component** + +```jsx +import { Channel, ChannelList, Chat, MessageInput, MessageList } from 'stream-chat-react'; +import { CustomTooltip } from '../Tooltip/CustomTooltip'; + +const Avatar = ({ image, title }) => { + return ( + <> + {title} +
+ {title} +
+ + ); +}; + +export const App = ( + + + + + + + +); +``` + +## Props + +### channel + +The currently active `StreamChat` `channel` instance to be loaded into the `Channel` component and referenced by its children. + +```jsx +const channel = client.channel('messaging', { + members: ['nate', 'roy'], +}); +``` + +:::caution +Do not provide this prop if you are using the `ChannelList` component, as it handles `channel` setting logic. +::: + +| Type | +| ------ | +| object | + +### acceptedFiles + +A list of accepted file upload types. + +| Type | +| -------- | +| string[] | + +### activeUnreadHandler + +Custom handler function that runs when the active channel has unread messages and the app is running on a separate browser tab. + +| Type | +| ----------------------------------------------- | +| (unread: number, documentTitle: string) => void | + +### Attachment + +Custom UI component to display a message attachment. + +| Type | Default | +| --------- | ---------------------------------------------------------------------- | +| component | | + +### AttachmentPreviewList + +Custom UI component to display an attachment previews in `MessageInput`. + +| Type | Default | +| --------- | ---------------------------------------------------------------------------------------------- | +| component | | + +### AutocompleteSuggestionHeader + +Custom UI component to override the default suggestion header component. + +| Type | Default | +| --------- | ------------------------------------------------------------------------ | +| component | | + +### AutocompleteSuggestionItem + +Custom UI component to override the default suggestion Item component. + +| Type | Default | +| --------- | ------------------------------------------------------------------- | +| component | | + +### AutocompleteSuggestionList + +Custom UI component to override the default List component that displays suggestions. + +| Type | Default | +| --------- | ------------------------------------------------------------------- | +| component | | + +### Avatar + +Custom UI component to display a user's avatar. + +| Type | Default | +| --------- | ---------------------------------------------------------- | +| component | | + +### channelQueryOptions + +Optional configuration parameters used for the initial channel query. Applied only if the value of `channel.initialized` is false. If the channel instance has already been initialized (channel has been queried), then the channel query will be skipped and channelQueryOptions will not be applied. + +In the example below, we specify, that the first page of messages when a channel is queried should have 20 messages (the default is 100). Note that the `channel` prop has to be passed along `channelQueryOptions`. + +```tsx +import { ChannelQueryOptions } from 'stream-chat'; +import { Channel, useChatContext } from 'stream-chat-react'; + +const channelQueryOptions: ChannelQueryOptions = { + messages: { limit: 20 }, +}; + +type ChannelRendererProps = { + id: string; + type: string; +}; + +const ChannelRenderer = ({ id, type }: ChannelRendererProps) => { + const { client } = useChatContext(); + return ( + + {/* Channel children */} + + ); +}; +``` + +| Type | +| --------------------- | +| `ChannelQueryOptions` | + +### CooldownTimer + +Custom UI component to display the slow mode cooldown timer. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------ | +| component | | + +### DateSeparator + +Custom UI component for date separators. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------- | +| component | | + +### doDeleteMessageRequest + +Custom action handler to override the default `client.deleteMessage(message.id)` function. + +| Type | +| ---------------------------------------------------------------------------------------------- | +| `(message: StreamMessage) => Promise>` | + +The function can execute different logic for message replies compared to messages in the main message list based on the `parent_id` property of `StreamMessage` object: + +```tsx +import { Channel, StreamMessage } from 'stream-chat-react'; +import type { MyStreamChatGenerics } from './types'; + +const doDeleteMessageRequest = async (message: StreamMessage) => { + if (message.parent_id) { + // do something before / after deleting a message reply + } else { + // do something before / after deleting a message + } +} + +const App = () => ( + {/* more components */} + + {/* more components */} + + {/* more components */} +); +``` + +### doMarkReadRequest + +Custom action handler to override the default `channel.markRead` request function (advanced usage only). The function takes two arguments: + +| Argument | Type | Description | +| ------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------- | +| `channel` | `Channel` | The current channel object instance | +| `setChannelUnreadUiState` | `(state: ChannelUnreadUiState) => void` | Function that allows us to set the unread state for the components reflecting the unread message state. | + +| Type | +| -------- | +| function | + +### doSendMessageRequest + +Custom action handler to override the default `channel.sendMessage` request function (advanced usage only). + +| Type | +| -------- | +| function | + +### doUpdateMessageRequest + +Custom action handler to override the default `client.updateMessage` request function (advanced usage only). + +| Type | +| -------- | +| function | + +### dragAndDropWindow + +If true, chat users will be able to drag and drop file uploads to the entire channel window. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### EditMessageInput + +Custom UI component to override default edit message input. + +| Type | Default | +| --------- | ---------------------------------------------------------------------------------- | +| component | | + +### emojiSearchIndex + +Custom search mechanism instance or object to enable emoji autocomplete. + +| Type | Default | +| ------ | --------- | +| object | undefined | + +### EmojiPicker + +Custom UI component to be rendered in the `MessageInput` component, see [Emoji Picker guide](../../guides/customization/emoji-picker.mdx) for more information. + +| Type | Default | +| --------- | --------- | +| component | undefined | + +### EmptyPlaceholder + +Custom UI component to be shown if no active `channel` is set, defaults to `null` and skips rendering the `Channel` component. + +| Type | Default | +| --------- | ------- | +| component | null | + +### EmptyStateIndicator + +Custom UI component to be displayed when the `MessageList` or `VirtualizedMessageList` is empty. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------------------- | +| component | | + +### enrichURLForPreview + +A global flag to toggle the URL enrichment and link previews in `MessageInput`. The feature is disabled by default. It can be overridden on `Thread` and `MessageList` level through `additionalMessageInputProps` +or directly on `MessageInput` level through `urlEnrichmentConfig` prop. See the guide [Link Previews in Message Input](../../../guides/customization/link-previews) for more. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### enrichURLForPreviewConfig + +Global configuration for link preview generation in all the MessageInput components. See the guide [Link Previews in Message Input](../../../guides/customization/link-previews) for more. + +| Type | +| ------------------------------------------------- | +| Omit | + +### FileUploadIcon + +Custom UI component for file upload icon. + +| Type | Default | +| --------- | ----------------------------------------------------------------------- | +| component | | + +### GiphyPreviewMessage + +Custom UI component to render a Giphy preview in the `VirtualizedMessageList`. + +| Type | Default | +| --------- | ----------------------------------------------------------------------------------------- | +| component | | + +### giphyVersion + +The Giphy version to render - check the keys of the [Image Object](https://developers.giphy.com/docs/api/schema#image-object) for possible values. + +| Type | Default | +| ------ | -------------- | +| string | 'fixed_height' | + +### HeaderComponent + +Custom UI component to render at the top of the `MessageList`. + +| Type | Default | +| --------- | ------- | +| component | none | + +### imageAttachmentSizeHandler + +A custom function to provide size configuration for image attachments + +| Type | +| ----------------------------------------------------------------- | +| `(a: Attachment, e: HTMLElement) => ImageAttachmentConfiguration` | + +### initializeOnMount + +Allows to prevent triggering the `channel.watch()` (triggers channel query HTTP request) call when mounting the `Channel` component (the default behavior) with uninitialized (`channel.initialized`) `Channel` instance. That means that no channel data from the back-end will be received neither channel WS events will be delivered to the client. Preventing to initialize the channel on mount allows us to postpone the channel creation in the Stream's DB to a later point in time, for example, when a first message is sent: + +```typescript jsx +import { useCallback } from 'react'; +import { + getChannel, + MessageInput as StreamMessageInput, + MessageInputProps, + MessageToSend, + useChannelActionContext, + useChatContext, +} from 'stream-chat-react'; +import { Message, SendMessageOptions } from 'stream-chat'; + +import { useChannelInitContext } from '../../context/ChannelInitProvider'; +import type { MyStreamChatGenerics } from '../../types'; + +export const MessageInput = (props: MessageInputProps) => { + const { client } = useChatContext(); + const { sendMessage } = useChannelActionContext(); + const { setInitializedChannelOnMount } = useChannelInitContext(); + + const submitHandler: MessageInputProps['overrideSubmitHandler'] = useCallback( + async ( + message: MessageToSend, + channelCid: string, + customMessageData?: Partial>, + options?: SendMessageOptions, + ) => { + const [channelType, channelId] = channelCid.split(':'); + const channel = client.channel(channelType, channelId); + if (!channel.initialized) { + await getChannel({ channel, client }); + setInitializedChannelOnMount(true); + } + + await sendMessage(message, customMessageData, options); + }, + [client, sendMessage, setInitializedChannelOnMount], + ); + + return ; +}; +``` + +| Type | Default | +| ------- | ------- | +| boolean | true | + +### markReadOnMount + +Configuration parameter to mark the active channel as read when mounted (opened). By default, the channel is marked read on mount. + +| Type | Default | +| ------- | ------- | +| boolean | true | + +### Input + +Custom UI component handling how the message input is rendered. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------ | +| component | | + +### LinkPreviewList + +Custom component to render link previews in `MessageInput`. + +| Type | Default | +| --------- | ---------------------------------------------------------------------------------- | +| component | | + +### LoadingErrorIndicator + +Custom UI component to be shown if the channel query fails. + +| Type | Default | +| --------- | ----------------------------------------------------------------------------------------- | +| component | | + +### LoadingIndicator + +Custom UI component to render while the `MessageList` is loading new messages. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------- | +| component | | + +### maxNumberOfFiles + +The maximum number of attachments allowed per message, defaults to the Stream Chat API maximum. + +| Type | Default | +| ------ | ------- | +| number | 10 | + +### Message + +Custom UI component to display a message in the standard `MessageList`. + +| Type | Default | +| --------- | ------------------------------------------------------------------------- | +| component | | + +### MessageDeleted + +Custom UI component for a deleted message. + +| Type | Default | +| --------- | --------------------------------------------------------------------------- | +| component | | + +### MessageListNotifications + +Custom UI component that displays message and connection status notifications in the `MessageList`. + +| Type | Default | +| --------- | ---------------------------------------------------------------------------------------------------------- | +| component | | + +### MessageNotification + +Custom UI component to display a notification when scrolled up the list and new messages arrive. + +| Type | Default | +| --------- | ----------------------------------------------------------------------------------------- | +| component | | + +### MessageOptions + +Custom UI component for message options popup. + +| Type | Default | +| --------- | --------------------------------------------------------------------------- | +| component | | + +### MessageRepliesCountButton + +Custom UI component to display message replies. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------------------- | +| component | | + +### MessageStatus + +Custom UI component to display message delivery status. + +| Type | Default | +| --------- | ------------------------------------------------------------------------- | +| component | | + +### MessageSystem + +Custom UI component to display system messages. + +| Type | Default | +| --------- | ---------------------------------------------------------------------------------- | +| component | | + +### MessageTimestamp + +Custom UI component to display a timestamp on a message. This does not include a timestamp for edited messages. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------- | +| component | | + +See also [`Timestamp`](#timestamp). + +### MessageBouncePrompt + +Custom UI component for the content of the modal dialog for messages that got bounced by the moderation rules. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------------- | +| component | | + +### ModalGallery + +Custom UI component for viewing message's image attachments. + +| Type | Default | +| --------- | ----------------------------------------------------------------------- | +| component | | + +### multipleUploads + +Whether to allow multiple attachment uploads on a message. + +| Type | Default | +| ------- | ------- | +| boolean | true | + +### onMentionsClick + +Custom action handler function to run on click of an @mention in a message. + +| Type | +| -------- | +| function | + +### onMentionsHover + +Custom action handler function to run on hover of an @mention in a message. + +| Type | +| -------- | +| function | + +### optionalMessageInputProps + +If `dragAndDropWindow` prop is true, the props to pass to the MessageInput component (overrides props placed directly on MessageInput). + +| Type | +| ------ | +| object | + +### PinIndicator + +Custom UI component to override default pinned message indicator. + +| Type | Default | +| --------- | ---------------------------------------------------------------- | +| component | | + +### QuotedMessage + +Custom UI component to override quoted message UI on a sent message. + +| Type | Default | +| --------- | ------------------------------------------------------------------------- | +| component | | + +### QuotedMessagePreview + +Custom UI component to override the message input's quoted message preview. + +| Type | Default | +| --------- | -------------------------------------------------------------------------------------------- | +| component | | + +### ReactionSelector + +Custom UI component to display the reaction selector. + +| Type | Default | +| --------- | --------------------------------------------------------------------------------- | +| component | | + +### ReactionsList + +Custom UI component to display the list of reactions on a message. + +| Type | Default | +| --------- | --------------------------------------------------------------------------- | +| component | | + +### SendButton + +Custom UI component for send button. + +| Type | Default | +| --------- | ------------------------------------------------------------------- | +| component | | + +### shouldGenerateVideoThumbnail + +You can turn on/off thumbnail generation for video attachments + +| Type | +| ------- | +| boolean | + +### skipMessageDataMemoization + +If true, skips the message data string comparison used to memoize the current channel messages (helpful for channels with 1000s of messages). + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### ThreadHead + +Custom UI component to be displayed at the beginning of a thread. By default, it is the thread parent message. It is composed of [Message](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Message/Message.tsx) context provider component and [ThreadStart](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Thread/ThreadStart.tsx) component. The latter can be customized by passing custom component to `Channel` props. The `ThreadHead` component defaults to and accepts the same props as [MessageSimple](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Message/MessageSimple.tsx). + +| Type | Default | +| --------- | ------------------------------------------------------------------ | +| component | | + +### ThreadHeader + +Custom UI component to display the header of a `Thread`. + +| Type | Default | +| --------- | ----------------------------------------------------------------------- | +| component | | + +### ThreadInput + +Custom UI component to replace the `MessageInput` of a `Thread`. For the applications using [theme version 1](../../guides/theming/css-and-theming.mdx), the default is `MessageInputSmall`. Applications using [theme version 2](../../theming/introduction.mdx) will use `MessageInputFlat` by default. + +| Type | Default | +| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| component | / | + +### ThreadStart + +Custom UI component to display the start of a threaded `MessageList`. + +| Type | Default | +| --------- | ---------------------------------------------------------------------- | +| component | | + +### Timestamp + +Custom UI component to display a date used in timestamps. It's used internally by the default `MessageTimestamp`, and to display a timestamp for edited messages. + +| Type | Default | +| --------- | ----------------------------------------------------------------- | +| component | | + +### TriggerProvider + +Optional context provider that lets you override the default autocomplete triggers. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------------------ | +| component | | + +### TypingIndicator + +Custom UI component for the typing indicator. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------- | +| component | | + +### UnreadMessagesNotification + +Custom UI component that indicates a user is viewing unread messages. It disappears once the user scrolls to `UnreadMessagesSeparator`. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------------------------- | +| component | | + +### UnreadMessagesSeparator + +Custom UI component inserted before the first message marked unread. + +| Type | Default | +| --------- | ------------------------------------------------------------------------------------------------- | +| component | | + +### videoAttachmentSizeHandler + +A custom function to provide size configuration for video attachments + +| Type | +| ----------------------------------------------------------------- | +| `(a: Attachment, e: HTMLElement) => VideoAttachmentConfiguration` | + +### VirtualMessage + +Custom UI component to display a message in the `VirtualizedMessageList`. + +| Type | Default | +| --------- | ------------------------------------------------------------------------- | +| component | | diff --git a/docusaurus/react_versioned_docs/version-11.x.x/components/core-components/chat.mdx b/docusaurus/react_versioned_docs/version-11.x.x/components/core-components/chat.mdx new file mode 100644 index 000000000..d1758fac6 --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/components/core-components/chat.mdx @@ -0,0 +1,131 @@ +--- +id: chat +title: Chat +--- + +The `Chat` component is a React Context provider that wraps the entire Stream Chat application. It provides the [`ChatContext`](../contexts/chat-context.mdx) +to its children, which includes the `StreamChat` client instance. All other components within the library must be nested as children +of `Chat` to maintain proper functionality. + +## Basic Usage + +The `Chat` component does not inject any UI, so its implementation is fairly simple. Once an instance of the `StreamChat` client +has been created, you pass the client object as a prop to add it to the `ChatContext`. + +```jsx + + + + + + +``` + +Any child of the `Chat` component has access to the `ChatContext`. Each React Context in the component library can be accessed with +one of our custom hooks, which must be imported individually. The `ChatContext` values are accessed with `useChatContext` hook. + +```jsx +const { client } = useChatContext(); +``` + +## Props + +###
Required
client + +The `StreamChat` client instance. Any methods from the `stream-chat-js` API interface can be run off this object. + +```jsx +const channel = client.channel('messaging', { + members: ['nate', 'roy'], +}); +``` + +| Type | +| ------ | +| object | + +### customClasses + +Object containing custom CSS classnames to override the library's default container CSS. See [CSS and Theming](../../guides/theming/css-and-theming.mdx) +for implementation assistance. + +| Type | +| ------ | +| object | + +### customStyles + +Object containing custom styles to override the default CSS variables. See [CSS and Theming](../../guides/theming/css-and-theming.mdx) +for implementation assistance. + +| Type | +| ------ | +| object | + +### darkMode + +If true, toggles the CSS variables to the default dark mode color palette. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### defaultLanguage + +Sets the default fallback language for UI component translation, defaults to 'en' for English. + +| Type | Default | +| ------ | ------- | +| string | 'en' | + +### i18nInstance + +The `Streami18n` translation instance. Create an instance of this class when you wish to change the connected user's default +language or override default text in the library. + +```jsx +const i18nInstance = new Streami18n({ + language: 'es', + translationsForLanguage: { + 'Nothing yet...': 'Nada', + }, +}); + + + {/* children of Chat component */} +; +``` + +| Type | +| ------ | +| object | + +### initialNavOpen + +When the screen width is at a mobile breakpoint, whether or not the mobile navigation menu is open. + +| Type | Default | +| ------- | ------- | +| boolean | true | + +### theme + +Deprecated and to be removed in a future major release. Use the `customStyles` prop to adjust CSS variables and [customize the theme](../../guides/theming/css-and-theming.mdx#css-variables) of your app. + +| Type | +| ----- | +| Theme | + +### useImageFlagEmojisOnWindows + +Windows 10 does not support country flag emojis out of the box. It chooses to render these emojis as characters instead. +Stream Chat can override this behavior by loading a custom web font that will render images instead (PNGs or SVGs depending +on the platform). Set this prop to true if you want to use these custom emojis for Windows users. + +:::caution +If you're moving from older versions to `11.0.0` then make sure to import related stylesheet from `stream-chat-react/css/v2/emoji-replacement.css` as it has been removed from our main stylesheet to reduce final bundle size for integrators who do not wish to use this feature. +::: + +| Type | Default | +| ------- | ------- | +| boolean | false | diff --git a/docusaurus/react_versioned_docs/version-11.x.x/components/core-components/message-list.mdx b/docusaurus/react_versioned_docs/version-11.x.x/components/core-components/message-list.mdx new file mode 100644 index 000000000..e132fc2ad --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/components/core-components/message-list.mdx @@ -0,0 +1,566 @@ +--- +id: message_list +title: MessageList +--- + +import GHComponentLink from '../../_docusaurus-components/GHComponentLink'; + +import MessageActionsBoxWithCustomAction from '../../assets/message-actions-box-custom-actions.png'; + +The `MessageList` component renders a scrollable list of messages. The UI for each individual message is rendered +conditionally based on its `message.type` value. The list renders date separators, message reactions, new message notifications, system +messages, deleted messages, and standard messages containing text and/or attachments. + +By default, the `MessageList` loads the most recent 25 messages held in the `channel.state`. More messages are fetched +from the Stream Chat API and loaded into the DOM on scrolling up the list. The currently loaded messages are held in +the `ChannelStateContext` and can be referenced with our custom hook. + +```tsx +const { messages } = useChannelStateContext(); +``` + +The `MessageList` has no required props and by default pulls overridable data from the various contexts established +in the [`Channel`](./channel.mdx) component. Customization of the messages rendered within the list is handled by +the [Message UI](../message-components/message-ui.mdx) component. + +## Basic Usage + +As a context consumer, the `MessageList` component must be rendered as a child of the `Channel` component. It can be +rendered with or without a provided `messages` prop. Providing your own `messages` value will override the default +value drawn from the `ChannelStateContext`. + +**Example 1** - without `messages` prop + +```tsx + + + + + + + +``` + +**Example 2** - with `messages` prop + +```tsx +const customMessages = [ + // array of messages +]; + + + + + + + +; +``` + +## Message grouping + +The `MessageList` internally creates a mapping of message id to a style group. There are 4 style groups - ` 'middle' | 'top' | 'bottom' | 'single'`. Later these group style tags are incorporated into the class of the `
  • ` element that wraps the `Message` component. This allows us to style messages by their position in the message group. An example of such class is `str-chat__li str-chat__li--bottom`. + +## Custom message list rendering + +You can completely change the way the message list is rendered by providing a custom `renderMessages` function. This function takes all the messages fetched so far (along with some additional data) and returns an array of React elements to render. By overriding the default behavior, you can add custom elements to the message list, change the way messages are grouped, add custom separators between messages, etc. + +If you provide a custom `renderMessages` function, it's your responsibility to render each message type correctly. You can use the as a reference. Or, if you just want to tweak a few things here and there, you can call `defaultRenderMessages` from your custom `renderMessages` function and build from there. + +In this example, we use the default implementation for rendering a message list, and we add a custom element at the bottom of the list: + +```tsx +const customRenderMessages: MessageRenderer = (options) => { + const elements = defaultRenderMessages(options); + + elements.push(
  • You're all caught up!
  • ); + + return elements; +}; + +const CustomMessageList = () => ; +``` + +Make sure that the elements you return have `key`, as they will be rendered as an array. It's also a good idea to wrap each element with `
  • ` to keep your markup semantically correct. + +:::note +`MessageList` will re-render every time `renderMessages` function changes. For best performance, make sure that you don't recreate `renderMessages` function on every render: either move it to the global or module scope, or wrap it with `useCallback`. +::: + +Custom message list rendering is only supported in `MessageList` and is currently not supported in `VirtualizedMessageList`. + +## Props + +### additionalMessageInputProps + +Additional props to be passed to the `MessageInput` component, [available props](../message-input-components/message-input.mdx/#props). It is rendered when editing a message. + +| Type | +| ------ | +| object | + +### closeReactionSelectorOnClick + +If true, picking a reaction from the `ReactionSelector` component will close the selector. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### customMessageActions + +An object containing custom message actions (key) and function handlers (value). For each custom action a dedicated item (button) in [`MessageActionsBox`](../message-components/message_ui#message-actions-box) is rendered. The key is used as a display text inside the button. Therefore, it should not be cryptic but rather bear the end user in mind when formulating it. + +```jsx +const customActions = { + 'Copy text': (message) => { + navigator.clipboard.writeText(message.text || ''); + }, +}; + +; +``` + +Custom action item "Copy text" in the message actions box: + +Image of a custom action item "Copy text" in the message actions box + +| Type | +| ------ | +| object | + +### disableDateSeparator + +If true, disables the injection of date separator UI components in the `Channel` `MessageList` component. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### disableQuotedMessages + +If true, disables the ability for users to quote messages. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### formatDate + +Overrides the default date formatting logic, has access to the original date object. + +| Type | +| ---------------------- | +| (date: Date) => string | + +### getDeleteMessageErrorNotification + +Function that returns the notification text to be displayed when the delete message request fails. This function receives the +deleted [message object](https://getstream.io/chat/docs/javascript/message_format/?language=javascript) as its argument. + +| Type | +| ---------------------------------- | +| (message: StreamMessage) => string | + +### getFetchReactionsErrorNotification + +Function that returns the notification text to be displayed when loading message reactions fails. This function receives the +current [message object](https://getstream.io/chat/docs/javascript/message_format/?language=javascript) as its argument. + +| Type | +| ---------------------------------- | +| (message: StreamMessage) => string | + +### getFlagMessageErrorNotification + +Function that returns the notification text to be displayed when a flag message request fails. This function receives the +flagged [message object](https://getstream.io/chat/docs/javascript/message_format/?language=javascript) as its argument. + +| Type | +| ---------------------------------- | +| (message: StreamMessage) => string | + +### getFlagMessageSuccessNotification + +Function that returns the notification text to be displayed when a flag message request succeeds. This function receives the +flagged [message object](https://getstream.io/chat/docs/javascript/message_format/?language=javascript) as its argument. + +| Type | +| ---------------------------------- | +| (message: StreamMessage) => string | + +### getMarkMessageUnreadErrorNotification + +Function that returns the notification text to be displayed when a mark message unread request fails. This function receives the +marked [message object](https://getstream.io/chat/docs/javascript/message_format/?language=javascript) as its argument. + +| Type | +| ---------------------------------- | +| (message: StreamMessage) => string | + +### getMarkMessageUnreadSuccessNotification + +Function that returns the notification text to be displayed when a mark message unread request succeeds. This function receives the +marked [message object](https://getstream.io/chat/docs/javascript/message_format/?language=javascript) as its argument. + +| Type | +| ---------------------------------- | +| (message: StreamMessage) => string | + +### getMuteUserErrorNotification + +Function that returns the notification text to be displayed when a mute user request fails. This function receives the +muted [user object](https://getstream.io/chat/docs/javascript/update_users/?language=javascript) as its argument. + +| Type | +| ------------------------------ | +| (user: UserResponse) => string | + +### getMuteUserSuccessNotification + +Function that returns the notification text to be displayed when a mute user request succeeds. This function receives the +muted [user object](https://getstream.io/chat/docs/javascript/update_users/?language=javascript) as its argument. + +| Type | +| ------------------------------ | +| (user: UserResponse) => string | + +### getPinMessageErrorNotification + +Function that returns the notification text to be displayed when a pin message request fails. This function receives the +pinned [message object](https://getstream.io/chat/docs/javascript/message_format/?language=javascript) as its argument. + +| Type | +| ---------------------------------- | +| (message: StreamMessage) => string | + +### groupStyles + +Callback function to map each message in the list to a group style (` 'middle' | 'top' | 'bottom' | 'single'`). + +| Type | +| -------------------------------------------------------------------------------------------------------------------------- | +| (message: StreamMessage, previousMessage: StreamMessage, nextMessage: StreamMessage, noGroupByUser: boolean) => GroupStyle | + +### hasMore + +Whether the list has more items to load. + +| Type | Default | +| ------- | ------------------------------------------------------------------------------------ | +| boolean | [ChannelStateContextValue['hasMore']](../contexts/channel-state-context.mdx#hasmore) | + +### headerPosition + +Position to render the `HeaderComponent` in the list. + +| Type | +| ------ | +| number | + +### hideDeletedMessages + +If true, removes the `MessageDeleted` components from the list. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### hideNewMessageSeparator + +If true, hides the `DateSeparator` component that renders when new messages are received in a channel that's watched but not active. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### internalInfiniteScrollProps + +Additional props for the underlying component. + +| Type | +| ------ | +| object | + +### loadingMore + +Whether the list is currently loading more items. + +| Type | Default | +| ------- | -------------------------------------------------------------------------------------------- | +| boolean | [ChannelStateContextValue['loadingMore']](../contexts/channel-state-context.mdx#loadingmore) | + +### loadMore + +Function called when more messages are to be loaded, provide your own function to override the handler stored in context. + +| Type | Default | +| -------- | ---------------------------------------------------------------------------------------- | +| function | [ChannelActionContextValue['loadMore']](../contexts/channel-action-context.mdx#loadmore) | + +### Message + +Custom UI component to display an individual message. + +| Type | Default | +| --------- | ------------------------------------------------------------------------- | +| component | | + +### messageActions + +Array of allowed message actions (ex: 'edit', 'delete', 'reply'). To disable all actions, provide an empty array. + +| Type | Default | +| ----- | -------------------------------------------------------------------- | +| array | ['edit', 'delete', 'flag', 'mute', 'pin', 'quote', 'react', 'reply'] | + +### messageLimit + +The limit to use when paginating new messages (the page size). + +:::caution +After mounting, the `MessageList` component checks if the list is completely filled with messages. If there is some space left in the list, `MessageList` will load the next page of messages, but it will do so _only once_. This means that if your `messageLimit` is too low, or if your viewport is very large, the list will not be completely filled. Set the limit with this in mind. +::: + +| Type | Default | +| ------ | ------- | +| number | 100 | + +### messages + +The messages to render in the list. Provide your own array to override the data stored in context. + +| Type | Default | +| ----- | -------------------------------------------------------------------------------------- | +| array | [ChannelStateContextValue['messages']](../contexts/channel-state-context.mdx#messages) | + +### noGroupByUser + +If true, turns off message UI grouping by user. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### onlySenderCanEdit + +If true, only the sender of the message has editing privileges. If `false` also channel capability `update-any-message` has to be enabled in order a user can edit other users' messages. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### onMentionsClick + +Custom action handler function to run on click on a @mention in a message. + +| Type | Default | +| -------- | ------------------------------------------------------------------------------------------------------ | +| function | [ChannelActionContextValue['onMentionsClick']](../contexts/channel-action-context.mdx#onmentionsclick) | + +### onMentionsHover + +Custom action handler function to run on hover over a @mention in a message. + +| Type | Default | +| -------- | ------------------------------------------------------------------------------------------------------ | +| function | [ChannelActionContextValue['onMentionsHover']](../contexts/channel-action-context.mdx#onmentionshover) | + +### onUserClick + +Custom action handler function to run on click of user avatar. + +| Type | +| ----------------------------------------------------- | +| (event: React.BaseSyntheticEvent, user: User) => void | + +### onUserHover + +Custom action handler function to run on hover of user avatar. + +| Type | +| ----------------------------------------------------- | +| (event: React.BaseSyntheticEvent, user: User) => void | + +### openThread + +Custom action handler to open a [`Thread`](./thread.mdx) component. + +| Type | Default | +| -------- | -------------------------------------------------------------------------------------------- | +| function | [ChannelActionContextValue['openThread']](../contexts/channel-action-context.mdx#openthread) | + +### pinPermissions + +The user roles allowed to pin messages in various channel types (deprecated in favor of `channelCapabilities`). + +| Type | Default | +| ------ | ------------------------------------------------------------------------- | +| object | | + +### renderText {#render-text} + +Custom function to render message text content. + +| Type | Default | +| -------- | ------------------------------------------------------------------------------ | +| function | | + +### renderMessages + +Custom function to render message text content. + +| Type | Default | +| -------- | -------------------------------------------------------------------------------------- | +| function | | + +#### Parameters + +The function receives a single object with the following properties: + +| Name | Type | Description | +| --------------------- | --------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| components | [ComponentContextValue](../contexts/component-context.mdx) | UI components, including possible overrides | +| customClasses | object | Object containing [custom CSS classnames](../../components/core-components/chat.mdx#customclasses) to override the library's default container CSS | +| lastReceivedMessageId | string | The latest message ID in the current channel | +| messageGroupStyles | string[] | An array of potential styles to apply to a grouped message (ex: top, bottom, single) | +| messages | Array<[ChannelStateContextValue['messages']](../contexts/channel-state-context.mdx#messages)> | The messages to render in the list | +| readData | object | The read state for for messages submitted by the user themselves | +| sharedMessageProps | object | Object containing props that can be directly passed to the `Message` component | + +#### Return value + +The function is expected to return an array of valid React nodes: `Array`. For best performance, each node should have a `key`. + +### retrySendMessage + +Custom action handler to retry sending a message after a failed request. + +| Type | Default | +| -------- | -------------------------------------------------------------------------------------------------------- | +| function | [ChannelActionContextValue['retrySendMessage']](../contexts/channel-action-context.mdx#retrysendmessage) | + +### returnAllReadData + +If true, `readBy` data supplied to the `Message` components will include all user read states per sent message. By default, +only `readBy` data for a user's most recently sent message is returned. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### reviewProcessedMessage + +Allows to review changes introduced to messages array on per message basis (for example date separator injection before a message). The array returned from the function is appended to the array of messages that are later rendered into React elements in the `MessageList`. + +The function expects a single parameter, which is an object containing the following attributes: + +- `changes` - array of messages representing the changes applied around a given processed message +- `context` - configuration params and information forwarded from `processMessages` +- `index` - index of the processed message in the original messages array +- `messages` - array of messages retrieved from the back-end +- `processedMessages` - newly built array of messages to be later rendered + +The `context` has the following parameters: + +- `userId` - the connected user ID; +- `enableDateSeparator` - flag determining whether the date separators will be injected Enable date separator +- `hideDeletedMessages` - flag determining whether deleted messages would be filtered out during the processing +- `hideNewMessageSeparator` - disables date separator display for unread incoming messages +- `lastRead`: Date when the channel has been last read. Sets the threshold after everything is considered unread + +The example below demonstrates how the custom logic can decide, whether deleted messages should be rendered on a given date. In this example, the deleted messages neither the date separator would be rendered if all the messages on a given date are deleted. + +```js +const getMsgDate = (msg) => + (msg && msg.created_at && isDate(msg.created_at) && msg.created_at.toDateString()) || ''; + +const dateSeparatorFilter = (msg) => msg.customType !== 'message.date'; + +const msgIsDeleted = (msg) => msg.type === 'deleted'; + +const reviewProcessedMessage = ({ changes, context, index, messages, processedMessages }) => { + if (!context.enableDateSeparator) return changes; + + const changesWithoutSeparator = changes.filter(dateSeparatorFilter); + const dateSeparatorInjected = changesWithoutSeparator.length !== changes.length; + const previousProcessedMessage = processedMessages[processedMessages.length - 1]; + const processedMessage = messages[index]; + const processedMessageDate = getMsgDate(processedMessage); + + if (dateSeparatorInjected) { + if (!processedMessageDate) return changes; + const followingMessages = messages.slice(index + 1); + let allFollowingMessagesOnDateDeleted = false; + + for (const followingMsg of followingMessages) { + const followingMsgDate = getMsgDate(followingMsg); + if (followingMsgDate !== processedMessageDate) break; + allFollowingMessagesOnDateDeleted = followingMsg.type === 'deleted'; + } + + return allFollowingMessagesOnDateDeleted ? [] : changes; + } else if ( + msgIsDeleted(processedMessage) && + getMsgDate(previousProcessedMessage) !== getMsgDate(processedMessage) + ) { + return []; + } else { + return changes; + } +}; +``` + +### scrolledUpThreshold + +The pixel threshold to determine whether the user is scrolled up in the list. When scrolled up in the active +channel, the `MessageNotification` component displays when new messages arrive. + +| Type | Default | +| ------ | ------- | +| number | 200 | + +### showUnreadNotificationAlways + +The floating notification informing about unread messages will be shown when the `UnreadMessagesSeparator` is not visible. The default is false, that means the notification +is shown only when viewing unread messages. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### sortReactionDetails + +Comparator function to sort the list of reacted users. Should have the same signature as an array's `sort` method. + +| Type | Default | +| ---------------------------------------------------------- | ------------------ | +| (this: ReactionResponse, that: ReactionResponse) => number | alphabetical order | + +### sortReactions + +Comparator function to sort reactions. Should have the same signature as the `sort` method for a string array. + +| Type | Default | +| -------------------------------------------------------- | ------------------ | +| (this: ReactionSummary, that: ReactionSummary) => number | alphabetical order | + +### threadList + +If true, indicates that the current `MessageList` component is part of a `Thread`. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### unsafeHTML + +If true, renders HTML instead of markdown. Posting HTML is only supported server-side. + +| Type | Default | +| ------- | ------- | +| boolean | false | diff --git a/docusaurus/react_versioned_docs/version-11.x.x/components/core-components/thread.mdx b/docusaurus/react_versioned_docs/version-11.x.x/components/core-components/thread.mdx new file mode 100644 index 000000000..fc7873e96 --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/components/core-components/thread.mdx @@ -0,0 +1,210 @@ +--- +id: thread +title: Thread +--- + +The `Thread` component renders a list of replies tied to a single parent message in a channel's main message list. +A `Thread` maintains its own state and renders its own `MessageList` and `MessageInput` components. Each piece of +rendered UI can be overridden with custom components either drawn from the `ComponentContext` or supplied via props. + +The `Thread` component consumes the contexts established in [`Channel`](./channel.mdx) and does not have any required props. + +## Basic Usage + +As a context consumer, the `Thread` component must be rendered as a child of the `Channel` component. To enable +smooth `Thread` mount and unmount behavior, wrap the main channel components in the [`Window`](../utility-components/window.mdx) +component. `Window` handles width changes in the main channel to ensure a seamless user experience when opening and +closing a `Thread`. + +```jsx + + + + + + + + + + +``` + +## UI Customization + +Since a `Thread` contains most of the pieces of a `Channel` component, just in an encapsulated form, many aspects +and components can be customized in a similar way. The UI components for both [`Message`](../message-components/message.mdx) +and [`MessageInput`](../message-input-components/message-input.mdx) can be overridden via props if you desire different +UI from the styles rendered in the main `Channel`. `ThreadHeader` and `ThreadStart` are two overridable UI +components unique to `Thread` that can be drawn from the `ComponentContext`. + +**Example 1** - The below example shows how to render different UI for messages and the input within a `Thread`, +versus those rendered in the main `Channel`. + +:::note +A common pattern we use in the library is to first check props to see if a value/component exists, and if not, +pull from context. +::: + +```jsx +const MainInput = (props) => { + // render main `MessageInput` UI component here +}; + +const MainMessage = (props) => { + // render main `Message` UI component here +}; + +const ThreadInput = (props) => { + // render thread `MessageInput` UI component here +}; + +const ThreadMessage = (props) => { + // render thread `Message` UI component here +}; + + + + + + + + + + +; +``` + +**Example 2** - The below example shows how to provide custom UI for the `ThreadHeader` and `ThreadStart` +components. `ThreadHeader` is rendered above the UI for the thread's parent `Message` component and at the +top of the `Thread`. `ThreadStart` serves as a separator between the parent message and the `MessageList` of replies. + +```jsx +const CustomThreadHeader = (props) => { + // render thread header UI component here +}; + +const CustomThreadStart = (props) => { + // render thread start UI component here +}; + + + + + + + + + + +; +``` + +**Example 3** - To customize the combo of the thread's parent message and the `ThreadStart` separator, you can create a custom `ThreadHead` component and pass it to the `Channel` props. It then will be stored in the [`ComponentContext['ThreadHead']`](../contexts/component-context.mdx/#threadhead) + +```jsx +const CustomThreadHead = (props) => { + // render thread header UI component here +}; + + + + + + + + + + +; +``` + +## Props + +### additionalMessageInputProps + +Additional props to be passed to the underlying [`MessageInput`](../message-input-components/message-input.mdx) component. + +| Type | +| ------ | +| object | + +### additionalMessageListProps + +Additional props to be passed to the underlying [`MessageList`](./message-list.mdx) component. + +| Type | +| ------ | +| object | + +### additionalParentMessageProps + +Additional props to be passed to the underlying [`Message`](../message-components/message.mdx) component, which represents the +thread's parent message. + +| Type | +| ------ | +| object | + +### additionalVirtualizedMessageListProps + +Additional [props for `VirtualizedMessageList`](../virtualized_list/#props) component. + +| Type | +| ------ | +| object | + +### autoFocus + +If true, focuses the `MessageInput` component on opening a thread. + +| Type | Default | +| ------- | ------- | +| boolean | true | + +### enableDateSeparator + +Controls injection of UI component into underlying `MessageList` or `VirtualizedMessageList`. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### fullWidth + +If true, displays the thread at 100% width of its parent container, useful for mobile styling. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### Input + +Custom thread input UI component used to override the optional `Input` value stored in `ComponentContext` or the default. For the applications using [theme version 1](../../guides/theming/css-and-theming.mdx), the default is `MessageInputSmall`. Applications using [theme version 2](../../theming/introduction.mdx) will use `MessageInputFlat` by default. + +| Type | Default | +| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| component | / | + +### Message + +Custom thread message UI component used to override the default `Message` value stored in `ComponentContext`. + +| Type | Default | +| --------- | ------------------------------------------------------------------------ | +| component | [ComponentContext['Message']](../contexts/component-context.mdx#message) | + +### messageActions + +Array of allowed message actions (ex: 'edit', 'delete', 'reply'). To disable all actions, provide an empty array. + +| Type | Default | +| ----- | -------------------------------------------------------------------- | +| array | ['edit', 'delete', 'flag', 'mute', 'pin', 'quote', 'react', 'reply'] | + +### virtualized + +If true, render the `VirtualizedMessageList` instead of the standard `MessageList` component. + +| Type | +| ------- | +| boolean | diff --git a/docusaurus/react_versioned_docs/version-11.x.x/components/core-components/virtualized-list.mdx b/docusaurus/react_versioned_docs/version-11.x.x/components/core-components/virtualized-list.mdx new file mode 100644 index 000000000..ba810983f --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/components/core-components/virtualized-list.mdx @@ -0,0 +1,352 @@ +--- +id: virtualized_list +title: VirtualizedMessageList +--- + +import GHComponentLink from '../../_docusaurus-components/GHComponentLink'; + +The `VirtualizedMessageList` component renders a scrollable list of messages. It differs from the standard `MessageList` +in that it handles UI virtualization by default. Virtualization is a technique used to emulate large lists of elements by +rendering as few items as possible to maintain performance and decrease the load on the DOM, while preserving the user +experience. These qualities make the `VirtualizedMessageList` ideal for livestream use cases, where a single channel may +have thousands of currently active users. + +Similar to the `MessageList`, the UI for each individual message is rendered conditionally based on its `message.type` value. +The list renders date separators, message reactions, new message notifications, system messages, deleted messages, and standard messages +containing text and/or attachments. + +By default, the `VirtualizedMessageList` loads the most recent 25 messages held in the `channel.state`. More messages are fetched +from the Stream Chat API and loaded into the DOM on scrolling up the list. The currently loaded messages are held in +the `ChannelStateContext` and can be referenced with our custom hook. + +```jsx +const { messages } = useChannelStateContext(); +``` + +The `VirtualizedMessageList` has no required props and by default pulls overridable data from the various contexts established +in the [`Channel`](./channel.mdx) component. Customization of the messages rendered within the list is handled by +the [Message UI](../message-components/message-ui.mdx) component. + +## Basic Usage + +As a context consumer, the `VirtualizedMessageList` component must be rendered as a child of the `Channel` component. It can be +rendered with or without a provided `messages` prop. Providing your own `messages` value will override the default +value drawn from the `ChannelStateContext`. + +**Example 1** - without `messages` prop + +```jsx + + + + + + + +``` + +**Example 2** - with `messages` prop + +```jsx +const customMessages = [ + // array of messages +]; + + + + + + + +; +``` + +## Scroll Behavior Optimization + +By default, the virtualized message list uses the latest message (which gets rendered first) in the list as the default item size. +This can lead to inaccurate scroll thumb size or scroll jumps if the last item is unusually tall (for example, an attachment). +To improve this behavior, set the `defaultItemHeight` property to a value close (or equal to) the height of the usual messages. + +```jsx + +``` + +## Message grouping + +The `VirtualizedMessageList` internally creates a mapping of message id to a style group. There are 4 style groups - ` 'middle' | 'top' | 'bottom' | 'single'`. Later these group style tags are incorporated into the class of the `
  • ` element that wraps the `Message` component. This allows us to style messages by their position in the message group. An example of such class is `str-chat__li str-chat__li--bottom`. + +## Props + +### additionalMessageInputProps + +Additional props to be passed to the `MessageInput` component, [available props](../message-input-components/message-input.mdx/#props). It is rendered when editing a message. + +| Type | +| ------ | +| object | + +### additionalVirtuosoProps + +Additional props to be passed the underlying [`react-virtuoso` virtualized list dependency](https://virtuoso.dev/virtuoso-api-reference/). + +| Type | +| ------ | +| object | + +### closeReactionSelectorOnClick + +If true, picking a reaction from the `ReactionSelector` component will close the selector. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### customMessageRenderer + +Custom message render function, overrides the default `messageRenderer` function defined in the component. + +| Type | +| ------------------------------------------------------------------ | +| ( messages: StreamMessage[], index: number ) => React.ReactElement | + +### defaultItemHeight + +If set, the default item height is used for the calculation of the total list height. Use if you expect messages with a lot of height variance. + +| Type | +| ------ | +| number | + +### disableDateSeparator + +If true, disables the injection of date separator UI components. + +| Type | Default | +| ------- | ------- | +| boolean | true | + +### groupStyles + +Callback function to set group styles for each message. + +| Type | +| -------------------------------------------------------------------------------------------------------------------------- | +| (message: StreamMessage, previousMessage: StreamMessage, nextMessage: StreamMessage, noGroupByUser: boolean) => GroupStyle | + +### hasMore + +Whether the list has more items to load. + +| Type | Default | +| ------- | ------------------------------------------------------------------------------------ | +| boolean | [ChannelStateContextValue['hasMore']](../contexts/channel-state-context.mdx#hasmore) | + +### hideDeletedMessages + +If true, removes the `MessageDeleted` components from the list. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### hideNewMessageSeparator + +If true, hides the `DateSeparator` component that renders when new messages are received in a channel that's watched but not active. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### loadingMore + +Whether the list is currently loading more items. + +| Type | Default | +| ------- | -------------------------------------------------------------------------------------------- | +| boolean | [ChannelStateContextValue['loadingMore']](../contexts/channel-state-context.mdx#loadingmore) | + +### loadMore + +Function called when more messages are to be loaded, provide your own function to override the handler stored in context. + +| Type | Default | +| -------- | ---------------------------------------------------------------------------------------- | +| function | [ChannelActionContextValue['loadMore']](../contexts/channel-action-context.mdx#loadmore) | + +### Message + +Custom UI component to display an individual message. + +| Type | Default | +| --------- | ------------------------------------------------------------------------- | +| component | | + +### messageLimit + +The limit to use when paginating messages (the page size). + +:::caution +After mounting, the `VirtualizedMessageList` component checks if the list is completely filled with messages. If there is some space left in the list, `VirtualizedMessageList` will load the next page of messages, but it will do so _only once_. This means that if your `messageLimit` is too low, or if your viewport is very large, the list will not be completely filled. Set the limit with this in mind. +::: + +| Type | Default | +| ------ | ------- | +| number | 100 | + +### messages + +The messages to render in the list, provide your own array to override the data stored in context. + +| Type | Default | +| ----- | -------------------------------------------------------------------------------------- | +| array | [ChannelStateContextValue['messages']](../contexts/channel-state-context.mdx#messages) | + +### overscan + +The amount of extra content the list should render in addition to what's necessary to fill in the viewport. + +| Type | Default | +| ------ | ------- | +| number | 0 | + +### returnAllReadData + +Keep track of read receipts for each message sent by the user. When disabled, only the last own message delivery / read status is rendered. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### reviewProcessedMessage + +Allows to review changes introduced to messages array on per message basis (for example date separator injection before a message). The array returned from the function is appended to the array of messages that are later rendered into React elements in the `VirtualizedMessageList`. + +The function expects a single parameter, which is an object containing the following attributes: + +- `changes` - array of messages representing the changes applied around a given processed message +- `context` - configuration params and information forwarded from `processMessages` +- `index` - index of the processed message in the original messages array +- `messages` - array of messages retrieved from the back-end +- `processedMessages` - newly built array of messages to be later rendered + +The `context` has the following parameters: + +- `userId` - the connected user ID; +- `enableDateSeparator` - flag determining whether the date separators will be injected Enable date separator +- `hideDeletedMessages` - flag determining whether deleted messages would be filtered out during the processing +- `hideNewMessageSeparator` - disables date separator display for unread incoming messages +- `lastRead`: Date when the channel has been last read. Sets the threshold after everything is considered unread + +The example below demonstrates how the custom logic can decide, whether deleted messages should be rendered on a given date. In this example, the deleted messages neither the date separator would be rendered if all the messages on a given date are deleted. + +```js +const getMsgDate = (msg) => + (msg && msg.created_at && isDate(msg.created_at) && msg.created_at.toDateString()) || ''; + +const dateSeparatorFilter = (msg) => msg.customType !== 'message.date'; + +const msgIsDeleted = (msg) => msg.type === 'deleted'; + +const reviewProcessedMessage = ({ changes, index, messages, processedMessages }) => { + const changesWithoutSeparator = changes.filter(dateSeparatorFilter); + const dateSeparatorInjected = changesWithoutSeparator.length !== changes.length; + const previousProcessedMessage = processedMessages[processedMessages.length - 1]; + const processedMessage = messages[index]; + const processedMessageDate = getMsgDate(processedMessage); + + if (dateSeparatorInjected) { + if (!processedMessageDate) return changes; + const followingMessages = messages.slice(index + 1); + let allFollowingMessagesOnDateDeleted = false; + + for (const followingMsg of followingMessages) { + const followingMsgDate = getMsgDate(followingMsg); + if (followingMsgDate !== processedMessageDate) break; + allFollowingMessagesOnDateDeleted = followingMsg.type === 'deleted'; + } + + return allFollowingMessagesOnDateDeleted ? [] : changes; + } else if ( + msgIsDeleted(processedMessage) && + getMsgDate(previousProcessedMessage) !== getMsgDate(processedMessage) + ) { + return []; + } else { + return changes; + } +}; +``` + +### scrollSeekPlaceHolder + +Custom data passed to the list that determines when message placeholders should be shown during fast scrolling. + +| Type | +| ------ | +| object | + +### scrollToLatestMessageOnFocus + +If true, the list will scroll to the latest message when the window regains focus. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### shouldGroupByUser + +If true, group messages belonging to the same user, otherwise show each message individually. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### separateGiphyPreview + +If true, the Giphy preview will render as a separate component above the `MessageInput`, rather than inline with the other messages in the list. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### showUnreadNotificationAlways + +The floating notification informing about unread messages will be shown when the `UnreadMessagesSeparator` is not visible. The default is false, that means the notification +is shown only when viewing unread messages. + +| Type | Default | +| ------- | ------- | +| boolean | false | + +### stickToBottomScrollBehavior + +The scroll-to behavior when new messages appear. Use `'smooth'` for regular chat channels and `'auto'` +(which results in instant scroll to bottom) if you expect high throughput. + +| Type | Default | +| ------------------ | -------- | +| 'smooth' \| 'auto' | 'smooth' | + +### sortReactionDetails + +Comparator function to sort the list of reacted users. Should have the same signature as an array's `sort` method. + +| Type | Default | +| ---------------------------------------------------------- | ------------------ | +| (this: ReactionResponse, that: ReactionResponse) => number | alphabetical order | + +### sortReactions + +Comparator function to sort reactions. Should have the same signature as an array's `sort` method. + +| Type | Default | +| -------------------------------------------------------- | ------------------ | +| (this: ReactionSummary, that: ReactionSummary) => number | alphabetical order | + +### threadList + +If true, indicates that the current `VirtualizedMessageList` component is part of a `Thread`. + +| Type | Default | +| ------- | ------- | +| boolean | false | diff --git a/docusaurus/react_versioned_docs/version-11.x.x/components/message-components/attachment.mdx b/docusaurus/react_versioned_docs/version-11.x.x/components/message-components/attachment.mdx new file mode 100644 index 000000000..6da230237 --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/components/message-components/attachment.mdx @@ -0,0 +1,233 @@ +--- +id: attachment +title: Attachments +--- + +import GHComponentLink from '../../_docusaurus-components/GHComponentLink'; +import ImageSizingScreenshot1 from '../../assets/ImageSizing1.png'; +import ImageSizingScreenshot2 from '../../assets/ImageSizing2.png'; +import ImageSizingScreenshot3 from '../../assets/ImageSizing3.png'; +import AttachmentSizeWarning from '../../assets/AttachmentSizeWarning.png'; + +The `Attachment` component takes a list of message attachments and conditionally renders the UI of each individual attachment based +upon its type. The following table shows the attachment UI components that will be rendered for various attachment types: + +| Attachment Type | UI Component | File type(s) (non-exhaustive) | +| --------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | +| `audio` | [Audio](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/Audio.tsx) | MP3, WAV, M4A, FLAC, AAC | +| `file` | [File](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/FileAttachment.tsx) | DOC, DOCX, PDF, PPT, PPTX, TXT, XLS, XLSX | +| `gallery` | [Gallery](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Gallery/Gallery.tsx) | when a message has more than 1 'image' type attachment | +| `image` | [Image](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Gallery/Image.tsx) | HEIC, GIF, JPEG, JPG, PNG, TIFF, BMP | +| `video` | [ReactPlayer](https://github.com/cookpete/react-player/blob/master/src/ReactPlayer.js) | MP4, OGG, WEBM, Quicktime(QTFF, QT, or MOV) | + +Message attachment objects that do not conform to one of the above types are considered to contain scraped content and should contain at least `og_scrape_url` or `title_link` to be rendered with the component. Otherwise, the attachment is not rendered. + +## Basic Usage + +By default, the `Attachment` component is included within `MessageSimple`. To render message attachment UI within a custom +[Message UI](./message-ui.mdx) component, import the `Attachment` component and render it conditionally based upon the presence of +message attachments. + +```jsx +const CustomMessage = () => { + // consume `MessageContext` + const { message } = useMessageContext(); + + const hasAttachments = message.attachments && message.attachments.length > 0; + + return ( +
    + {hasAttachments && } + // render remaining custom Message UI +
    + ); +}; + + + + + + +; +``` + +## UI Customization + +`Attachment` accepts component override props for each attachment UI component. Building upon the previous example, the below +snippets show how to customize one of the individual attachment UI components with either custom Message UI component: + +```jsx +const CustomImage = (props) => { + // render custom image component here +}; + +const CustomMessage = () => { + // consume `MessageContext` + const { message } = useMessageContext(); + + const hasAttachments = message.attachments && message.attachments.length > 0; + + return ( +
    + {hasAttachments && } + {/* render remaining custom Message UI */} +
    + ); +}; + + + + + + +; +``` + +or using wrapped `Attachment` component: + +```jsx +const CustomAudioAttachment = (props) => { + // you can add any custom data (such as "customType" in this case) + if (props.og?.customType === 'voice-memo') return
    my custom voice-memo component
    ; + return
  • +
    #️⃣
    + {channel.data?.name} +
  • +); + +const UserSearchResultPreview = ({ user }) => ( +
  • +
    👤
    + {user.name ?? user.id} +
  • +); + +const MessageSearchResultPreview = ({ message }) => ( +
  • +
    💬
    + {message.text} +
  • +); + +const SearchResultsPreview = ({ results }) => { + if (results.items.length === 0) { + return
    🤷‍♂️ No results
    ; + } + + return ( +
      + {results.entity === 'channel' && + results.items.map((item) => )} + {results.entity === 'user' && + results.items.map((item) => )} + {results.entity === 'message' && + results.items.map((item) => )} +
    + ); +}; +``` + + + + +```css +.search-results { + list-style: none; + padding: 0; + margin: 0; +} + +.search-results__item { + padding-left: 30px; +} + +.search-results__item:not(:last-child) { + margin-bottom: 10px; + padding-bottom: 10px; + border-bottom: 1px solid #dbdde1; +} + +.search-results__icon { + display: inline-block; + width: 30px; + margin-left: -30px; +} +``` + + + + +![](../../assets/channel-search-channels.png) +![](../../assets/channel-search-users.png) +![](../../assets/channel-search-messages.png) + +What happens when you click on a search result depends on your desired user +experience. If you click on a channel, it makes sense to set the channel as +active. When clicking on a user, you may want to create or open a channel with +a one-on-one conversation with the user. When clicking on a message, it's +probably expected that a relevant channel will be set as active and scrolled to the +message. + + + + +```jsx +import { useChatContext } from 'stream-chat-react'; + +const ChannelSearchResultPreview = ({ channel }) => { + const { setActiveChannel } = useChatContext(); + + return ( +
  • setActiveChannel(channel)}> +
    #️⃣
    + {channel.data?.name} +
  • + ); +}; +``` + +
    + + +```jsx +import { useChatContext } from 'stream-chat-react'; + +const UserSearchResultPreview = ({ user }) => { + const { client, setActiveChannel } = useChatContext(); + + const handleClick = async () => { + const channel = client.channel('messaging', { members: [userId, user.id] }); + await channel.watch(); + setActiveChannel(channel); + }; + + return ( +
  • +
    👤
    + {user.name ?? user.id} +
  • + ); +}; +``` + +
    + + +```jsx +import { useChatContext } from 'stream-chat-react'; + +const MessageSearchResultPreview = ({ message }) => { + const history = useHistory(); // bring your own router of choice + const { client, setActiveChannel } = useChatContext(); + + const handleClick = async () => { + if (message.channel) { + const channel = client.channel(message.channel.type, message.channel.id); + setActiveChannel(channel); + await channel.state.loadMessageIntoState(message.id); + history.replace(`${window.location.pathname}#${message.id}`); + } + }; + + return ( +
  • +
    💬
    + {message.text} +
  • + ); +}; + +// Somewhere in your application code: +const location = useLocation(); +const messageId = useMemo(() => new URL(location).hash.slice(1), [location]); +; +``` + +
    +
    + +And that's it! Here's the complete code: + + + + +```jsx +import { useChatContext } from 'stream-chat-react'; + +const CustomSearch = () => { + const { client } = useChatContext(); + const [query, setQuery] = useState(''); + const { results, pending, querySearchResults } = useSearchQuery(); + // Use your favorite query library here 👆 + + const handleChannelSearchClick = async () => { + querySearchResults(async () => { + const channels = await client.queryChannels( + { + type: 'messaging', + name: { $autocomplete: query }, + members: { $in: [userId] }, + }, + { last_message_at: -1, updated_at: -1 }, + { limit: 5 }, + ); + + return { + entity: 'channel', + items: channels, + }; + }); + }; + + const handleUserSearchClick = async () => { + querySearchResults(async () => { + const { users } = await client.queryUsers( + { + $or: [{ id: { $autocomplete: query } }, { name: { $autocomplete: query } }], + id: { $ne: userId }, + }, + { id: 1, name: 1 }, + { limit: 5 }, + ); + + return { + entity: 'user', + items: users, + }; + }); + }; + + const handleMessageSearchClick = async () => { + querySearchResults(async () => { + const { results } = await client.search( + { type: 'messaging', members: { $in: [userId] } }, + query, + { limit: 5 }, + ); + + return { + entity: 'message', + items: results.map((item) => item.message), + }; + }); + }; + + return ( +
    + setQuery(event.target.value)} + /> + {query && ( +
    + + + +
    + )} + + {pending && <>Searching...} + {results && } +
    + ); +}; + +const ChannelSearchResultPreview = ({ channel }) => { + const { setActiveChannel } = useChatContext(); + + return ( +
  • setActiveChannel(channel)}> +
    #️⃣
    + {channel.data?.name} +
  • + ); +}; + +const UserSearchResultPreview = ({ user }) => { + const { client, setActiveChannel } = useChatContext(); + + const handleClick = async () => { + const channel = client.channel('messaging', { members: [userId, user.id] }); + await channel.watch(); + setActiveChannel(channel); + }; + + return ( +
  • +
    👤
    + {user.name ?? user.id} +
  • + ); +}; + +const MessageSearchResultPreview = ({ message }) => { + const history = useHistory(); // bring your own router of choice + const { client, setActiveChannel } = useChatContext(); + + const handleClick = async () => { + if (message.channel) { + const channel = client.channel(message.channel.type, message.channel.id); + setActiveChannel(channel); + await channel.state.loadMessageIntoState(message.id); + history.replace(`${window.location.pathname}#${message.id}`); + } + }; + + return ( +
  • +
    💬
    + {message.text} +
  • + ); +}; + +const SearchResultsPreview = ({ results }) => { + if (results.items.length === 0) { + return <>No results; + } + + return ( +
      + {results.entity === 'channel' && + results.items.map((item) => )} + {results.entity === 'user' && + results.items.map((item) => )} + {results.entity === 'message' && + results.items.map((item) => )} +
    + ); +}; +``` + +
    + + +```css +.search-input { + width: 100%; + border: 0; + border-radius: 10px; + background: #00000014; + font: inherit; + padding: 10px 15px; +} + +.search-input::-webkit-search-cancel-button { + appearance: none; +} + +.search-actions { + display: flex; + flex-direction: column; + margin: 10px 0 20px; +} + +.search-button { + background: #00000014; + border: 0; + border-bottom: 1px solid #dbdde1; + padding: 10px 15px; + cursor: pointer; +} + +.search-button:first-child { + border-radius: 10px 10px 0 0; +} + +.search-button:last-child { + border-radius: 0 0 10px 10px; + border-bottom: 0; +} + +.search-button:hover { + background: #dbdde1; +} + +.search-results { + list-style: none; + padding: 0; + margin: 0; +} + +.search-results__item { + padding-left: 30px; +} + +.search-results__item:not(:last-child) { + margin-bottom: 10px; + padding-bottom: 10px; + border-bottom: 1px solid #dbdde1; +} + +.search-results__icon { + display: inline-block; + width: 30px; + margin-left: -30px; +} +``` + + +
    diff --git a/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/emoji-picker.mdx b/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/emoji-picker.mdx new file mode 100644 index 000000000..fe01c7449 --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/emoji-picker.mdx @@ -0,0 +1,74 @@ +--- +id: emoji_picker +title: Emoji Picker +--- + +In this guide we'll show you how to add `EmojiPicker` component to your chat application as no chat experience is complete without emojis. + +## Prerequisities + +Our `EmojiPicker` is built on top of `emoji-mart` so let's begin with installing `emoji-mart`-related packages (make sure they meet our [peer-dependency requirements](https://github.com/GetStream/stream-chat-react/blob/v11.0.0/package.json#L97-L99)): + +```bash +yarn add emoji-mart @emoji-mart/data @emoji-mart/react +``` + +## Basic Usage + +The SDK `EmojiPicker` carries both button and the actual picker components and owns its "open" state. + +```tsx +import { Channel } from 'stream-chat-react'; +import { EmojiPicker } from 'stream-chat-react/emojis'; + +const WrappedChannel = ({ children }) => { + return {children}; +}; +``` + +![Default EmojiPicker Component](../../assets/default-emoji-picker.png) + +## Building custom EmojiPicker component + +If `emoji-mart` is too heavy for your use-case and you'd like to build your own you can certainly do so, here's a very simple `EmojiPicker` example built using native emojis: + +```tsx +import { useMessageInputContext } from 'stream-chat-react'; + +const emojis = ['🍳', '🥐', '🥓', '🧇', '🥞', '🍩']; + +export const CustomEmojiPicker = () => { + const [open, setOpen] = useState(false); + + const { insertText, textareaRef } = useMessageInputContext('CustomEmojiPicker'); + + return ( +
    + {open && ( +
    + {emojis.map((emoji) => ( + + ))} +
    + )} + + +
    + ); +}; +``` + +![Preview of the custom EmojiPicker component](../../assets/custom-emoji-picker.png) diff --git a/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/gallery.mdx b/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/gallery.mdx new file mode 100644 index 000000000..34722be19 --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/gallery.mdx @@ -0,0 +1,114 @@ +--- +id: image_gallery +title: Image Gallery +--- + +import Gallery from '../../assets/Gallery.png'; + +In this example, we demonstrate how to replace our default image [`Gallery`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Gallery/Gallery.tsx) +component with a custom implementation. The `Gallery` component is a child of `Attachment`, so we'll need +to create a custom `Attachment` component as well. + +## React Image Gallery + +In this example, we are going to use the [`react-image-gallery`](https://www.npmjs.com/package/react-image-gallery) +dependency. Many pre-built React image galleries exists, so this demo just shows one possible way to replace the +library's default `Gallery` component. + +We'll need to import a few additional modules into our app to access the main component, an item type, and the +distributed CSS: + +```tsx +import ImageGallery, { ReactImageGalleryItem } from 'react-image-gallery'; +import 'react-image-gallery/styles/css/image-gallery.css'; +``` + +## Custom Gallery + +A custom component will always receive the same props as the library's default. In the case of `Gallery`, the custom component +receives an array of image objects to be loaded. Each image object contains an `image_url` key, which references the CDN-hosted +URL of the image. + +The `ImageGallery` component we've imported requires an `items` prop. The `items` prop accepts a similar array of image objects, +with the `original` key as the only required type. The `original` key references the image URL, similar to the `image_url` +key coming into the component via props. + +To make the types line up, we manipulate the props array of images slightly, and pass into the `ImageGallery` component. + +```tsx +const CustomGallery: React.FC = (props) => { + const { images } = props; + + const updatedImages: ReactImageGalleryItem[] = []; + + Object.values(images).forEach((image) => { + if (image.image_url) { + updatedImages.push({ original: image.image_url }); + } + }); + + return ; +}; +``` + +## Custom Attachment + +In order to render our `CustomGallery` component, we need to supply it as a prop to the +[`Attachment`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/Attachment.tsx) +component. The resulting `CustomAttachment` component is then added to `Channel`, so it can be injected into the +`ComponentContext` and consumed within the [Message UI](../../components/message-components/message-ui.mdx) component. + +```tsx +const CustomAttachment: React.FC = (props) => ( + +); + +{/* children of Channel component */}; +``` + +## Implementation + +Now that each individual piece has been constructed, we can assemble all of the snippets into the final code example. + +### The Code + +```tsx +import ImageGallery, { ReactImageGalleryItem } from 'react-image-gallery'; +import 'react-image-gallery/styles/css/image-gallery.css'; + +const CustomGallery: React.FC = (props) => { + const { images } = props; + + const updatedImages: ReactImageGalleryItem[] = []; + + Object.values(images).forEach((image) => { + if (image.image_url) { + updatedImages.push({ original: image.image_url }); + } + }); + + return ; +}; + +const CustomAttachment: React.FC = (props) => { + return ; +}; + +const App = () => ( + + + + + + + + + + + +); +``` + +### The Result + +Gallery diff --git a/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/giphy-preview.mdx b/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/giphy-preview.mdx new file mode 100644 index 000000000..2f2cbcc9f --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/giphy-preview.mdx @@ -0,0 +1,79 @@ +--- +id: giphy_preview +title: Giphy Preview +--- + +import GiphyPreview from '../../assets/GiphyPreview.png'; + +This example demonstrates how to build a custom component to override the default `GiphyPreviewMessage` component that is rendered optionally in the +`VirtualizedMessageList`. + +## separateGiphyPreview Prop + +When the `separateGiphyPreview` prop on the list is set to true, the Giphy preview is rendered in a separate component above the `MessageInput` rather than inline with the other messages in the list. +This separate component makes it so the preview doesn't scroll away in the large channel. + +```jsx + +``` + +## Implementation + +Our custom preview component will render an `Attachment` component with a custom `AttachmentActions` UI component, which handles the onClick functionality. +This functionality is handled with the `handleAction` method via the `Message` component's `useActionHandler` hook. + +```jsx +const CustomAttachmentActions: React.FC = (props) => { + const { actionHandler, actions } = props; + + const handleClick = async ( + event: React.MouseEvent, + value?: string, + name?: string, + ) => { + try { + if (actionHandler) await actionHandler(name, value, event); + } catch (err) { + console.log(err); + } + }; + + return ( + <> + {actions.map((action) => ( + + ))} + + ); +}; + +const CustomGiphyPreview: React.FC = (props) => { + const { message } = props; + + const handleAction = useActionHandler(message); + + if (!message.attachments) return null; + + return ( + + ); +}; + + + + + + + +; +``` + +## The Result + +Custom GiphyPreview component for Chat diff --git a/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/link-preview.mdx b/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/link-preview.mdx new file mode 100644 index 000000000..5d3b357f2 --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/link-preview.mdx @@ -0,0 +1,394 @@ +--- +id: link-previews +title: Link Previews in Message Input +--- + +import LinkPreviewMessageInput from '../../assets/link-preview-message-input.png'; +import LinkPreviewEditMessageForm from '../../assets/link-preview-edit-message-form.png'; + +The purpose of link previews in the `MessageInput` is to provide visual guides of what a user may expect to be rendered later in the `MessageList` by [`Card` component](../../../components/message-components/attachment#card) among message attachments. + +## Rendering of link previews + +The link previews are rendered using `LinkPreviewList`. The component accepts a single prop `linkPreviews` which is an array of `LinkPreview` objects. + +### The default LinkPreviewList component + +The default `LinkPreviewList` component lists all the successfully loaded previews. + +The default link preview UI is implemented for: + +**Message input** + + + +
    + +**Edit message form** + + + +### Enabling link previews + +Link previews have to be enabled in two places: + +- [**channel config property `url-enrichment`**](https://getstream.io/chat/docs/javascript/channel-level_settings/?language=javascript&q=url_enrichment#list-of-settings-that-can-be-overridden) - enabled by default +- `enrichURLForPreview` prop - disabled by default + +Those who have not previously disabled `url-enrichment` in the channel config, can enable link previews in `MessageInput` by setting `enrichURLForPreview` in one of the following places: + +**Channel props** + +```tsx +import { + Channel, + ChannelHeader, + VirtualizedMessageList as MessageList, + MessageInput, + Thread, + Window, +} from 'stream-chat-react'; + +const App = () => ( + // highlight-next-line + + + + + + + + +); + +export default App; +``` + +**MessageList or VirtualizedMessageList (applied to EditMessageForm)** + +```tsx +import { Channel, VirtualizedMessageList as MessageList } from 'stream-chat-react'; + +const App = () => ( + + {/* ... */} + // highlight-start + + // highlight-end + {/* ... */} + +); + +export default App; +``` + +**Thread (applied to MessageInput)** + +```tsx +import { Channel, Thread } from 'stream-chat-react'; + +const App = () => ( + + {/* ... */} + // highlight-start + + // highlight-end + +); + +export default App; +``` + +**MessageInput** + +```tsx +import { Channel, MessageInput } from 'stream-chat-react'; + +const App = () => ( + + {/* ... */} + // highlight-next-line + + {/* ... */} + +); + +export default App; +``` + +## Link Preview customization + +### Custom rendering of link previews + +If the default link previews UI does not meet our expectations, we can provide a custom component. To render our own `LinkPreviewList`, we just need to pass it to `Channel` prop `LinkPreviewList`. The component will be passed `linkPreviews`, an array of `LinkPreview` objects. + +```tsx +import { Channel, LinkPreviewListProps, LinkPreviewState } from 'stream-chat-react'; + +import { LinkPreviewCardLoaded, LinkPreviewCardLoading } from './LinkPreviewCard'; + +const CustomLinkPreviewList = ({ linkPreviews }: LinkPreviewListProps) => { + const showLinkPreviews = linkPreviews.length > 0; + + if (!showLinkPreviews) return null; + + return ( +
    + {Array.from(linkPreviews.values()).map((linkPreview) => { + switch (linkPreview.state) { + case LinkPreviewState.LOADED: + return ( + + ); + case LinkPreviewState.LOADING: + return ( + + ); + case LinkPreviewState.QUEUED: + return ( + + ); + default: + return null; + } + })} +
    + ); +}; + +const App = () => ( + // highlight-next-line + + {/* ... */} + +); + +export default App; +``` + +### Link preview states + +In the above example we can notice, that the `LinkPreview` object comes with property `state`. This property can be used to determine, how the preview for a given link should be rendered. These are the possible states a link preview can acquire: + +```typescript +enum LinkPreviewState { + /** Link preview has been dismissed using MessageInputContextValue.dismissLinkPreview **/ + DISMISSED = 'dismissed', + /** Link preview could not be loaded, the enrichment request has failed. **/ + FAILED = 'failed', + /** Link preview has been successfully loaded. **/ + LOADED = 'loaded', + /** The enrichment query is in progress for a given link. **/ + LOADING = 'loading', + /** The link is scheduled for enrichment. **/ + QUEUED = 'queued', +} +``` + +### Behavior customization + +The following aspect of link preview management in `MessageInput` can be customized: + +- The debounce interval for the URL discovery and enrichment requests. +- URL discovery +- Link preview dismissal + +In general, the behavior can be customized in two ways: + +1. globally through `Channel` props (`enrichURLForPreviewConfig`) +2. with more granularity over `MessageList`, `VirtualizedMessageList`, `Thread`, `MessageInput` props (`additionalMessageInputProps.urlEnrichmentConfig`) + +#### Custom debounce interval + +The default debounce interval is 1.5 seconds. The URL discovery and enrichment will thus not start until the stops typing for at least 1.5 seconds. This interval can be increased or decreased by passing `debounceURLEnrichmentMs` configuration parameter. + +Global debounce interval configuration over `Channel`: + +```tsx +import { + Channel, + MessageInput, + Thread, + VirtualizedMessageList as MessageList, +} from 'stream-chat-react'; + +const debounceURLEnrichmentMs = 1000; + +const App = () => ( + + + + + +); +``` + +Local debounce configuration: + +```tsx +import { + Channel, + MessageInput, + Thread, + VirtualizedMessageList as MessageList, +} from 'stream-chat-react'; + +const debounceURLEnrichmentMs = 1000; +const additionalMessageInputProps = { + urlEnrichmentConfig: { debounceURLEnrichmentMs }, +}; + +const App = () => ( + + + + + +); +``` + +#### Custom text parsing function + +If the default link discovery functionality is not sufficient, this can be overridden by providing `findURLFn` custom function. The requirement is that the function returns an array of strings - links - that will be later used to scrape the data. + +The parameter set globally over `Channel` props: + +```tsx +import { + Channel, + MessageInput, + Thread, + VirtualizedMessageList as MessageList, +} from 'stream-chat-react'; + +import { searchForURLs } from '../utils'; + +const App = () => ( + + + + + +); +``` + +Local configuration of URL discovery function: + +```tsx +import { + Channel, + MessageInput, + Thread, + VirtualizedMessageList as MessageList, +} from 'stream-chat-react'; + +import { searchForURLs } from '../utils'; + +const additionalMessageInputProps = { + urlEnrichmentConfig: { findURLFn: searchForURLs }, +}; + +const App = () => ( + + + + + +); +``` + +#### Custom actions on link preview dismissal + +When a link preview is dismissed, it's state is set to `'dismissed'`. This behavior can be expanded (not changed) by providing `onLinkPreviewDismissed` callback. The callback is invoked at the beginning of the dismissal procedure. It is then followed by state update marking the given URL preview as `'dismissed'`. + +The `onLinkPreviewDismissed` callback can be passed to `Channel` prop `enrichURLForPreviewConfig`: + +```tsx +import { + Channel, + LinkPreview, + MessageInput, + Thread, + VirtualizedMessageList as MessageList, +} from 'stream-chat-react'; + +const onLinkPreviewDismissed = (linkPreview: LinkPreview) => { + // custom logic to invoke, when a given link preview is dismissed +}; + +const App = () => ( + + + + + +); +``` + +The configuration can be passed individually to `MessageList`, `VirtualizedMessageList`, `Thread`, `MessageInput`: + +```tsx +import { + Channel, + LinkPreview, + MessageInput, + Thread, + VirtualizedMessageList as MessageList, +} from 'stream-chat-react'; + +const onLinkPreviewDismissed = (linkPreview: LinkPreview) => { + // custom logic to invoke, when a given link preview is dismissed +}; + +const additionalMessageInputProps = { + urlEnrichmentConfig: { onLinkPreviewDismissed }, +}; + +const App = () => ( + + + + + +); +``` + +### EnrichURLsController API + +In case we would aspire at implementing custom `MessageInput` components that would require control over link previews, we can access the API over the `MessageInputContext` value. This is the API that allows us: + +- to trigger URL search in message text and enrichment - `findAndEnqueueURLsToEnrich` +- cancel the URL enrichment (for example when submitting a message) - `cancelURLEnrichment` +- dismiss the loaded link previews assigning them with state `dismissed` - `dismissLinkPreview` + +```tsx +import { useMessageInputContext } from 'stream-chat-react'; + +const CustomMessageInputUI = () => { + const { + cancelURLEnrichment, + findAndEnqueueURLsToEnrich, + dismissLinkPreview, + } = useMessageInputContext(); + + // ... +}; + +const App = () => { + + {/* ... */} + ; +}; +``` + +:::note +The `findAndEnqueueURLsToEnrich` function serves as an indicator, whether the link preview feature is actually enabled in the application. +::: diff --git a/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/override-submit-handler.mdx b/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/override-submit-handler.mdx new file mode 100644 index 000000000..dcc818953 --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/override-submit-handler.mdx @@ -0,0 +1,147 @@ +--- +id: override_submit_handler +title: Input Submit Handler +--- + +import SubmitHandler from '../../assets/SubmitHandler.png'; +import MessageCustomPayload from '../../assets/message-payload-custom-fields.png'; + +In this example, we demonstrate how to provide custom logic and override the [`MessageInput`](../../components/message-input-components/message-input.mdx) +component's default submit handler function. Our custom handler function will bold any message text. + +## overrideSubmitHandler Prop + +The `MessageInput` component accepts an `overrideSubmitHandler` prop, which allows you to add custom logic to the +conclusion of the underlying `textarea` element's [`handleSubmit`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/MessageInput/hooks/useSubmitHandler.ts) +function. + +:::note +You do not have to implement your custom submit handler, if the only thing you need is to pass custom message data to the underlying API call. In that case you can use the [`handleSubmit`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/MessageInput/hooks/useSubmitHandler.ts) function from the [`MessageInputContext`](../../components/contexts/message-input-context.mdx). The `handleSubmit` function allows you to pass custom message data through its second parameter `customMessageData`. This applies to sending a new message as well as updating an existing one. In order for this to work, you will have to implement custom message input components and pass them to [`Channel`](../../components/core-components/channel.mdx) props `EditMessageInput` or `Input` respectively. +::: + +The `overrideSubmitHandler` function receives three arguments, the message to be sent, the `cid` (channel type prepended to channel id) +for the currently active channel and optionally custom message data. The message object (the first argument) is of the following type: + +```tsx +type MessageToSend = { + attachments?: MessageAttachments; + error?: ErrorFromResponse; + errorStatusCode?: number; + id?: string; + mentioned_users?: UserResponse[]; + parent?: StreamMessage; + parent_id?: string; + status?: string; + text?: string; +}; +``` + +:::important +Call the `sendMessage` function from the [`ChannelActionContext`](../../components/contexts/channel-action-context.mdx#sendmessage) within +your custom function to ensure a message is sent to the active channel. +::: + +## Custom Function + +For this example, we will take the input text entered by the user and wrap it in two asterisks to render bold markdown. Once we've +added the markdown characters, we call the `sendMessage` function with the updated message object. + +```tsx +const overrideSubmitHandler = (message: MessageToSend, cid: string) => { + const boldMessage = { + ...message, + text: `**${message.text}**`, + }; + + sendMessage(boldMessage); +}; +``` + +## Implementation + +Now that we have our custom function, we can add the `overrideSubmitHandler` prop to the `MessageInput` component and begin sending +bold text to our `MessageList`. + +:::note +Since `sendMessage` is drawn from the `ChannelActionContext`, we must create an inner component that is a child of `Channel` and +call the `useChannelActionContext` custom hook. +::: + +### The Code + +```tsx +const ChannelInner: React.FC = () => { + const { sendMessage } = useChannelActionContext(); + + const overrideSubmitHandler = (message: MessageToSend, cid: string) => { + const boldMessage = { + ...message, + text: `**${message.text}**`, + }; + + sendMessage(boldMessage); + }; + + return ( + <> + + + + + + + + ); +}; + +const App = () => ( + + + + + + +); +``` + +### The Result + +Override Submit Handler + +## Adding custom message data + +If you would like to store custom data on your message objects, you can pass additional parameters to the [`sendMessage`](../../components/contexts/channel-action-context.mdx#sendmessage) function you retrieve from `ChannelActionContext`. + +Now, the `overrideSubmitHandler` implementation may change as follows: + +```tsx +import React from 'react'; +import { + ChannelHeader, + MessageList, + MessageInput, + Window, + MessageToSend, + useChannelActionContext, +} from 'stream-chat-react'; + +const ChannelInner = () => { + const { sendMessage } = useChannelActionContext(); + + const overrideSubmitHandler = (message: MessageToSend, cid: string) => { + sendMessage(message, { important: true }); + }; + + return ( + + + + + + ); +}; +``` + +In your browser's Developer tools Network tab you can now observe, that the message payload includes the custom field: + +{'Custom diff --git a/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/overview.mdx b/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/overview.mdx new file mode 100644 index 000000000..d5391b33f --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/overview.mdx @@ -0,0 +1,29 @@ +--- +id: customization-overview +slug: /guides/customization/ +title: Overview +--- + +When [Theming](../../theming/introduction.mdx) is not enough for how you want our chat SDK to look and behave, customization is the next step. By customizing specific components you can make precise adjustments to the look and feel of our SDK exactly where you need them. + +## Showcase of the Default UI Components + +### MessageList + +![Default MessageList](../../assets/default-message-list.png) + +### ChannelList + +![Default ChannelList](../../assets/default-channel-list.png) + +### MessageInput + +![Default MessageInput](../../assets/default-message-input.png) + +### ChannelHeader + +![Default ChannelHeader](../../assets/default-channel-header.png) + +### Thread + +![Default Thread](../../assets/default-thread.png) diff --git a/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/persist-input-text-in-local-storage.mdx b/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/persist-input-text-in-local-storage.mdx new file mode 100644 index 000000000..01cb6bf23 --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/persist-input-text-in-local-storage.mdx @@ -0,0 +1,189 @@ +--- +id: persist_input_text_in_localstorage +slug: /guides/persist-input-text-in-localstorage/ +title: Storing message drafts +--- + +In this recipe, we would like to demonstrate how you can start storing unsent user's messages as drafts. The whole implementation turns around the use of `MessageInput`'s prop `getDefaultValue` and custom change event handler. We will store the messages in localStorage. + +## Building the draft storage logic + +Below, we have a simple logic to store all the message text drafts in a localStorage object under the key `@chat/drafts`. + +```ts +const STORAGE_KEY = '@chat/drafts'; + +const getDrafts = () => JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}'); + +const removeDraft = (key: string) => { + const drafts = getDrafts(); + + if (drafts[key]) { + delete drafts[key]; + localStorage.setItem(STORAGE_KEY, JSON.stringify(drafts)); + } +}; + +const updateDraft = (key: string, value: string) => { + const drafts = getDrafts(); + + if (!value) { + delete drafts[key]; + } else { + drafts[key] = value; + } + + localStorage.setItem(STORAGE_KEY, JSON.stringify(drafts)); +}; +``` + +On top of this logic we build a hook that exposes the change handler functions for both thread and main `MessageInput` components as well as functions for `MessageInput`'s `getDefaultValue` prop. We also have to override the `MessageInput`'s default submit handler, because we want to remove the draft from storage when a message is sent. + +```ts +import { ChangeEvent, useCallback } from 'react'; +import { MessageToSend, useChannelActionContext, useChannelStateContext } from 'stream-chat-react'; +import type { Message } from 'stream-chat'; + +const STORAGE_KEY = '@chat/drafts'; + +const getDrafts = () => JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}'); + +const removeDraft = (key: string) => { + const drafts = getDrafts(); + + if (drafts[key]) { + delete drafts[key]; + localStorage.setItem(STORAGE_KEY, JSON.stringify(drafts)); + } +}; + +const updateDraft = (key: string, value: string) => { + const drafts = getDrafts(); + + if (!value) { + delete drafts[key]; + } else { + drafts[key] = value; + } + + localStorage.setItem(STORAGE_KEY, JSON.stringify(drafts)); +}; + +// highlight-start +const useDraftAPI = () => { + const { channel, thread } = useChannelStateContext(); + const { sendMessage } = useChannelActionContext(); + + const handleInputChange = useCallback( + (e: ChangeEvent) => { + updateDraft(channel.cid, e.target.value); + }, + [channel.cid], + ); + + const handleThreadInputChange = useCallback( + (e: ChangeEvent) => { + if (!thread) return; + updateDraft(`${channel.cid}:${thread.id}`, e.target.value); + }, + [channel.cid, thread], + ); + + const getMainInputDraft = useCallback(() => { + const drafts = getDrafts(); + return drafts[channel.cid] || ''; + }, [channel.cid]); + + const getThreadInputDraft = useCallback(() => { + if (!thread) return; + const drafts = getDrafts(); + return drafts[`${channel.cid}:${thread.id}`] || ''; + }, [channel.cid, thread]); + + const overrideSubmitHandler = useCallback( + async (message: MessageToSend, channelCid: string, customMessageData?: Partial) => { + await sendMessage(message, customMessageData); + const key = message.parent ? `${channelCid}:${message.parent.id}` : channelCid; + removeDraft(key); + }, + [sendMessage], + ); + + return { + getMainInputDraft, + getThreadInputDraft, + handleInputChange, + handleThreadInputChange, + overrideSubmitHandler, + }; +}; +// highlight-end +``` + +## Plugging it in + +Now it is time to access the API in our React component. The component has to be a descendant of `Channel` component, because `useDraftAPI` accesses the `ChannelStateContext` and `ChannelActionContext` through corresponding consumers. In our example we call this component `ChannelWindow`. + +```tsx +import { ChannelFilters, ChannelOptions, ChannelSort, StreamChat } from 'stream-chat'; +import { useDraftAPI } from './useDraftAPI'; +import type { StreamChatGenerics } from './types'; + +const ChannelWindow = () => { + const { + getMainInputDraft, + getThreadInputDraft, + handleInputChange, + handleThreadInputChange, + overrideSubmitHandler, + } = useDraftAPI(); + + return ( + <> + + + + + + + + + ); +}; + +// In your application you will probably initiate the client in a React effect. +const chatClient = StreamChat.getInstance(''); + +// User your own filters, options, sort if needed +const filters: ChannelFilters = { type: 'messaging', members: { $in: [''] } }; +const options: ChannelOptions = { state: true, presence: true, limit: 10 }; +const sort: ChannelSort = { last_message_at: -1, updated_at: -1 }; + +const App = () => { + return ( + + + + + + + ); +}; +``` + +Now once you start typing, you should be able to see the drafts in the `localStorage` under the key `@chat/drafts`. Despite changing channels or threads, the unsent message text should be kept in the textarea. diff --git a/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/pin-indicator.mdx b/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/pin-indicator.mdx new file mode 100644 index 000000000..2edee4d12 --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/pin-indicator.mdx @@ -0,0 +1,106 @@ +--- +id: pin_indicator +title: Pin Indicator +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +In this example, we will demonstrate how to create a custom pin indicator for pinned messages. [Pinned messages](https://getstream.io/chat/docs/javascript/pinned_messages/?language=javascript) allow users to highlight important messages, make announcements, or temporarily promote content. + +## Custom Pin Indicator + +### CSS Based Solution + +Let's start with the less invasive and fairly simple CSS based solution. All the class names you need to build this feature are in place and toggled appropriately. We'll add `::before` pseudo-class to our message bubble element with a pin (📌) icon to display whenever message has been pinned. + +```css +.str-chat__message--pinned .str-chat__message-bubble::before { + content: '📌'; + display: flex; + align-items: center; + justify-content: center; + position: absolute; + background-color: papayawhip; + font-size: 0.6rem; + width: 1.4rem; + height: 1.4rem; + border-radius: 9999px; + z-index: 1; + top: -10px; +} + +.str-chat__message--other.str-chat__message--pinned .str-chat__message-bubble::before { + right: -10px; +} + +.str-chat__message--me.str-chat__message--pinned .str-chat__message-bubble::before { + left: -10px; +} +``` + +![Custom Pin Indicator - CSS Based Solution](../../assets/custom-pin-indicator-css.png) + +### Component Based Solution + +While CSS solution is certainly less invasive it's also less malleable when it comes to hooking some JavaScript to it. For that case the component based solution is also an option. In this example we'll build an indicator which displays the name of the user who pinned the message. We'll pass our custom component to the [`Channel`](../../components/core-components/channel.mdx) prop `PinIndicator` which forwards it to [`ComponentContext`](../../components/contexts/component-context.mdx) from which it'll be picked up by the [`MessageSimple`](../../components/message-components/message-ui.mdx) component to render. + + + + +```jsx +import { Channel } from 'stream-chat-react'; + +const CustomPinIndicator = () => { + const { message } = useMessageContext('CustomPinIndicator'); + + const pinnedBy = message.pinned_by?.name || message.pinned_by?.id; + + if (!pinnedBy) return null; + + return
    📌 Pinned by {pinnedBy}
    ; +}; + +//... + +...; +``` + +
    + + +```css +.pin-indicator { + grid-area: pin; +} + +.str-chat__message.str-chat__message--other, +.str-chat__message.str-chat__quoted-message-preview { + grid-template-areas: + '. pin' + 'avatar message' + '. replies' + '. translation-notice' + '. custom-metadata' + '. metadata'; +} + +.str-chat__message.str-chat__message--me { + grid-template-areas: + 'pin' + 'message' + 'replies' + 'translation-notice' + 'custom-metadata' + 'metadata'; +} +``` + + +
    + +![Custom Pin Indicator](../../assets/custom-pin-indicator.png) + +### Read More + +See more on permissions regarding message pinning in [_Permissions v2_](https://getstream.io/chat/docs/react/user_permissions/?language=javascript) section of our JS documentation. diff --git a/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/suggestion-list.mdx b/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/suggestion-list.mdx new file mode 100644 index 000000000..9b9c582dc --- /dev/null +++ b/docusaurus/react_versioned_docs/version-11.x.x/guides/customization/suggestion-list.mdx @@ -0,0 +1,794 @@ +--- +id: suggestion_list +title: Autocomplete Suggestions +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +One of the advanced features of the message input is autocompletion support. By default, it +autocompletes mentions, commands and emojis. + +Autocomplete suggestions are triggered by typing the special characters: + +| Trigger | Action | Example | +| ------- | ------- | -------- | +| `@` | mention | @user | +| `/` | command | /giphy | +| `:` | emoji | :smiling | + +The default message input component provided by the SDK supports this out of the box. When a trigger +character is typed into the message input, a list of suggested options appears: + +![](../../assets/message-input-ui-suggestions.png) + +If you want to customize the look and behavior of the suggestions list, you have two options: + +1. Use the default message input provided by the SDK, and override the following components to + customize the look and feel of the suggestion list: + + - [`AutocompleteSuggestionItem`](../../components/contexts/component-context.mdx#autocompletesuggestionitem) + - [`AutocompleteSuggestionList`](../../components/contexts/component-context.mdx#autocompletesuggestionlist) + +2. Implement the message input component from scratch, and add autocomplete functionality to it + yourself. + +Let's explore both options. + +## Overriding the Suggestion Item Component + +Let's start by creating a custom suggestion item component. + +As usual, to override a component used by the SDK, you should pass a custom component as a prop to +the [`Channel`](../../components/core-components/channel.mdx) component in your application code. In +this case we are overriding +[`AutocompleteSuggestionItem`](../../components/contexts/component-context.mdx#autocompletesuggestionitem): + +```jsx +import { + Chat, + Channel, + ChannelHeader, + ChannelList, + MessageList, + Thread, + Window, + MessageInput, +} from 'stream-chat-react'; +import { SearchIndex } from 'emoji-mart'; + +export const App = () => ( + + + + + + + + + + + +); +``` + +Since we are not overriding the entire suggestion list yet, just an item component, our custom item +component will get all the necessary data and callbacks in props - the default +`AutocompleteSuggestionList` will take care of that. + +This makes the basic implementation pretty straightforward. Two things to note, though: + +1. To show different previews for different item types (e.g. we want to show avatars for users and + emoji previews for emojis) we need to put in type guards for each item type. +2. The default `AutocompleteSuggestionList` requires you to call the `onSelectHandler` callback when + an item is focused or hovered. This is to ensure that items in the list are keyboard accessible. + + + + +```jsx +const CustomSuggestionItem = (props) => { + const { item } = props; + let children = null; + + // Item is an emoji suggestion + if ('native' in item && typeof item.native === 'string') { + children = ( + <> + {item.native} + {item.name} + + ); + } + + // Item is a user to be mentioned + if (!('native' in item) && 'id' in item) { + children = ( + <> + + {item.name ?? item.id} + + ); + } + + // Item is a command configured for the current channel + if ('name' in item && 'description' in item) { + children = ( + <> + /{item.name} + {item.description} + + ); + } + + return ( + + ); +}; +``` + + + + +```css +.suggestion-list__item { + display: flex; + align-items: center; + gap: 10px; + font: inherit; + border: 0; + background: none; + padding: 20px 10px; +} + +.suggestion-list__item_selected { + background: #00000014; +} +``` + + + + +![](../../assets/message-input-ui-emoji-suggestions.png) +![](../../assets/message-input-ui-user-suggestions.png) +![](../../assets/message-input-ui-command-suggestions.png) + +If you are building an internationalized application, you will need to translate command +descriptions and arguments. Translations for all of the supported languages are provided with the +SDK. You can access them by using the translation helper function provided in the +[`TranslationContext`](../theming/translations.mdx). All you need to do is to query the translation +with the right key: `-command-description` for the description, and +`-command-args` for the arguments (you can always refer to our +[translation files](https://github.com/GetStream/stream-chat-react/blob/master/src/i18n/es.json) to +check if the key is correct). + +```jsx +// In CustomSuggestionItem component: +const { t } = useTranslationContext(); + +// Item is a command configured for the current channel +if ('name' in item && 'description' in item) { + children = ( + <> + /{item.name} + {t(`${item.name}-command-description`, { + defaultValue: item.description, + })} + + ); +} +``` + +![](../../assets/message-input-ui-suggestions-localized.png) + +The English (US) translation is loaded from the Stream backend as part of the channel config object, +and is not part of the translation resources, so we explicitly set it as the fallback value. + +## Overriding the Suggestion List Component + +If you want to further customize the default behavior of the suggestion list, you can override the +entire list component. + +This is an easy way to add a header or footer to the list. You don't have to reimplement the whole +list component, just create a small wrapper: + + + + +```jsx +import { DefaultSuggestionList } from 'stream-chat-react'; + +const SuggestionListWithHeader = (props) => { + let header = ''; + + if (props.currentTrigger === '@') { + header = 'Users'; + } + + if (props.currentTrigger === '/') { + header = 'Commands'; + } + + if (props.currentTrigger === ':') { + header = 'Emoji'; + } + + if (props.value && props.value.length > 1) { + header += ` matching "${props.value.slice(1)}"`; + } + + return ( + <> +
    {header}
    + + + ); +}; +``` + +
    + + +```css +.suggestion-list__header { + padding: 10px; + font-size: 0.9em; +} +``` + + +
    + +This wrapper uses two props (provided to your component by the default message input component) to +construct a header: `currentTrigger` contains the special character that triggered autocomplete, and +`value` contains the query the user has typed so far. + +Then override the +[`AutocompleteSuggestionList`](../../components/contexts/component-context.mdx#autocompletesuggestionlist) +list at the [`Channel`](../../components/core-components/channel.mdx) level, and you're done: + +```jsx +import { + Chat, + Channel, + ChannelHeader, + ChannelList, + MessageList, + Thread, + Window, + MessageInput, +} from 'stream-chat-react'; +import { SearchIndex } from 'emoji-mart'; + +export const App = () => ( + + + + + + + + + + + +); +``` + +![](../../assets/message-input-ui-suggestions-header.png) + +Or you can go deeper and reimplement the entire list component from scratch. Note that in this case +it's up to you to handle the interactions and accessibility. This example implementation is a good +starting point, but it doesn't handle any keyboard interactions: + + + + +```jsx +const CustomSuggestionList = (props) => { + const [selectedIndex, setSelectedIndex] = useState(0); + + if (selectedIndex >= props.values.length && selectedIndex !== 0) { + setSelectedIndex(0); + } + + const handleClick = (item) => { + props.onSelect(props.getTextToReplace(item)); + }; + + return ( +
      + {props.values.map((item, index) => ( +
    • + setSelectedIndex(index)} + onClickHandler={() => handleClick(item)} + /> +
    • + ))} +
    + ); +}; +``` + +
    + + +```css +.suggestion-list { + list-style: none; + padding: 0; + margin: 0; +} + +.suggestion-list__item { + display: flex; + align-items: center; + gap: 10px; + width: 100%; + font: inherit; + border: 0; + background: none; + padding: 20px 10px; +} + +.suggestion-list__item_selected { + background: #00000014; +} +``` + + +
    + +## Implementing Autocompletion for Custom Message Input + +Finally, if you are implementing the entire message input component +[from scratch](../theming/input-ui.mdx), it's up to you to build the autocomplete functionality. The +good news is that the +[`autocompleteTriggers`](../../components/contexts/message-input-context.mdx#autocompletetriggers) +value in the `MessageInputContext` provides a lot of reusable functionality. The bad news is that +properly implementing autocomplete is still a lot of work. + +Let's try to tackle that. We'll start with the simple message input implementation from the +[Message Input UI cookbook](../theming/input-ui.mdx): + +```jsx +import { useMessageInputContext } from 'stream-chat-react'; + +const CustomMessageInput = () => { + const { text, handleChange, handleSubmit } = useMessageInputContext(); + + return ( +
    +