You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			111 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			TypeScript
		
	
			
		
		
	
	
			111 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			TypeScript
		
	
| import React from 'react';
 | |
| 
 | |
| import { getRegex, SizeClassType } from '../../util/emoji';
 | |
| 
 | |
| import { RenderTextCallbackType } from '../../types/Util';
 | |
| import { Twemoji } from 'react-emoji-render';
 | |
| 
 | |
| interface Props {
 | |
|   text: string;
 | |
|   /** A class name to be added to the generated emoji images */
 | |
|   sizeClass?: SizeClassType;
 | |
|   /** Allows you to customize now non-newlines are rendered. Simplest is just a <span>. */
 | |
|   renderNonEmoji?: RenderTextCallbackType;
 | |
|   isGroup?: boolean;
 | |
|   convoId: string;
 | |
| }
 | |
| 
 | |
| export class Emojify extends React.Component<Props> {
 | |
|   public static defaultProps: Partial<Props> = {
 | |
|     renderNonEmoji: ({ text }) => text || '',
 | |
|     isGroup: false,
 | |
|   };
 | |
| 
 | |
|   public render() {
 | |
|     const { text, sizeClass, renderNonEmoji, isGroup, convoId } = this.props;
 | |
|     const results: Array<any> = [];
 | |
|     const regex = getRegex();
 | |
| 
 | |
|     // We have to do this, because renderNonEmoji is not required in our Props object,
 | |
|     //  but it is always provided via defaultProps.
 | |
|     if (!renderNonEmoji) {
 | |
|       return null;
 | |
|     }
 | |
| 
 | |
|     let match = regex.exec(text);
 | |
|     let last = 0;
 | |
|     let count = 1;
 | |
| 
 | |
|     if (!match) {
 | |
|       return renderNonEmoji({ text, key: 0, isGroup, convoId });
 | |
|     }
 | |
| 
 | |
|     while (match) {
 | |
|       if (last < match.index) {
 | |
|         const textWithNoEmoji = text.slice(last, match.index);
 | |
|         results.push(
 | |
|           renderNonEmoji({
 | |
|             text: textWithNoEmoji,
 | |
|             key: count++,
 | |
|             isGroup,
 | |
|             convoId,
 | |
|           })
 | |
|         );
 | |
|       }
 | |
| 
 | |
|       let size = 1.0;
 | |
|       switch (sizeClass) {
 | |
|         case 'jumbo':
 | |
|           size = 2.0;
 | |
|           break;
 | |
|         case 'large':
 | |
|           size = 1.8;
 | |
|           break;
 | |
|         case 'medium':
 | |
|           size = 1.5;
 | |
|           break;
 | |
|         case 'small':
 | |
|           size = 1.1;
 | |
|           break;
 | |
|         default:
 | |
|       }
 | |
| 
 | |
|       const style = { fontSize: `${size}em` };
 | |
| 
 | |
|       const emojiText = match[0] ?? match[1];
 | |
| 
 | |
|       results.push(
 | |
|         <span style={style} key={count++}>
 | |
|           <Twemoji
 | |
|             key={count}
 | |
|             text={emojiText}
 | |
|             options={
 | |
|               {
 | |
|                 baseUrl: 'images/twemoji/',
 | |
|                 protocol: '',
 | |
|                 ext: 'png',
 | |
|               } as any
 | |
|             }
 | |
|           />
 | |
|         </span>
 | |
|       );
 | |
| 
 | |
|       last = regex.lastIndex;
 | |
|       match = regex.exec(text);
 | |
|     }
 | |
| 
 | |
|     if (last < text.length) {
 | |
|       results.push(
 | |
|         renderNonEmoji({
 | |
|           text: text.slice(last),
 | |
|           key: count++,
 | |
|           isGroup,
 | |
|           convoId,
 | |
|         })
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     return results;
 | |
|   }
 | |
| }
 |