Support Emoji 15.1 & fixes (#4343)
This commit is contained in:
parent
7bf1b2b878
commit
6054151969
8
package-lock.json
generated
8
package-lock.json
generated
@ -14,7 +14,7 @@
|
||||
"async-mutex": "^0.4.0",
|
||||
"big-integer": "github:painor/BigInteger.js",
|
||||
"croppie": "^2.6.5",
|
||||
"emoji-data-ios": "git+https://github.com/korenskoy/emoji-data-ios#2886b318eae174527c4bc9fcd321940ef3a85527",
|
||||
"emoji-data-ios": "git+https://github.com/korenskoy/emoji-data-ios#de1a69aff2c8eb7548df4e6bcf50c7d2304792fc",
|
||||
"idb-keyval": "^6.2.1",
|
||||
"lowlight": "^2.9.0",
|
||||
"mp4box": "^0.5.2",
|
||||
@ -11124,9 +11124,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/emoji-data-ios": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "git+ssh://git@github.com/korenskoy/emoji-data-ios.git#2886b318eae174527c4bc9fcd321940ef3a85527",
|
||||
"integrity": "sha512-kqoSV9kSLVjl5+tCpFwxXKYNnjgASPnRMwY4aLilYGNwX/R9mBYzSiHe/YbPurggz5AisLz/PeJuJeLe7XG7Fg==",
|
||||
"version": "0.5.1",
|
||||
"resolved": "git+ssh://git@github.com/korenskoy/emoji-data-ios.git#de1a69aff2c8eb7548df4e6bcf50c7d2304792fc",
|
||||
"integrity": "sha512-aNh0bvCsHcRuLpTgOoJ2DQBYBHjuhjrpwrZtKKQ1ZyGVg0ab2ys26bjmI+zgWYcgg48hAhO2JQPZNRaR5yOK5w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
|
||||
@ -139,7 +139,7 @@
|
||||
"async-mutex": "^0.4.0",
|
||||
"big-integer": "github:painor/BigInteger.js",
|
||||
"croppie": "^2.6.5",
|
||||
"emoji-data-ios": "git+https://github.com/korenskoy/emoji-data-ios#2886b318eae174527c4bc9fcd321940ef3a85527",
|
||||
"emoji-data-ios": "git+https://github.com/korenskoy/emoji-data-ios#de1a69aff2c8eb7548df4e6bcf50c7d2304792fc",
|
||||
"idb-keyval": "^6.2.1",
|
||||
"lowlight": "^2.9.0",
|
||||
"mp4box": "^0.5.2",
|
||||
|
||||
@ -8,7 +8,7 @@ import type { ApiCountryCode } from '../../api/types';
|
||||
|
||||
import { ANIMATION_END_DELAY } from '../../config';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import { isoToEmoji } from '../../util/emoji';
|
||||
import { isoToEmoji } from '../../util/emoji/emoji';
|
||||
import { prepareSearchWordsForNeedle } from '../../util/searchWords';
|
||||
import renderText from '../common/helpers/renderText';
|
||||
|
||||
|
||||
@ -86,9 +86,9 @@ import {
|
||||
} from '../../global/selectors';
|
||||
import { selectCurrentLimit } from '../../global/selectors/limits';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import { processMessageInputForCustomEmoji } from '../../util/customEmojiManager';
|
||||
import { formatMediaDuration, formatVoiceRecordDuration } from '../../util/dateFormat';
|
||||
import deleteLastCharacterOutsideSelection from '../../util/deleteLastCharacterOutsideSelection';
|
||||
import { processMessageInputForCustomEmoji } from '../../util/emoji/customEmojiManager';
|
||||
import focusEditableElement from '../../util/focusEditableElement';
|
||||
import { MEMO_EMPTY_ARRAY } from '../../util/memo';
|
||||
import parseHtmlAsFormattedText from '../../util/parseHtmlAsFormattedText';
|
||||
|
||||
@ -10,11 +10,11 @@ import EMOJI_REGEX from '../../../lib/twemojiRegex';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import { isDeepLink } from '../../../util/deepLinkParser';
|
||||
import {
|
||||
fixNonStandardEmoji,
|
||||
handleEmojiLoad,
|
||||
LOADED_EMOJIS,
|
||||
nativeToUnifiedExtendedWithCache,
|
||||
} from '../../../util/emoji';
|
||||
} from '../../../util/emoji/emoji';
|
||||
import fixNonStandardEmoji from '../../../util/emoji/fixNonStandardEmoji';
|
||||
import { compact } from '../../../util/iteratees';
|
||||
import { IS_EMOJI_SUPPORTED } from '../../../util/windowEnvironment';
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ import type { ApiSticker } from '../../../api/types';
|
||||
import type { GlobalState } from '../../../global/types';
|
||||
|
||||
import { selectCanPlayAnimatedEmojis } from '../../../global/selectors';
|
||||
import { addCustomEmojiCallback, removeCustomEmojiCallback } from '../../../util/customEmojiManager';
|
||||
import { addCustomEmojiCallback, removeCustomEmojiCallback } from '../../../util/emoji/customEmojiManager';
|
||||
|
||||
import useEnsureCustomEmoji from '../../../hooks/useEnsureCustomEmoji';
|
||||
import useLastCallback from '../../../hooks/useLastCallback';
|
||||
|
||||
@ -3,7 +3,7 @@ import React, { memo } from '../../../lib/teact/teact';
|
||||
|
||||
import { BASE_URL, IS_PACKAGED_ELECTRON } from '../../../config';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import { handleEmojiLoad, LOADED_EMOJIS } from '../../../util/emoji';
|
||||
import { handleEmojiLoad, LOADED_EMOJIS } from '../../../util/emoji/emoji';
|
||||
import { IS_EMOJI_SUPPORTED } from '../../../util/windowEnvironment';
|
||||
|
||||
import useLastCallback from '../../../hooks/useLastCallback';
|
||||
|
||||
@ -10,13 +10,13 @@ import type {
|
||||
EmojiData,
|
||||
EmojiModule,
|
||||
EmojiRawData,
|
||||
} from '../../../util/emoji';
|
||||
} from '../../../util/emoji/emoji';
|
||||
|
||||
import { MENU_TRANSITION_DURATION, RECENT_SYMBOL_SET_ID } from '../../../config';
|
||||
import animateHorizontalScroll from '../../../util/animateHorizontalScroll';
|
||||
import animateScroll from '../../../util/animateScroll';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import { uncompressEmoji } from '../../../util/emoji';
|
||||
import { uncompressEmoji } from '../../../util/emoji/emoji';
|
||||
import { pick } from '../../../util/iteratees';
|
||||
import { MEMO_EMPTY_ARRAY } from '../../../util/memo';
|
||||
import { IS_TOUCH_ENV } from '../../../util/windowEnvironment';
|
||||
|
||||
@ -16,8 +16,8 @@ import { selectCanPlayAnimatedEmojis, selectDraft, selectIsInSelectMode } from '
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import captureKeyboardListeners from '../../../util/captureKeyboardListeners';
|
||||
import { getIsDirectTextInputDisabled } from '../../../util/directInputManager';
|
||||
import parseEmojiOnlyString from '../../../util/emoji/parseEmojiOnlyString';
|
||||
import focusEditableElement from '../../../util/focusEditableElement';
|
||||
import parseEmojiOnlyString from '../../../util/parseEmojiOnlyString';
|
||||
import { debounce } from '../../../util/schedulers';
|
||||
import {
|
||||
IS_ANDROID, IS_EMOJI_SUPPORTED, IS_IOS, IS_TOUCH_ENV,
|
||||
|
||||
@ -5,7 +5,7 @@ import { ApiMessageEntityTypes } from '../../../../api/types';
|
||||
|
||||
import { EMOJI_SIZES } from '../../../../config';
|
||||
import buildClassName from '../../../../util/buildClassName';
|
||||
import { getInputCustomEmojiParams } from '../../../../util/customEmojiManager';
|
||||
import { getInputCustomEmojiParams } from '../../../../util/emoji/customEmojiManager';
|
||||
import { REM } from '../../../common/helpers/mediaDimensions';
|
||||
|
||||
export const INPUT_CUSTOM_EMOJI_SELECTOR = 'img[data-document-id]';
|
||||
|
||||
@ -2,13 +2,13 @@ import { useEffect, useState } from '../../../../lib/teact/teact';
|
||||
import { getGlobal } from '../../../../global';
|
||||
|
||||
import type { ApiSticker } from '../../../../api/types';
|
||||
import type { EmojiData, EmojiModule, EmojiRawData } from '../../../../util/emoji';
|
||||
import type { EmojiData, EmojiModule, EmojiRawData } from '../../../../util/emoji/emoji';
|
||||
import type { Signal } from '../../../../util/signals';
|
||||
|
||||
import { EDITABLE_INPUT_CSS_SELECTOR, EDITABLE_INPUT_ID } from '../../../../config';
|
||||
import { requestNextMutation } from '../../../../lib/fasterdom/fasterdom';
|
||||
import { selectCustomEmojiForEmojis } from '../../../../global/selectors';
|
||||
import { uncompressEmoji } from '../../../../util/emoji';
|
||||
import { uncompressEmoji } from '../../../../util/emoji/emoji';
|
||||
import focusEditableElement from '../../../../util/focusEditableElement';
|
||||
import {
|
||||
buildCollectionByKey, mapValues, pickTruthy, unique, uniqueByField,
|
||||
|
||||
@ -13,7 +13,7 @@ import AbsoluteVideo from '../../../../util/AbsoluteVideo';
|
||||
import {
|
||||
addCustomEmojiInputRenderCallback,
|
||||
getCustomEmojiMediaDataForInput,
|
||||
} from '../../../../util/customEmojiManager';
|
||||
} from '../../../../util/emoji/customEmojiManager';
|
||||
import { round } from '../../../../util/math';
|
||||
import { hexToRgb } from '../../../../util/switchTheme';
|
||||
import { REM } from '../../../common/helpers/mediaDimensions';
|
||||
|
||||
@ -6,7 +6,7 @@ import type { Signal } from '../../../../util/signals';
|
||||
|
||||
import { EMOJI_IMG_REGEX } from '../../../../config';
|
||||
import twemojiRegex from '../../../../lib/twemojiRegex';
|
||||
import parseEmojiOnlyString from '../../../../util/parseEmojiOnlyString';
|
||||
import parseEmojiOnlyString from '../../../../util/emoji/parseEmojiOnlyString';
|
||||
import { IS_EMOJI_SUPPORTED } from '../../../../util/windowEnvironment';
|
||||
import { prepareForRegExp } from '../helpers/prepareForRegExp';
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ import {
|
||||
} from '../../../global/selectors';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import { formatDateAtTime, formatDateTimeToString } from '../../../util/dateFormat';
|
||||
import { isoToEmoji } from '../../../util/emoji';
|
||||
import { isoToEmoji } from '../../../util/emoji/emoji';
|
||||
import { getServerTime } from '../../../util/serverTime';
|
||||
import { callApi } from '../../../api/gramjs';
|
||||
import { LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets';
|
||||
|
||||
@ -814,7 +814,7 @@
|
||||
--emoji-only-size: #{$size};
|
||||
|
||||
.text-content {
|
||||
width: #{calc($size * $i)};
|
||||
width: #{calc(($size + 1px) * $i)};
|
||||
font-size: calc($size * 0.9);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import type { MediaContent } from '../../api/types';
|
||||
import { ApiMessageEntityTypes } from '../../api/types';
|
||||
|
||||
import parseEmojiOnlyString from '../../util/parseEmojiOnlyString';
|
||||
import parseEmojiOnlyString from '../../util/emoji/parseEmojiOnlyString';
|
||||
|
||||
export function getEmojiOnlyCountForMessage(content: MediaContent, groupedId?: string): number | undefined {
|
||||
if (!content.text) return undefined;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { getActions, getGlobal } from '../global';
|
||||
|
||||
import { addCustomEmojiInputRenderCallback } from '../util/customEmojiManager';
|
||||
import { addCustomEmojiInputRenderCallback } from '../util/emoji/customEmojiManager';
|
||||
import { throttle } from '../util/schedulers';
|
||||
|
||||
let LOAD_QUEUE = new Set<string>();
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -1,21 +1,21 @@
|
||||
import { addCallback } from '../lib/teact/teactn';
|
||||
import { getGlobal } from '../global';
|
||||
import { addCallback } from '../../lib/teact/teactn';
|
||||
import { getGlobal } from '../../global';
|
||||
|
||||
import type { ApiSticker } from '../api/types';
|
||||
import type { GlobalState } from '../global/types';
|
||||
import { ApiMediaFormat } from '../api/types';
|
||||
import type { ApiSticker } from '../../api/types';
|
||||
import type { GlobalState } from '../../global/types';
|
||||
import { ApiMediaFormat } from '../../api/types';
|
||||
|
||||
import { requestMutation } from '../lib/fasterdom/fasterdom';
|
||||
import { getStickerPreviewHash } from '../global/helpers';
|
||||
import { selectCanPlayAnimatedEmojis } from '../global/selectors';
|
||||
import { createCallbackManager } from './callbacks';
|
||||
import generateUniqueId from './generateUniqueId';
|
||||
import * as mediaLoader from './mediaLoader';
|
||||
import { throttle } from './schedulers';
|
||||
import { IS_WEBM_SUPPORTED } from './windowEnvironment';
|
||||
import { requestMutation } from '../../lib/fasterdom/fasterdom';
|
||||
import { getStickerPreviewHash } from '../../global/helpers';
|
||||
import { selectCanPlayAnimatedEmojis } from '../../global/selectors';
|
||||
import { createCallbackManager } from '../callbacks';
|
||||
import generateUniqueId from '../generateUniqueId';
|
||||
import * as mediaLoader from '../mediaLoader';
|
||||
import { throttle } from '../schedulers';
|
||||
import { IS_WEBM_SUPPORTED } from '../windowEnvironment';
|
||||
|
||||
import blankSrc from '../assets/blank.png';
|
||||
import placeholderSrc from '../assets/square.svg';
|
||||
import blankSrc from '../../assets/blank.png';
|
||||
import placeholderSrc from '../../assets/square.svg';
|
||||
|
||||
type CustomEmojiLoadCallback = (customEmojis: GlobalState['customEmojis']) => void;
|
||||
type CustomEmojiInputRenderCallback = (emojiId: string) => void;
|
||||
@ -1,6 +1,8 @@
|
||||
import { requestMutation } from '../lib/fasterdom/fasterdom';
|
||||
import EMOJI_REGEX, { removeVS16s } from '../lib/twemojiRegex';
|
||||
import withCache from './withCache';
|
||||
import { addExtraClass } from '../../lib/teact/teact-dom';
|
||||
|
||||
import { requestMutation } from '../../lib/fasterdom/fasterdom';
|
||||
import { removeVS16s } from '../../lib/twemojiRegex';
|
||||
import withCache from '../withCache';
|
||||
|
||||
// Due to the fact that emoji from Apple do not contain some characters, it is necessary to remove them from emoji-data
|
||||
// https://github.com/iamcal/emoji-data/issues/136
|
||||
@ -16,13 +18,6 @@ export type EmojiData = {
|
||||
emojis: Record<string, Emoji>;
|
||||
};
|
||||
|
||||
// Non-standard variations of emojis, used on some devices
|
||||
const EMOJI_EXCEPTIONS: [string | RegExp, string][] = [
|
||||
[/\u{1f3f3}\u200d\u{1f308}/gu, '\u{1f3f3}\ufe0f\u200d\u{1f308}'], // 🏳🌈
|
||||
[/\u{1f3f3}\u200d\u26a7\ufe0f/gu, '\u{1f3f3}\ufe0f\u200d\u26a7\ufe0f'], // 🏳️⚧️
|
||||
[/\u{1f937}\u200d\u2642[^\ufe0f]/gu, '\u{1f937}\u200d\u2642\ufe0f'], // 🤷♂️
|
||||
];
|
||||
|
||||
function unifiedToNative(unified: string) {
|
||||
const unicodes = unified.split('-');
|
||||
const codePoints = unicodes.map((i) => parseInt(i, 16));
|
||||
@ -38,21 +33,10 @@ export function handleEmojiLoad(event: React.SyntheticEvent<HTMLImageElement>) {
|
||||
LOADED_EMOJIS.add(event.currentTarget.dataset.path!);
|
||||
|
||||
requestMutation(() => {
|
||||
emoji.classList.add('open');
|
||||
addExtraClass(emoji, 'open');
|
||||
});
|
||||
}
|
||||
|
||||
export function fixNonStandardEmoji(text: string) {
|
||||
// Non-standard sequences typically parsed as separate emojis, so no need to fix text without any
|
||||
if (!text.match(EMOJI_REGEX)) return text;
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const [regex, replacement] of EMOJI_EXCEPTIONS) {
|
||||
text = text.replace(regex, replacement);
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
export function nativeToUnified(emoji: string) {
|
||||
let code;
|
||||
|
||||
20
src/util/emoji/fixNonStandardEmoji.ts
Normal file
20
src/util/emoji/fixNonStandardEmoji.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import EMOJI_REGEX from '../../lib/twemojiRegex';
|
||||
|
||||
// Non-standard variations of emojis, used on some devices
|
||||
const EMOJI_EXCEPTIONS: [string | RegExp, string][] = [
|
||||
[/\u{1f3f3}\u200d\u{1f308}/gu, '\u{1f3f3}\ufe0f\u200d\u{1f308}'], // 🏳🌈
|
||||
[/\u{1f3f3}\u200d\u26a7\ufe0f?/gu, '\u{1f3f3}\ufe0f\u200d\u26a7\ufe0f'], // 🏳️⚧️
|
||||
[/\u26d3\u200d\u{1f4a5}/gu, '\u26d3\ufe0f\u200d\u{1f4a5}'], // ⛓💥
|
||||
[/\u200d([\u2640\u2642])(?!\ufe0f)/gu, '\u200d$1\ufe0f'], // Gender variation without 0xFE0F
|
||||
];
|
||||
|
||||
export default function fixNonStandardEmoji(text: string) {
|
||||
// Non-standard sequences typically parsed as separate emojis, so no need to fix text without any
|
||||
if (!text.match(EMOJI_REGEX)) return text;
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const [regex, replacement] of EMOJI_EXCEPTIONS) {
|
||||
text = text.replace(regex, replacement);
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
@ -1,11 +1,13 @@
|
||||
import twemojiRegex from '../lib/twemojiRegex';
|
||||
import twemojiRegex from '../../lib/twemojiRegex';
|
||||
import fixNonStandardEmoji from './fixNonStandardEmoji';
|
||||
|
||||
const DETECT_UP_TO = 100;
|
||||
const MAX_LENGTH = DETECT_UP_TO * 8; // Maximum 8 per one emoji.
|
||||
const RE_EMOJI_ONLY = new RegExp(`^(?:${twemojiRegex.source})+$`, '');
|
||||
|
||||
const parseEmojiOnlyString = (text: string): number | false => {
|
||||
const lines = text.split('\n');
|
||||
const standardizedText = fixNonStandardEmoji(text);
|
||||
const lines = standardizedText.split('\n');
|
||||
const textWithoutNewlines = lines.join('');
|
||||
if (textWithoutNewlines.length > MAX_LENGTH) {
|
||||
return false;
|
||||
@ -1,7 +1,7 @@
|
||||
import type { LangFn } from '../hooks/useLang';
|
||||
|
||||
import EMOJI_REGEX from '../lib/twemojiRegex';
|
||||
import { fixNonStandardEmoji } from './emoji';
|
||||
import fixNonStandardEmoji from './emoji/fixNonStandardEmoji';
|
||||
import withCache from './withCache';
|
||||
|
||||
export function formatInteger(value: number) {
|
||||
|
||||
@ -125,7 +125,7 @@ function isLastEmojiVersionSupported() {
|
||||
inlineEl.classList.add('emoji-test-element');
|
||||
document.body.appendChild(inlineEl);
|
||||
|
||||
inlineEl.innerText = '🫸🏻'; // Emoji from 15.0 version
|
||||
inlineEl.innerText = '🐦🔥'; // Emoji from 15.1 version
|
||||
const newEmojiWidth = inlineEl.offsetWidth;
|
||||
inlineEl.innerText = '❤️'; // Emoji from 1.0 version
|
||||
const legacyEmojiWidth = inlineEl.offsetWidth;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user