Message / Emoji, Emoji Button: Fade-in animation (#1802)

This commit is contained in:
Alexander Zinchuk 2022-04-19 15:11:57 +02:00
parent d44d465520
commit f132faf7cd
6 changed files with 50 additions and 11 deletions

View File

@ -3,7 +3,9 @@ import EMOJI_REGEX, { removeVS16s } from '../../../lib/twemojiRegex';
import { RE_LINK_TEMPLATE, RE_MENTION_TEMPLATE } from '../../../config';
import { IS_EMOJI_SUPPORTED } from '../../../util/environment';
import { fixNonStandardEmoji, nativeToUnified } from '../../../util/emoji';
import {
fixNonStandardEmoji, handleEmojiLoad, LOADED_EMOJIS, nativeToUnified,
} from '../../../util/emoji';
import buildClassName from '../../../util/buildClassName';
import { compact } from '../../../util/iteratees';
@ -14,7 +16,7 @@ type TextPart = string | Element;
export type TextFilter = (
'escape_html' | 'hq_emoji' | 'emoji' | 'emoji_html' | 'br' | 'br_html' | 'highlight' | 'links' |
'simple_markdown' | 'simple_markdown_html'
);
);
const RE_LETTER_OR_DIGIT = /^[\d\wа-яё]$/i;
const SIMPLE_MARKDOWN_REGEX = /(\*\*|__).+?\1/g;
@ -102,16 +104,22 @@ function replaceEmojis(textParts: TextPart[], size: 'big' | 'small', type: 'jsx'
return emojis.reduce((emojiResult: TextPart[], emoji, i) => {
const code = nativeToUnified(removeVS16s(emoji));
if (!code) return emojiResult;
const src = `./img-apple-${size === 'big' ? '160' : '64'}/${code}.png`;
const className = buildClassName(
'emoji',
size === 'small' && 'emoji-small',
);
if (type === 'jsx') {
const isLoaded = LOADED_EMOJIS.has(src);
emojiResult.push(
<img
className={className}
src={`./img-apple-${size === 'big' ? '160' : '64'}/${code}.png`}
src={src}
className={`${className}${!isLoaded ? ' opacity-transition slow shown' : ''}`}
alt={emoji}
data-path={src}
onLoad={!isLoaded ? handleEmojiLoad : undefined}
/>,
);
}

View File

@ -9,6 +9,7 @@
cursor: pointer;
font-size: 1.75rem;
line-height: 2.5rem;
background-color: transparent;
transition: background-color 0.15s ease;

View File

@ -1,6 +1,10 @@
import React, { FC, memo, useCallback } from '../../../lib/teact/teact';
import React, {
FC, memo, useCallback,
} from '../../../lib/teact/teact';
import { IS_EMOJI_SUPPORTED } from '../../../util/environment';
import { handleEmojiLoad, LOADED_EMOJIS } from '../../../util/emoji';
import buildClassName from '../../../util/buildClassName';
import './EmojiButton.scss';
@ -18,15 +22,30 @@ const EmojiButton: FC<OwnProps> = ({ emoji, focus, onClick }) => {
onClick(emoji.native, emoji.id);
}, [emoji, onClick]);
const className = buildClassName(
'EmojiButton',
focus && 'focus',
);
const src = `./img-apple-64/${emoji.image}.png`;
const isLoaded = LOADED_EMOJIS.has(src);
return (
<div
className={`EmojiButton ${focus ? 'focus' : ''}`}
className={className}
onMouseDown={handleClick}
title={`:${emoji.names[0]}:`}
>
{IS_EMOJI_SUPPORTED
? emoji.native
: <img src={`./img-apple-64/${emoji.image}.png`} alt={emoji.native} loading="lazy" />}
{IS_EMOJI_SUPPORTED ? emoji.native : (
<img
src={src}
className={!isLoaded ? 'opacity-transition shown' : undefined}
alt={emoji.native}
loading="lazy"
data-path={src}
onLoad={!isLoaded ? handleEmojiLoad : undefined}
/>
)}
</div>
);
};

View File

@ -219,7 +219,7 @@ const EmojiPicker: FC<OwnProps & StateProps> = ({
async function ensureEmojiData() {
if (!emojiDataPromise) {
emojiDataPromise = import('emoji-data-ios/emoji-data.json') as unknown as Promise<EmojiModule>;
emojiDataPromise = import('emoji-data-ios/emoji-data.json');
emojiRawData = (await emojiDataPromise).default;
emojiData = uncompressEmoji(emojiRawData);

View File

@ -64,6 +64,7 @@ body.cursor-ew-resize {
#root {
height: 100%;
@media (max-width: 600px) {
height: calc(var(--vh, 1vh) * 100);
}
@ -265,10 +266,12 @@ div[role="button"] {
transform: scale(0.5);
opacity: 0.8;
}
50% {
transform: scale(1.1);
opacity: 1;
}
100% {
transform: scale(1);
}
@ -279,6 +282,7 @@ div[role="button"] {
transform: scale(1);
opacity: 0.4;
}
to {
transform: scale(0.5);
opacity: 0;

View File

@ -28,6 +28,13 @@ function unifiedToNative(unified: string) {
return String.fromCodePoint(...codePoints);
}
export const LOADED_EMOJIS = new Set<string>();
export function handleEmojiLoad(event: React.SyntheticEvent<HTMLImageElement>) {
event.currentTarget.classList.add('open');
LOADED_EMOJIS.add(event.currentTarget.dataset.path!);
}
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;
@ -51,7 +58,7 @@ export function nativeToUnified(emoji: string) {
if (emoji.charCodeAt(i + 1) >= 0xdc00 && emoji.charCodeAt(i + 1) <= 0xdfff) {
pairs.push(
(emoji.charCodeAt(i) - 0xd800) * 0x400
+ (emoji.charCodeAt(i + 1) - 0xdc00) + 0x10000,
+ (emoji.charCodeAt(i + 1) - 0xdc00) + 0x10000,
);
}
} else if (emoji.charCodeAt(i) < 0xd800 || emoji.charCodeAt(i) > 0xdfff) {