Emoji Tooltip: Update recent emojis (#1066)

This commit is contained in:
Alexander Zinchuk 2021-05-11 02:57:05 +03:00
parent 0cf1bbb72c
commit 1436cb6908
3 changed files with 28 additions and 15 deletions

View File

@ -811,6 +811,7 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
emojis={filteredEmojis}
onClose={closeEmojiTooltip}
onEmojiSelect={insertEmoji}
addRecentEmoji={addRecentEmoji}
/>
<AttachMenu
isOpen={isAttachMenuOpen}

View File

@ -10,6 +10,7 @@ import findInViewport from '../../../util/findInViewport';
import isFullyVisible from '../../../util/isFullyVisible';
import fastSmoothScrollHorizontal from '../../../util/fastSmoothScrollHorizontal';
import useShowTransition from '../../../hooks/useShowTransition';
import usePrevDuringAnimation from '../../../hooks/usePrevDuringAnimation';
import Loading from '../../ui/Loading';
import EmojiButton from './EmojiButton';
@ -51,18 +52,23 @@ export type OwnProps = {
isOpen: boolean;
onEmojiSelect: (text: string) => void;
onClose: NoneToVoidFunction;
addRecentEmoji: AnyToVoidFunction;
emojis: Emoji[];
};
const CLOSE_DURATION = 350;
const EmojiTooltip: FC<OwnProps> = ({
isOpen,
emojis,
onClose,
onEmojiSelect,
addRecentEmoji,
}) => {
// eslint-disable-next-line no-null/no-null
const containerRef = useRef<HTMLDivElement>(null);
const { shouldRender, transitionClassNames } = useShowTransition(isOpen, undefined, undefined, false);
const listEmojis: Emoji[] = usePrevDuringAnimation(emojis.length ? emojis : undefined, CLOSE_DURATION) || [];
const [selectedIndex, setSelectedIndex] = useState(-1);
@ -95,9 +101,10 @@ const EmojiTooltip: FC<OwnProps> = ({
if (emoji) {
e.preventDefault();
onEmojiSelect(emoji.native);
addRecentEmoji({ emoji: emoji.id });
}
}
}, [emojis, onEmojiSelect, selectedIndex]);
}, [addRecentEmoji, emojis, onEmojiSelect, selectedIndex]);
useEffect(() => (isOpen ? captureKeyboardListeners({
onEsc: onClose,
@ -126,8 +133,8 @@ const EmojiTooltip: FC<OwnProps> = ({
onMouseEnter={!IS_TOUCH_ENV ? handleMouseEnter : undefined}
onMouseLeave={!IS_TOUCH_ENV ? handleMouseLeave : undefined}
>
{shouldRender && emojis ? (
emojis.map((emoji, index) => (
{shouldRender && listEmojis ? (
listEmojis.map((emoji, index) => (
<EmojiButton
key={emoji.id}
emoji={emoji}

View File

@ -15,7 +15,7 @@ let emojiRawData: EmojiRawData;
let emojiData: EmojiData;
const RE_NOT_EMOJI_SEARCH = /[^-:_a-z\d]+/i;
const EMOJIS_LIMIT = 50;
const EMOJIS_LIMIT = 36;
export default function useEmojiTooltip(
isAllowed: boolean,
@ -25,24 +25,26 @@ export default function useEmojiTooltip(
onUpdateHtml: (html: string) => void,
) {
const [isOpen, markIsOpen, unmarkIsOpen] = useFlag();
const [emojis, setEmojis] = useState<Emoji[]>([]);
const [emojiIds, setEmojiIds] = useState<string[]>([]);
const [filteredEmojis, setFilteredEmojis] = useState<Emoji[]>([]);
const recentEmojis = useMemo(
() => {
if (!emojis && !recentEmojiIds.length) {
if (!emojiIds.length || !recentEmojiIds.length) {
return [];
}
return emojis.filter((emoji) => recentEmojiIds.includes(emoji.id)) as Emoji[];
return recentEmojiIds
.map((emojiId) => emojiData.emojis[emojiId])
.filter<Emoji>(Boolean as any);
},
[emojis, recentEmojiIds],
[emojiIds, recentEmojiIds],
);
// Initialize data on first render.
useEffect(() => {
const exec = () => {
setEmojis(Object.values(emojiData.emojis));
setEmojiIds(Object.keys(emojiData.emojis));
};
if (emojiData) {
@ -54,7 +56,7 @@ export default function useEmojiTooltip(
}, []);
useEffect(() => {
if (!html || !emojis) {
if (!html || !emojiIds.length) {
unmarkIsOpen();
return;
}
@ -67,17 +69,20 @@ export default function useEmojiTooltip(
}
const filter = code.substr(1);
const matched = filter === '' ? recentEmojis : emojis.filter((emoji) => {
return 'names' in emoji && (!filter || emoji.names.find((name) => name.includes(filter)));
}) as Emoji[];
const matched = filter === ''
? recentEmojis
: emojiIds
.filter((emojiId) => emojiData.emojis[emojiId].names.find((name) => name.includes(filter)))
.slice(0, EMOJIS_LIMIT)
.map((emojiId) => emojiData.emojis[emojiId]);
if (matched.length) {
markIsOpen();
setFilteredEmojis(matched.slice(0, EMOJIS_LIMIT));
setFilteredEmojis(matched);
} else {
unmarkIsOpen();
}
}, [emojis, html, markIsOpen, recentEmojis, unmarkIsOpen]);
}, [emojiIds, html, markIsOpen, recentEmojis, unmarkIsOpen]);
const insertEmoji = useCallback((textEmoji: string) => {
const atIndex = html.lastIndexOf(':');