stream-chat-react
Version:
React components to create chat conversations or livestream style chat
51 lines (50 loc) • 2.45 kB
JavaScript
import { escapeRegExp } from '../regex';
import { findAndReplace } from 'hast-util-find-and-replace';
import { u } from 'unist-builder';
import { visit } from 'unist-util-visit';
export const mentionsMarkdownPlugin = (mentioned_users) => () => {
const mentioned_usernames = mentioned_users
.map((user) => user.name || user.id)
.filter(Boolean)
.map(escapeRegExp);
const mentionedUsersRegex = new RegExp(mentioned_usernames.map((username) => `@${username}`).join('|'), 'g');
const replace = (match) => {
const usernameOrId = match.replace('@', '');
const user = mentioned_users.find(({ id, name }) => name === usernameOrId || id === usernameOrId);
return u('element', { mentionedUser: user, properties: {}, tagName: 'mention' }, [
u('text', match),
]);
};
const transform = (tree) => {
if (!mentioned_usernames.length)
return;
// handles special cases of mentions where user.name is an e-mail
// Remark GFM translates all e-mail-like text nodes to links creating
// two separate child nodes "@" and "your.name@as.email" instead of
// keeping it as one text node with value "@your.name@as.email"
// this piece finds these two separated nodes and merges them together
// before "replace" function takes over
visit(tree, (node, index, parent) => {
if (typeof index === 'undefined')
return;
if (!parent)
return;
const nextChild = parent.children.at(index + 1);
const nextChildHref = nextChild?.properties?.href;
if (node.type === 'text' &&
// text value has to have @ sign at the end of the string
// and no other characters except whitespace can precede it
// valid cases: "text @", "@", " @"
// invalid cases: "text@", "@text",
/.?\s?@$|^@$/.test(node.value) &&
nextChildHref?.startsWith('mailto:')) {
const newTextValue = node.value.replace(/@$/, '');
const username = nextChildHref.replace('mailto:', '');
parent.children[index] = u('text', newTextValue);
parent.children[index + 1] = u('text', `@${username}`);
}
});
findAndReplace(tree, [mentionedUsersRegex, replace]);
};
return transform;
};