emoji: display native emoji simiarly to custom (#3147)

This commit is contained in:
John Regan 2023-07-06 15:47:38 -04:00 committed by GitHub
parent cc75be1c00
commit 58bc3ac173
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 79 additions and 0 deletions

View file

@ -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>

View 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';
}
}

1
web/package-lock.json generated
View file

@ -44,6 +44,7 @@
"react-markdown": "8.0.7",
"react-virtuoso": "4.3.11",
"recoil": "0.7.7",
"regexpu-core": "^5.3.2",
"sanitize-html": "^2.11.0",
"sharp": "0.32.1",
"ua-parser-js": "1.0.35",

View file

@ -49,6 +49,7 @@
"react-markdown": "8.0.7",
"react-virtuoso": "4.3.11",
"recoil": "0.7.7",
"regexpu-core": "^5.3.2",
"sanitize-html": "^2.11.0",
"sharp": "0.32.1",
"ua-parser-js": "1.0.35",

View file

@ -125,9 +125,13 @@ body {
}
.emoji {
display: inline-block;
font-size: 30px;
height: 30px;
line-height: 30px;
margin-left: 5px;
margin-right: 5px;
vertical-align: middle;
}
body::-webkit-scrollbar {