Add tooltips to emoji in messages (#7592)

pull/21833/head
Robin 2022-01-21 05:10:57 -05:00 committed by GitHub
parent 35ebca2966
commit af8b3c2714
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 16 additions and 18 deletions

View File

@ -391,10 +391,9 @@ $left-gutter: 64px;
position: absolute; position: absolute;
} }
/* HACK to override line-height which is already marked important elsewhere */ .mx_EventTile_bigEmoji .mx_EventTile_Emoji {
.mx_EventTile_bigEmoji.mx_EventTile_bigEmoji {
font-size: 48px !important; font-size: 48px !important;
line-height: 57px !important; line-height: 57px;
} }
.mx_EventTile_content .mx_EventTile_edited { .mx_EventTile_content .mx_EventTile_edited {

View File

@ -22,6 +22,7 @@ import sanitizeHtml from 'sanitize-html';
import cheerio from 'cheerio'; import cheerio from 'cheerio';
import classNames from 'classnames'; import classNames from 'classnames';
import EMOJIBASE_REGEX from 'emojibase-regex'; import EMOJIBASE_REGEX from 'emojibase-regex';
import { split } from 'lodash';
import katex from 'katex'; import katex from 'katex';
import { AllHtmlEntities } from 'html-entities'; import { AllHtmlEntities } from 'html-entities';
import { IContent } from 'matrix-js-sdk/src/models/event'; import { IContent } from 'matrix-js-sdk/src/models/event';
@ -402,6 +403,11 @@ export interface IOptsReturnString extends IOpts {
returnString: true; returnString: true;
} }
const emojiToHtmlSpan = (emoji: string) =>
`<span class='mx_EventTile_Emoji' title='${unicodeToShortcode(emoji)}'>${emoji}</span>`;
const emojiToJsxSpan = (emoji: string, key: number) =>
<span key={key} className='mx_EventTile_Emoji' title={unicodeToShortcode(emoji)}>{ emoji }</span>;
/** /**
* Wraps emojis in <span> to style them separately from the rest of message. Consecutive emojis (and modifiers) are wrapped * Wraps emojis in <span> to style them separately from the rest of message. Consecutive emojis (and modifiers) are wrapped
* in the same <span>. * in the same <span>.
@ -411,34 +417,27 @@ export interface IOptsReturnString extends IOpts {
* and plain text for everything else * and plain text for everything else
*/ */
function formatEmojis(message: string, isHtmlMessage: boolean): (JSX.Element | string)[] { function formatEmojis(message: string, isHtmlMessage: boolean): (JSX.Element | string)[] {
const emojiToSpan = isHtmlMessage ? (emoji: string) => `<span class='mx_EventTile_Emoji'>${emoji}</span>` : const emojiToSpan = isHtmlMessage ? emojiToHtmlSpan : emojiToJsxSpan;
(emoji: string, key: number) => <span key={key} className='mx_EventTile_Emoji'>{ emoji }</span>;
const result: (JSX.Element | string)[] = []; const result: (JSX.Element | string)[] = [];
let text = ''; let text = '';
let emojis = '';
let key = 0; let key = 0;
for (const char of message) {
if (mightContainEmoji(char) || ZWJ_REGEX.test(char) || char === '\ufe0f') { // We use lodash's grapheme splitter to avoid breaking apart compound emojis
for (const char of split(message, '')) {
if (mightContainEmoji(char)) {
if (text) { if (text) {
result.push(text); result.push(text);
text = ''; text = '';
} }
emojis += char; result.push(emojiToSpan(char, key));
} else {
if (emojis) {
result.push(emojiToSpan(emojis, key));
key++; key++;
emojis = ''; } else {
}
text += char; text += char;
} }
} }
if (text) { if (text) {
result.push(text); result.push(text);
} }
if (emojis) {
result.push(emojiToSpan(emojis, key));
}
return result; return result;
} }
@ -574,7 +573,7 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts
}); });
let emojiBodyElements: JSX.Element[]; let emojiBodyElements: JSX.Element[];
if (!isDisplayedWithHtml && bodyHasEmoji && !emojiBody) { if (!isDisplayedWithHtml && bodyHasEmoji) {
emojiBodyElements = formatEmojis(strippedBody, false) as JSX.Element[]; emojiBodyElements = formatEmojis(strippedBody, false) as JSX.Element[];
} }