From af8b3c2714520bd4f584a58325a6f41cf9dc3bbc Mon Sep 17 00:00:00 2001 From: Robin Date: Fri, 21 Jan 2022 05:10:57 -0500 Subject: [PATCH] Add tooltips to emoji in messages (#7592) --- res/css/views/rooms/_EventTile.scss | 5 ++--- src/HtmlUtils.tsx | 29 ++++++++++++++--------------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index b077dc8bbc..51e7f16927 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -391,10 +391,9 @@ $left-gutter: 64px; position: absolute; } -/* HACK to override line-height which is already marked important elsewhere */ -.mx_EventTile_bigEmoji.mx_EventTile_bigEmoji { +.mx_EventTile_bigEmoji .mx_EventTile_Emoji { font-size: 48px !important; - line-height: 57px !important; + line-height: 57px; } .mx_EventTile_content .mx_EventTile_edited { diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index e50d868ef9..ca391fc300 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -22,6 +22,7 @@ import sanitizeHtml from 'sanitize-html'; import cheerio from 'cheerio'; import classNames from 'classnames'; import EMOJIBASE_REGEX from 'emojibase-regex'; +import { split } from 'lodash'; import katex from 'katex'; import { AllHtmlEntities } from 'html-entities'; import { IContent } from 'matrix-js-sdk/src/models/event'; @@ -402,6 +403,11 @@ export interface IOptsReturnString extends IOpts { returnString: true; } +const emojiToHtmlSpan = (emoji: string) => + `${emoji}`; +const emojiToJsxSpan = (emoji: string, key: number) => + { emoji }; + /** * Wraps emojis in to style them separately from the rest of message. Consecutive emojis (and modifiers) are wrapped * in the same . @@ -411,34 +417,27 @@ export interface IOptsReturnString extends IOpts { * and plain text for everything else */ function formatEmojis(message: string, isHtmlMessage: boolean): (JSX.Element | string)[] { - const emojiToSpan = isHtmlMessage ? (emoji: string) => `${emoji}` : - (emoji: string, key: number) => { emoji }; + const emojiToSpan = isHtmlMessage ? emojiToHtmlSpan : emojiToJsxSpan; const result: (JSX.Element | string)[] = []; let text = ''; - let emojis = ''; 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) { result.push(text); text = ''; } - emojis += char; + result.push(emojiToSpan(char, key)); + key++; } else { - if (emojis) { - result.push(emojiToSpan(emojis, key)); - key++; - emojis = ''; - } text += char; } } if (text) { result.push(text); } - if (emojis) { - result.push(emojiToSpan(emojis, key)); - } return result; } @@ -574,7 +573,7 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts }); let emojiBodyElements: JSX.Element[]; - if (!isDisplayedWithHtml && bodyHasEmoji && !emojiBody) { + if (!isDisplayedWithHtml && bodyHasEmoji) { emojiBodyElements = formatEmojis(strippedBody, false) as JSX.Element[]; }