emoji: display native emoji simiarly to custom (#3147)
This commit is contained in:
@@ -6,6 +6,7 @@ import dynamic from 'next/dynamic';
|
||||
import { Interweave } from 'interweave';
|
||||
import { UrlMatcher } from 'interweave-autolink';
|
||||
import { ChatMessageHighlightMatcher } from './customMatcher';
|
||||
import { ChatMessageEmojiMatcher } from './emojiMatcher';
|
||||
import styles from './ChatUserMessage.module.scss';
|
||||
import { formatTimestamp } from './messageFmt';
|
||||
import { ChatMessage } from '../../../interfaces/chat-message.model';
|
||||
@@ -111,6 +112,7 @@ export const ChatUserMessage: FC<ChatUserMessageProps> = ({
|
||||
matchers={[
|
||||
new UrlMatcher('url', { customTLDs: ['online'] }),
|
||||
new ChatMessageHighlightMatcher('highlight', { highlightString }),
|
||||
new ChatMessageEmojiMatcher('emoji', { className: 'emoji' }),
|
||||
]}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
71
web/components/chat/ChatUserMessage/emojiMatcher.ts
Normal file
71
web/components/chat/ChatUserMessage/emojiMatcher.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
/* eslint-disable class-methods-use-this */
|
||||
import { ChildrenNode, Matcher, MatchResponse, Node } from 'interweave';
|
||||
import rewritePattern from 'regexpu-core';
|
||||
import React from 'react';
|
||||
|
||||
export interface ChatMessageEmojiProps {
|
||||
key: string;
|
||||
}
|
||||
|
||||
interface options {
|
||||
className: string;
|
||||
}
|
||||
|
||||
const emojiPattern = '\\p{RGI_Emoji}+';
|
||||
|
||||
const regexSupportsUnicodeSets = (() => {
|
||||
// Using a variable for regexpFlags to avoid eslint error about the flag
|
||||
// being invalid. It's not invalid, it's just new.
|
||||
const regexpFlags = 'v';
|
||||
|
||||
// A bit more working around eslint - just calling new RegExp throws an
|
||||
// error about not saving the value / just using side effects.
|
||||
let regexp = null;
|
||||
try {
|
||||
regexp = new RegExp(emojiPattern, regexpFlags);
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We have to use the variable somehow. Since we didn't catch an error
|
||||
// this line always returns true.
|
||||
return regexp !== null;
|
||||
})();
|
||||
|
||||
const emojiRegex = (() => {
|
||||
const rewriteFlags = {
|
||||
unicodeSetsFlag: regexSupportsUnicodeSets ? 'parse' : 'transform',
|
||||
};
|
||||
const regexFlag = regexSupportsUnicodeSets ? 'v' : 'u';
|
||||
|
||||
const regexPattern = rewritePattern(emojiPattern, 'v', rewriteFlags);
|
||||
|
||||
return new RegExp(regexPattern, regexFlag);
|
||||
})();
|
||||
|
||||
export class ChatMessageEmojiMatcher extends Matcher {
|
||||
match(str: string): MatchResponse<{}> | null {
|
||||
const result = str.match(emojiRegex);
|
||||
|
||||
if (!result) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
index: result.index!,
|
||||
length: result[0].length,
|
||||
match: result[0],
|
||||
valid: true,
|
||||
};
|
||||
}
|
||||
|
||||
replaceWith(children: ChildrenNode, props: ChatMessageEmojiProps): Node {
|
||||
const { key } = props;
|
||||
const { className } = this.options as options;
|
||||
return React.createElement('span', { key, className }, children);
|
||||
}
|
||||
|
||||
asTag(): string {
|
||||
return 'span';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user