mirror of
				https://github.com/owncast/owncast.git
				synced 2025-11-04 13:27:21 +08:00 
			
		
		
		
	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';
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										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 {
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user