Composer: Support 👍 emoji format (#1264)

This commit is contained in:
Alexander Zinchuk 2021-07-14 14:48:34 +03:00
parent 1c6f3fe06a
commit 791f6a30d5
4 changed files with 27 additions and 32 deletions

View File

@ -3,7 +3,6 @@ import React, {
} from '../../../lib/teact/teact';
import { ApiAttachment, ApiChatMember, ApiUser } from '../../../api/types';
import { LangCode } from '../../../types';
import { CONTENT_TYPES_FOR_QUICK_UPLOAD, EDITABLE_INPUT_MODAL_ID } from '../../../config';
import { getFileExtension } from '../../common/helpers/documentInfo';
@ -32,10 +31,8 @@ export type OwnProps = {
groupChatMembers?: ApiChatMember[];
usersById?: Record<number, ApiUser>;
recentEmojis: string[];
language: LangCode;
emojiKeywords?: Record<string, string[]>;
addRecentEmoji: AnyToVoidFunction;
loadEmojiKeywords: AnyToVoidFunction;
onCaptionUpdate: (html: string) => void;
onSend: () => void;
onFileAppend: (files: File[], isQuick: boolean) => void;
@ -52,11 +49,9 @@ const AttachmentModal: FC<OwnProps> = ({
currentUserId,
usersById,
recentEmojis,
language,
emojiKeywords,
onCaptionUpdate,
addRecentEmoji,
loadEmojiKeywords,
onSend,
onFileAppend,
onClear,
@ -237,10 +232,8 @@ const AttachmentModal: FC<OwnProps> = ({
isOpen={isEmojiTooltipOpen}
emojis={filteredEmojis}
onClose={closeEmojiTooltip}
language={language}
onEmojiSelect={insertEmoji}
addRecentEmoji={addRecentEmoji}
loadEmojiKeywords={loadEmojiKeywords}
/>
<MessageInput
id="caption-input-text"

View File

@ -232,6 +232,13 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
}
}, [isReady, chatId, loadScheduledHistory, lastSyncTime, threadId]);
useEffect(() => {
loadEmojiKeywords({ language: 'en' });
if (language !== 'en') {
loadEmojiKeywords({ language });
}
}, [loadEmojiKeywords, language]);
useLayoutEffect(() => {
if (!appendixRef.current) return;
@ -710,10 +717,8 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
usersById={usersById}
recentEmojis={recentEmojis}
onCaptionUpdate={setHtml}
language={language}
emojiKeywords={emojiKeywords}
addRecentEmoji={addRecentEmoji}
loadEmojiKeywords={loadEmojiKeywords}
onSend={shouldSchedule ? openCalendar : handleSend}
onFileAppend={handleAppendFiles}
onClear={handleClearAttachment}
@ -845,8 +850,6 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
onClose={closeEmojiTooltip}
onEmojiSelect={insertEmoji}
addRecentEmoji={addRecentEmoji}
loadEmojiKeywords={loadEmojiKeywords}
language={language}
/>
<AttachMenu
isOpen={isAttachMenuOpen}

View File

@ -2,8 +2,6 @@ import React, {
FC, memo, useCallback, useEffect, useRef, useState,
} from '../../../lib/teact/teact';
import { LangCode } from '../../../types';
import { IS_TOUCH_ENV } from '../../../util/environment';
import buildClassName from '../../../util/buildClassName';
import cycleRestrict from '../../../util/cycleRestrict';
@ -54,22 +52,18 @@ function setItemVisible(index: number, containerRef: Record<string, any>) {
export type OwnProps = {
isOpen: boolean;
language: LangCode;
onEmojiSelect: (text: string) => void;
onClose: NoneToVoidFunction;
addRecentEmoji: AnyToVoidFunction;
loadEmojiKeywords: AnyToVoidFunction;
emojis: Emoji[];
};
const EmojiTooltip: FC<OwnProps> = ({
isOpen,
language,
emojis,
onClose,
onEmojiSelect,
addRecentEmoji,
loadEmojiKeywords,
}) => {
// eslint-disable-next-line no-null/no-null
const containerRef = useRef<HTMLDivElement>(null);
@ -78,13 +72,6 @@ const EmojiTooltip: FC<OwnProps> = ({
const [selectedIndex, setSelectedIndex] = useState(NO_EMOJI_SELECTED_INDEX);
useEffect(() => {
loadEmojiKeywords({ language: 'en' });
if (language !== 'en') {
loadEmojiKeywords({ language });
}
}, [loadEmojiKeywords, language]);
useEffect(() => {
setSelectedIndex(0);
}, [emojis]);

View File

@ -22,10 +22,10 @@ const EMOJIS_LIMIT = 36;
const FILTER_MIN_LENGTH = 2;
try {
RE_NOT_EMOJI_SEARCH = new RegExp('[^-_:\\p{L}\\p{N}]+', 'iu');
RE_NOT_EMOJI_SEARCH = new RegExp('[^-+_:\\p{L}\\p{N}]+', 'iu');
} catch (e) {
// Support for older versions of firefox
RE_NOT_EMOJI_SEARCH = new RegExp('[^-_:\\d\\wа-яё]+', 'i');
RE_NOT_EMOJI_SEARCH = new RegExp('[^-+_:\\d\\wа-яё]+', 'i');
}
export default function useEmojiTooltip(
@ -45,6 +45,7 @@ export default function useEmojiTooltip(
const [byKeyword, setByKeyword] = useState<Record<string, Emoji[]>>({});
const [names, setNames] = useState<string[]>();
const [byName, setByName] = useState<Record<string, Emoji[]>>({});
const [shouldForceInsertEmoji, setShouldForceInsertEmoji] = useState(false);
const [filteredEmojis, setFilteredEmojis] = useState<Emoji[]>([]);
@ -124,9 +125,12 @@ export default function useEmojiTooltip(
return;
}
const filter = code.substr(1);
const forceSend = code.length > 2 && code.endsWith(':');
const filter = code.substr(1, forceSend ? code.length - 2 : undefined);
let matched: Emoji[] = [];
setShouldForceInsertEmoji(forceSend);
if (!filter) {
matched = recentEmojis;
} else if (filter.length >= FILTER_MIN_LENGTH) {
@ -141,18 +145,20 @@ export default function useEmojiTooltip(
}
if (matched.length) {
markIsOpen();
if (!forceSend) {
markIsOpen();
}
setFilteredEmojis(matched.slice(0, EMOJIS_LIMIT));
} else {
unmarkIsOpen();
}
}, [
byId, byKeyword, keywords, byName, names,
html, isAllowed, markIsOpen, recentEmojis, unmarkIsOpen,
byId, byKeyword, keywords, byName, names, html, isAllowed, markIsOpen,
recentEmojis, unmarkIsOpen, setShouldForceInsertEmoji,
]);
const insertEmoji = useCallback((textEmoji: string) => {
const atIndex = html.lastIndexOf(':');
const insertEmoji = useCallback((textEmoji: string, isForce?: boolean) => {
const atIndex = html.lastIndexOf(':', isForce ? -1 : undefined);
if (atIndex !== -1) {
onUpdateHtml(`${html.substr(0, atIndex)}${textEmoji}`);
const messageInput = document.getElementById(inputId)!;
@ -166,6 +172,12 @@ export default function useEmojiTooltip(
unmarkIsOpen();
}, [html, inputId, onUpdateHtml, unmarkIsOpen]);
useEffect(() => {
if (isOpen && shouldForceInsertEmoji && filteredEmojis.length) {
insertEmoji(filteredEmojis[0].native, true);
}
}, [filteredEmojis, insertEmoji, isOpen, shouldForceInsertEmoji]);
return {
isEmojiTooltipOpen: isOpen,
closeEmojiTooltip: unmarkIsOpen,