Add tooltips to emoji in messages (#7592)
parent
35ebca2966
commit
af8b3c2714
|
@ -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 {
|
||||||
|
|
|
@ -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));
|
||||||
|
key++;
|
||||||
} else {
|
} else {
|
||||||
if (emojis) {
|
|
||||||
result.push(emojiToSpan(emojis, key));
|
|
||||||
key++;
|
|
||||||
emojis = '';
|
|
||||||
}
|
|
||||||
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[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue