-
Notifications
You must be signed in to change notification settings - Fork 279
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Separate renderText from MessageList
- Loading branch information
1 parent
b49e2b2
commit 064c462
Showing
4 changed files
with
163 additions
and
160 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
155 changes: 155 additions & 0 deletions
155
docusaurus/docs/React/components/message-components/render-text.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
--- | ||
id: render-text | ||
title: renderText function | ||
--- | ||
|
||
The `renderText` function is a core piece of functionality, which handles how the text of our message is going to be formatted/look like. 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. | ||
|
||
The default `remark` plugins used by SDK are: | ||
|
||
1. [`remark-gfm`](https://github.com/remarkjs/remark-gfm) - a third party plugin to add GitHub-like markdown support | ||
|
||
The default `rehype` plugins (both specific to this SDK) are: | ||
|
||
1. plugin to render user mentions | ||
2. plugin to render emojis | ||
|
||
### Overriding defaults | ||
|
||
#### Custom `renderText` function | ||
|
||
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. | ||
|
||
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: | ||
|
||
```tsx | ||
const customRenderText = (text) => { | ||
return <span>{text}</span>; | ||
}; | ||
|
||
const App = () => ( | ||
<Chat client={client}> | ||
<Channel> | ||
<Window> | ||
<MessageList renderText={customRenderText} /> | ||
</Window> | ||
</Channel> | ||
</Chat> | ||
); | ||
``` | ||
|
||
Here's also an example with `VirtualizedMessageList` which currently does not accept `renderText` directly: | ||
|
||
```tsx | ||
import { MessageSimple } from 'stream-chat-react'; | ||
|
||
const customRenderText = (text) => { | ||
return <span>{text}</span>; | ||
}; | ||
|
||
const CustomMessage = (props) => <MessageSimple {...props} renderText={customRenderText} />; | ||
|
||
const App = () => ( | ||
<Chat client={client}> | ||
<Channel> | ||
<Window> | ||
<VirtualizedMessageList Message={CustomMessage} /> | ||
</Window> | ||
</Channel> | ||
</Chat> | ||
); | ||
``` | ||
|
||
#### Custom element rendering | ||
|
||
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: | ||
|
||
:::note | ||
Types `mention` and `emoji` are special case component types generated by our SDK's custom rehype plugins. | ||
::: | ||
|
||
```tsx | ||
import { renderText } from 'stream-chat-react'; | ||
|
||
const StrongComponent = ({ children }) => <b className='custom-strong-class-name'>{children}</b>; | ||
|
||
const MentionComponent = ({ children, node: { mentionedUser } }) => ( | ||
<a data-user-id={mentionedUser.id} href={`/user-profile/${mentionedUser.id}`}> | ||
{children} | ||
</a> | ||
); | ||
|
||
const App = () => ( | ||
<Chat client={client}> | ||
<Channel> | ||
<Window> | ||
<MessageList | ||
renderText={(text, mentionedUsers) => | ||
renderText(text, mentionedUsers, { | ||
customMarkDownRenderers: { strong: StrongComponent, mention: MentionComponent }, | ||
}) | ||
} | ||
/> | ||
</Window> | ||
</Channel> | ||
</Chat> | ||
); | ||
``` | ||
|
||
#### Custom remark and rehype plugins | ||
|
||
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: | ||
|
||
:::note | ||
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. | ||
::: | ||
|
||
```tsx | ||
import { renderText, RenderTextPluginConfigurator } from 'stream-chat-react'; | ||
import { customRehypePlugin } from './rehypePlugins'; | ||
import { customRemarkPlugin } from './remarkPlugins'; | ||
|
||
const getRehypePlugins: RenderTextPluginConfigurator = (plugins) => { | ||
return [customRehypePlugin, ...plugins]; | ||
}; | ||
const getRemarkPlugins: RenderTextPluginConfigurator = (plugins) => { | ||
return [customRemarkPlugin, ...plugins]; | ||
}; | ||
|
||
const customRenderText = (text, mentionedUsers) => | ||
renderText(text, mentionedUsers, { | ||
getRehypePlugins, | ||
getRemarkPlugins, | ||
}); | ||
|
||
const CustomMessageList = () => <MessageList renderText={customRenderText} />; | ||
``` | ||
|
||
It is also possible to define your custom set of allowed tag names for the elements rendered from the parsed markdown. To perform the tree transformations, you will need to use libraries like [`unist-builder`](https://github.com/syntax-tree/unist-builder) to build the trees and [`unist-util-visit`](https://github.com/syntax-tree/unist-util-visit-parents) or [`hast-util-find-and-replace`](https://github.com/syntax-tree/hast-util-find-and-replace) to traverse the tree: | ||
|
||
```tsx | ||
import { findAndReplace } from 'hast-util-find-and-replace'; | ||
import { u } from 'unist-builder'; | ||
import { | ||
defaultAllowedTagNames, | ||
renderText, | ||
RenderTextPluginConfigurator, | ||
} from 'stream-chat-react'; | ||
|
||
// wraps every letter b in <xxx></xxx> tags | ||
const customTagName = 'xxx'; | ||
const replace = (match) => u('element', { tagName: customTagName }, [u('text', match)]); | ||
const customRehypePlugin = () => (tree) => findAndReplace(tree, /b/, replace); | ||
|
||
const getRehypePlugins: RenderTextPluginConfigurator = (plugins) => { | ||
return [customRehypePlugin, ...plugins]; | ||
}; | ||
|
||
const customRenderText = (text, mentionedUsers) => | ||
renderText(text, mentionedUsers, { | ||
allowedTagNames: [...defaultAllowedTagNames, customTagName], | ||
getRehypePlugins, | ||
}); | ||
|
||
const CustomMessageList = () => <MessageList renderText={customRenderText} />; | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -487,7 +487,7 @@ const doSendMessageRequest: ChannelProps['doSendMessageRequest'] = async ( | |
## Message text rendering | ||
|
||
Optional remark plugins `htmlToTextPlugin`, `keepLineBreaksPlugin` introduced with [[email protected]](https://github.com/GetStream/stream-chat-react/releases/tag/v10.19.0) are now included among the default remark plugins. That means that in the messages that originally contained a sequence of multiple newline characters `\n`, these will be replaced with line break elements `<br/>`. The number of line breaks equals count of newline characters minus 1. | ||
The dependencies used to parse the markdown with [`renderText()` function](../components/core-components/message-list.mdx#rendering-message-text-with-rendertext-function) have been upgraded as a result of that, the following changes had to be performed in stream-chat-react library: | ||
The dependencies used to parse the markdown with [`renderText` function](../components/message-components/render-text.mdx) have been upgraded as a result of that, the following changes had to be performed in stream-chat-react library: | ||
|
||
### `ReactMarkdownProps` dropped from `customMarkDownRenderers` | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters