mirror of
https://github.com/owncast/owncast.git
synced 2024-11-24 13:50:06 +03:00
emoji: display native emoji simiarly to custom (#3147)
This commit is contained in:
parent
cc75be1c00
commit
58bc3ac173
5 changed files with 79 additions and 0 deletions
|
@ -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';
|
||||
}
|
||||
}
|
1
web/package-lock.json
generated
1
web/package-lock.json
generated
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue