Skip to content

Commit 4a25912

Browse files
authored
feat(renderText): allow custom remark and rehype plugin composition (#2142)
Add optional parameters to `renderText()` to enable configuration of rehype and remark plugins used to transform message.text into React elements.
1 parent 6ea9ff0 commit 4a25912

File tree

27 files changed

+748
-507
lines changed

27 files changed

+748
-507
lines changed

docusaurus/docs/React/components/contexts/message-context.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ Custom function to render message text content.
341341

342342
| Type | Default |
343343
| -------- | -------------------------------------------------------------------------------------- |
344-
| function | [renderText](https://github.com/GetStream/stream-chat-react/blob/master/src/utils.tsx) |
344+
| function | <GHComponentLink text='renderText' path='/Message/renderText/renderText.tsx'/> |
345345

346346
### setEditingState
347347

docusaurus/docs/React/components/core-components/message-list.mdx

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,20 @@ The `MessageList` internally creates a mapping of message id to a style group. T
6666

6767
### Default behaviour
6868

69-
The output of the default [`renderText`](#render-text) function is a message text processed by the `ReactMarkdown` component with [`remark`](https://github.com/remarkjs/remark/blob/main/doc/plugins.md) [`remark-gfm`](https://github.com/remarkjs/remark-gfm) plugin and custom [`rehype`](https://github.com/rehypejs/rehype/blob/main/doc/plugins.md) plugins for mentions and emojis.
69+
The default [`renderText`](#render-text) function parses a markdown string and outputs a `ReactElement`. Under the hood, the output is generated by the `ReactMarkdown` component from [react-markdown library](https://github.com/remarkjs/react-markdown). The component transforms the markdown to `ReactElement` by using [`remark` parser](https://github.com/remarkjs/remark/tree/main) and [`remark`](https://github.com/remarkjs/remark/blob/main/doc/plugins.md) and [`rehype`](https://github.com/rehypejs/rehype/blob/main/doc/plugins.md) plugins.
70+
71+
The default `remark` plugins used by SDK are:
72+
73+
1. [`remark-gfm`](https://github.com/remarkjs/remark-gfm) - a third party plugin to add GitHub-like markdown support
74+
75+
The default `rehype` plugins (both specific to this SDK) are:
76+
1. plugin to render user mentions
77+
2. plugin to render emojis
7078

7179
### Overriding defaults
7280

81+
#### Custom `renderText` function
82+
7383
If you don't want your chat implementation to support markdown syntax by default you can override the default behaviour by creating a custom `renderText` function which returns a React node and passing it down to the `MessageList` or `MessageSimple` component via `renderText` property.
7484

7585
For this particular example we'll create a very primitive one which takes the message text passed down to it as a first argument and returns it wrapped in `span` element:
@@ -112,10 +122,12 @@ const App = () => (
112122
);
113123
```
114124

115-
If you feel like the default output is sufficient but you'd like to adjust how certain [ReactMarkdown components](https://github.com/remarkjs/react-markdown#appendix-b-components) look like (like `strong` element generated by typing \*\*strong\*\*) you can do so by passing down options to a third argument of the default `renderText` function:
125+
#### Custom element rendering
126+
127+
If you feel like the default output is sufficient, but you'd like to adjust how certain [ReactMarkdown components](https://github.com/remarkjs/react-markdown#appendix-b-components) look like (like `strong` element generated by typing \*\*strong\*\*) you can do so by passing down options to a third argument of the default `renderText` function:
116128

117129
:::note
118-
Types `mention` and `emoji` are special case component types generated by our custom rehype plugins. Currently we do not allow to add custom rehype/remark plugins to our default `renderText` function due to compatibility reasons regarding our custom plugins.
130+
Types `mention` and `emoji` are special case component types generated by our SDK's custom rehype plugins.
119131
:::
120132

121133
```tsx
@@ -146,6 +158,38 @@ const App = () => (
146158
);
147159
```
148160

161+
#### Custom remark and rehype plugins
162+
163+
If you would like to extend the array of plugins used to parse the markdown, you can provide your own lists of remark resp. rehype plugins. The logic that determines what plugins are used and in which order can be specified in custom `getRehypePlugins` and `getRemarkPlugins` functions. These receive the default array of rehype and remark plugins for further customization. Both custom functions ought to be passed to the third `renderText()` parameter. An example follows:
164+
165+
:::note
166+
It is important to understand what constitutes a rehype or remark plugin. A good start is to learn about the library called [`react-remark`](https://github.com/remarkjs/react-remark) which is used under the hood in our `renderText()` function.
167+
:::
168+
169+
170+
```tsx
171+
import { renderText, RenderTextPluginConfigurator } from 'stream-chat-react';
172+
import {customRehypePlugin} from './rehypePlugins';
173+
import {customRemarkPlugin} from './remarkPlugins';
174+
175+
const getRehypePlugins: RenderTextPluginConfigurator = (plugins) => {
176+
return [customRehypePlugin, ...plugins];
177+
}
178+
const getRemarkPlugins: RenderTextPluginConfigurator = (plugins) => {
179+
return [customRemarkPlugin, ...plugins];
180+
}
181+
182+
const customRenderText = (text, mentionedUsers) =>
183+
renderText(text, mentionedUsers, {
184+
getRehypePlugins,
185+
getRemarkPlugins
186+
});
187+
188+
const CustomMessageList = () => (
189+
<MessageList renderText={customRenderText}/>
190+
);
191+
```
192+
149193
## Props
150194

151195
### additionalMessageInputProps
@@ -434,7 +478,7 @@ Custom function to render message text content.
434478

435479
| Type | Default |
436480
| -------- | -------------------------------------------------------------------------------------- |
437-
| function | [renderText](https://github.com/GetStream/stream-chat-react/blob/master/src/utils.tsx) |
481+
| function | <GHComponentLink text='renderText' path='/Message/renderText/renderText.tsx'/> |
438482

439483
### retrySendMessage
440484

docusaurus/docs/React/components/message-components/message-ui.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ Custom function to render message text content (overrides the function stored in
460460

461461
| Type | Default |
462462
| -------- | -------------------------------------------------------------------------------------- |
463-
| function | [renderText](https://github.com/GetStream/stream-chat-react/blob/master/src/utils.tsx) |
463+
| function | <GHComponentLink text='renderText' path='/Message/renderText/renderText.tsx'/> |
464464

465465
### setEditingState
466466

docusaurus/docs/React/components/message-components/message.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ Custom function to render message text content.
326326

327327
| Type | Default |
328328
| -------- | -------------------------------------------------------------------------------------- |
329-
| function | [renderText](https://github.com/GetStream/stream-chat-react/blob/master/src/utils.tsx) |
329+
| function | <GHComponentLink text='renderText' path='/Message/renderText/renderText.tsx'/> |
330330

331331
### retrySendMessage
332332

src/__tests__/utils.test.js

Lines changed: 0 additions & 115 deletions
This file was deleted.

src/components/AutoCompleteTextarea/List.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import clsx from 'clsx';
33

44
import { useComponentContext } from '../../context/ComponentContext';
55
import { useChatContext } from '../../context/ChatContext';
6-
import { escapeRegExp } from '../../utils';
76

87
import { Item } from './Item';
98
import { DefaultSuggestionListHeader } from './Header';
9+
import { escapeRegExp } from '../Message/renderText';
1010

1111
export const List = ({
1212
className,

src/components/Avatar/Avatar.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React, { useEffect, useState } from 'react';
2-
3-
import { getWholeChar } from '../../utils';
2+
import { getWholeChar } from '../../utils/getWholeChar';
43

54
import type { UserResponse } from 'stream-chat';
65

src/components/Message/FixedHeightMessage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { useChatContext } from '../../context/ChatContext';
1414
import { useComponentContext } from '../../context/ComponentContext';
1515
import { useMessageContext } from '../../context/MessageContext';
1616
import { useTranslationContext } from '../../context/TranslationContext';
17-
import { renderText } from '../../utils';
17+
import { renderText } from './renderText';
1818

1919
import type { TranslationLanguages } from 'stream-chat';
2020

src/components/Message/MessageText.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import React, { useMemo } from 'react';
22

33
import { QuotedMessage as DefaultQuotedMessage } from './QuotedMessage';
4-
import { messageHasAttachments } from './utils';
4+
import { isOnlyEmojis, messageHasAttachments } from './utils';
55

66
import { useComponentContext, useMessageContext, useTranslationContext } from '../../context';
7-
import { renderText as defaultRenderText, isOnlyEmojis } from '../../utils';
7+
import { renderText as defaultRenderText } from './renderText';
88

99
import type { TranslationLanguages } from 'stream-chat';
1010
import type { MessageContextValue, StreamMessage } from '../../context';

src/components/Message/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ export * from './MessageStatus';
1010
export * from './MessageText';
1111
export * from './MessageTimestamp';
1212
export * from './QuotedMessage';
13+
export * from './renderText';
1314
export * from './types';
1415
export * from './utils';

0 commit comments

Comments
 (0)