Composer: Support 👍 emoji format (#1264)
This commit is contained in:
parent
1c6f3fe06a
commit
791f6a30d5
@ -3,7 +3,6 @@ import React, {
|
|||||||
} from '../../../lib/teact/teact';
|
} from '../../../lib/teact/teact';
|
||||||
|
|
||||||
import { ApiAttachment, ApiChatMember, ApiUser } from '../../../api/types';
|
import { ApiAttachment, ApiChatMember, ApiUser } from '../../../api/types';
|
||||||
import { LangCode } from '../../../types';
|
|
||||||
|
|
||||||
import { CONTENT_TYPES_FOR_QUICK_UPLOAD, EDITABLE_INPUT_MODAL_ID } from '../../../config';
|
import { CONTENT_TYPES_FOR_QUICK_UPLOAD, EDITABLE_INPUT_MODAL_ID } from '../../../config';
|
||||||
import { getFileExtension } from '../../common/helpers/documentInfo';
|
import { getFileExtension } from '../../common/helpers/documentInfo';
|
||||||
@ -32,10 +31,8 @@ export type OwnProps = {
|
|||||||
groupChatMembers?: ApiChatMember[];
|
groupChatMembers?: ApiChatMember[];
|
||||||
usersById?: Record<number, ApiUser>;
|
usersById?: Record<number, ApiUser>;
|
||||||
recentEmojis: string[];
|
recentEmojis: string[];
|
||||||
language: LangCode;
|
|
||||||
emojiKeywords?: Record<string, string[]>;
|
emojiKeywords?: Record<string, string[]>;
|
||||||
addRecentEmoji: AnyToVoidFunction;
|
addRecentEmoji: AnyToVoidFunction;
|
||||||
loadEmojiKeywords: AnyToVoidFunction;
|
|
||||||
onCaptionUpdate: (html: string) => void;
|
onCaptionUpdate: (html: string) => void;
|
||||||
onSend: () => void;
|
onSend: () => void;
|
||||||
onFileAppend: (files: File[], isQuick: boolean) => void;
|
onFileAppend: (files: File[], isQuick: boolean) => void;
|
||||||
@ -52,11 +49,9 @@ const AttachmentModal: FC<OwnProps> = ({
|
|||||||
currentUserId,
|
currentUserId,
|
||||||
usersById,
|
usersById,
|
||||||
recentEmojis,
|
recentEmojis,
|
||||||
language,
|
|
||||||
emojiKeywords,
|
emojiKeywords,
|
||||||
onCaptionUpdate,
|
onCaptionUpdate,
|
||||||
addRecentEmoji,
|
addRecentEmoji,
|
||||||
loadEmojiKeywords,
|
|
||||||
onSend,
|
onSend,
|
||||||
onFileAppend,
|
onFileAppend,
|
||||||
onClear,
|
onClear,
|
||||||
@ -237,10 +232,8 @@ const AttachmentModal: FC<OwnProps> = ({
|
|||||||
isOpen={isEmojiTooltipOpen}
|
isOpen={isEmojiTooltipOpen}
|
||||||
emojis={filteredEmojis}
|
emojis={filteredEmojis}
|
||||||
onClose={closeEmojiTooltip}
|
onClose={closeEmojiTooltip}
|
||||||
language={language}
|
|
||||||
onEmojiSelect={insertEmoji}
|
onEmojiSelect={insertEmoji}
|
||||||
addRecentEmoji={addRecentEmoji}
|
addRecentEmoji={addRecentEmoji}
|
||||||
loadEmojiKeywords={loadEmojiKeywords}
|
|
||||||
/>
|
/>
|
||||||
<MessageInput
|
<MessageInput
|
||||||
id="caption-input-text"
|
id="caption-input-text"
|
||||||
|
|||||||
@ -232,6 +232,13 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
}
|
}
|
||||||
}, [isReady, chatId, loadScheduledHistory, lastSyncTime, threadId]);
|
}, [isReady, chatId, loadScheduledHistory, lastSyncTime, threadId]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadEmojiKeywords({ language: 'en' });
|
||||||
|
if (language !== 'en') {
|
||||||
|
loadEmojiKeywords({ language });
|
||||||
|
}
|
||||||
|
}, [loadEmojiKeywords, language]);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (!appendixRef.current) return;
|
if (!appendixRef.current) return;
|
||||||
|
|
||||||
@ -710,10 +717,8 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
usersById={usersById}
|
usersById={usersById}
|
||||||
recentEmojis={recentEmojis}
|
recentEmojis={recentEmojis}
|
||||||
onCaptionUpdate={setHtml}
|
onCaptionUpdate={setHtml}
|
||||||
language={language}
|
|
||||||
emojiKeywords={emojiKeywords}
|
emojiKeywords={emojiKeywords}
|
||||||
addRecentEmoji={addRecentEmoji}
|
addRecentEmoji={addRecentEmoji}
|
||||||
loadEmojiKeywords={loadEmojiKeywords}
|
|
||||||
onSend={shouldSchedule ? openCalendar : handleSend}
|
onSend={shouldSchedule ? openCalendar : handleSend}
|
||||||
onFileAppend={handleAppendFiles}
|
onFileAppend={handleAppendFiles}
|
||||||
onClear={handleClearAttachment}
|
onClear={handleClearAttachment}
|
||||||
@ -845,8 +850,6 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
onClose={closeEmojiTooltip}
|
onClose={closeEmojiTooltip}
|
||||||
onEmojiSelect={insertEmoji}
|
onEmojiSelect={insertEmoji}
|
||||||
addRecentEmoji={addRecentEmoji}
|
addRecentEmoji={addRecentEmoji}
|
||||||
loadEmojiKeywords={loadEmojiKeywords}
|
|
||||||
language={language}
|
|
||||||
/>
|
/>
|
||||||
<AttachMenu
|
<AttachMenu
|
||||||
isOpen={isAttachMenuOpen}
|
isOpen={isAttachMenuOpen}
|
||||||
|
|||||||
@ -2,8 +2,6 @@ import React, {
|
|||||||
FC, memo, useCallback, useEffect, useRef, useState,
|
FC, memo, useCallback, useEffect, useRef, useState,
|
||||||
} from '../../../lib/teact/teact';
|
} from '../../../lib/teact/teact';
|
||||||
|
|
||||||
import { LangCode } from '../../../types';
|
|
||||||
|
|
||||||
import { IS_TOUCH_ENV } from '../../../util/environment';
|
import { IS_TOUCH_ENV } from '../../../util/environment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import cycleRestrict from '../../../util/cycleRestrict';
|
import cycleRestrict from '../../../util/cycleRestrict';
|
||||||
@ -54,22 +52,18 @@ function setItemVisible(index: number, containerRef: Record<string, any>) {
|
|||||||
|
|
||||||
export type OwnProps = {
|
export type OwnProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
language: LangCode;
|
|
||||||
onEmojiSelect: (text: string) => void;
|
onEmojiSelect: (text: string) => void;
|
||||||
onClose: NoneToVoidFunction;
|
onClose: NoneToVoidFunction;
|
||||||
addRecentEmoji: AnyToVoidFunction;
|
addRecentEmoji: AnyToVoidFunction;
|
||||||
loadEmojiKeywords: AnyToVoidFunction;
|
|
||||||
emojis: Emoji[];
|
emojis: Emoji[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const EmojiTooltip: FC<OwnProps> = ({
|
const EmojiTooltip: FC<OwnProps> = ({
|
||||||
isOpen,
|
isOpen,
|
||||||
language,
|
|
||||||
emojis,
|
emojis,
|
||||||
onClose,
|
onClose,
|
||||||
onEmojiSelect,
|
onEmojiSelect,
|
||||||
addRecentEmoji,
|
addRecentEmoji,
|
||||||
loadEmojiKeywords,
|
|
||||||
}) => {
|
}) => {
|
||||||
// eslint-disable-next-line no-null/no-null
|
// eslint-disable-next-line no-null/no-null
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
@ -78,13 +72,6 @@ const EmojiTooltip: FC<OwnProps> = ({
|
|||||||
|
|
||||||
const [selectedIndex, setSelectedIndex] = useState(NO_EMOJI_SELECTED_INDEX);
|
const [selectedIndex, setSelectedIndex] = useState(NO_EMOJI_SELECTED_INDEX);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
loadEmojiKeywords({ language: 'en' });
|
|
||||||
if (language !== 'en') {
|
|
||||||
loadEmojiKeywords({ language });
|
|
||||||
}
|
|
||||||
}, [loadEmojiKeywords, language]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSelectedIndex(0);
|
setSelectedIndex(0);
|
||||||
}, [emojis]);
|
}, [emojis]);
|
||||||
|
|||||||
@ -22,10 +22,10 @@ const EMOJIS_LIMIT = 36;
|
|||||||
const FILTER_MIN_LENGTH = 2;
|
const FILTER_MIN_LENGTH = 2;
|
||||||
|
|
||||||
try {
|
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) {
|
} catch (e) {
|
||||||
// Support for older versions of firefox
|
// 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(
|
export default function useEmojiTooltip(
|
||||||
@ -45,6 +45,7 @@ export default function useEmojiTooltip(
|
|||||||
const [byKeyword, setByKeyword] = useState<Record<string, Emoji[]>>({});
|
const [byKeyword, setByKeyword] = useState<Record<string, Emoji[]>>({});
|
||||||
const [names, setNames] = useState<string[]>();
|
const [names, setNames] = useState<string[]>();
|
||||||
const [byName, setByName] = useState<Record<string, Emoji[]>>({});
|
const [byName, setByName] = useState<Record<string, Emoji[]>>({});
|
||||||
|
const [shouldForceInsertEmoji, setShouldForceInsertEmoji] = useState(false);
|
||||||
|
|
||||||
const [filteredEmojis, setFilteredEmojis] = useState<Emoji[]>([]);
|
const [filteredEmojis, setFilteredEmojis] = useState<Emoji[]>([]);
|
||||||
|
|
||||||
@ -124,9 +125,12 @@ export default function useEmojiTooltip(
|
|||||||
return;
|
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[] = [];
|
let matched: Emoji[] = [];
|
||||||
|
|
||||||
|
setShouldForceInsertEmoji(forceSend);
|
||||||
|
|
||||||
if (!filter) {
|
if (!filter) {
|
||||||
matched = recentEmojis;
|
matched = recentEmojis;
|
||||||
} else if (filter.length >= FILTER_MIN_LENGTH) {
|
} else if (filter.length >= FILTER_MIN_LENGTH) {
|
||||||
@ -141,18 +145,20 @@ export default function useEmojiTooltip(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (matched.length) {
|
if (matched.length) {
|
||||||
markIsOpen();
|
if (!forceSend) {
|
||||||
|
markIsOpen();
|
||||||
|
}
|
||||||
setFilteredEmojis(matched.slice(0, EMOJIS_LIMIT));
|
setFilteredEmojis(matched.slice(0, EMOJIS_LIMIT));
|
||||||
} else {
|
} else {
|
||||||
unmarkIsOpen();
|
unmarkIsOpen();
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
byId, byKeyword, keywords, byName, names,
|
byId, byKeyword, keywords, byName, names, html, isAllowed, markIsOpen,
|
||||||
html, isAllowed, markIsOpen, recentEmojis, unmarkIsOpen,
|
recentEmojis, unmarkIsOpen, setShouldForceInsertEmoji,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const insertEmoji = useCallback((textEmoji: string) => {
|
const insertEmoji = useCallback((textEmoji: string, isForce?: boolean) => {
|
||||||
const atIndex = html.lastIndexOf(':');
|
const atIndex = html.lastIndexOf(':', isForce ? -1 : undefined);
|
||||||
if (atIndex !== -1) {
|
if (atIndex !== -1) {
|
||||||
onUpdateHtml(`${html.substr(0, atIndex)}${textEmoji}`);
|
onUpdateHtml(`${html.substr(0, atIndex)}${textEmoji}`);
|
||||||
const messageInput = document.getElementById(inputId)!;
|
const messageInput = document.getElementById(inputId)!;
|
||||||
@ -166,6 +172,12 @@ export default function useEmojiTooltip(
|
|||||||
unmarkIsOpen();
|
unmarkIsOpen();
|
||||||
}, [html, inputId, onUpdateHtml, unmarkIsOpen]);
|
}, [html, inputId, onUpdateHtml, unmarkIsOpen]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isOpen && shouldForceInsertEmoji && filteredEmojis.length) {
|
||||||
|
insertEmoji(filteredEmojis[0].native, true);
|
||||||
|
}
|
||||||
|
}, [filteredEmojis, insertEmoji, isOpen, shouldForceInsertEmoji]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isEmojiTooltipOpen: isOpen,
|
isEmojiTooltipOpen: isOpen,
|
||||||
closeEmojiTooltip: unmarkIsOpen,
|
closeEmojiTooltip: unmarkIsOpen,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user