Emoji Tooltip: Various fixes (#2688)

This commit is contained in:
Alexander Zinchuk 2023-02-28 18:44:00 +01:00
parent 92c1b0b281
commit 7c7e0c1d69
8 changed files with 45 additions and 14 deletions

View File

@ -2,6 +2,7 @@ import React, { memo, useCallback } from '../../../lib/teact/teact';
import type { FC } from '../../../lib/teact/teact';
import type { ApiSticker } from '../../../api/types';
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
import buildClassName from '../../../util/buildClassName';
@ -15,10 +16,11 @@ type OwnProps = {
emoji: ApiSticker;
focus?: boolean;
onClick?: (emoji: ApiSticker) => void;
observeIntersection?: ObserveFn;
};
const CustomEmojiButton: FC<OwnProps> = ({
emoji, focus, onClick,
emoji, focus, onClick, observeIntersection,
}) => {
const handleClick = useCallback((e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
// Preventing safari from losing focus on Composer MessageInput
@ -38,7 +40,13 @@ const CustomEmojiButton: FC<OwnProps> = ({
onMouseDown={handleClick}
title={emoji.emoji}
>
<CustomEmoji documentId={emoji.id} size={CUSTOM_EMOJI_SIZE} withSharedAnimation shouldPreloadPreview />
<CustomEmoji
documentId={emoji.id}
size={CUSTOM_EMOJI_SIZE}
withSharedAnimation
shouldPreloadPreview
observeIntersectionForPlaying={observeIntersection}
/>
</div>
);
};

View File

@ -10,7 +10,7 @@
}
.emojiButton {
flex: 0 0 2.5rem;
flex: 0 0 2rem;
--custom-emoji-size: 2rem;
margin: 0.5rem 0 0.5rem 0.25rem;
}

View File

@ -59,7 +59,7 @@ const CustomEmojiTooltip: FC<OwnProps & StateProps> = ({
const {
observe: observeIntersection,
} = useIntersectionObserver({ rootRef: containerRef, throttleMs: INTERSECTION_THROTTLE });
} = useIntersectionObserver({ rootRef: containerRef, throttleMs: INTERSECTION_THROTTLE, isDisabled: !isOpen });
useEffect(() => (isOpen ? captureEscKeyListener(onClose) : undefined), [isOpen, onClose]);

View File

@ -14,6 +14,7 @@ import useShowTransition from '../../../hooks/useShowTransition';
import usePrevDuringAnimation from '../../../hooks/usePrevDuringAnimation';
import { useKeyboardNavigation } from './hooks/useKeyboardNavigation';
import useHorizontalScroll from '../../../hooks/useHorizontalScroll';
import { useIntersectionObserver } from '../../../hooks/useIntersectionObserver';
import Loading from '../../ui/Loading';
import EmojiButton from './EmojiButton';
@ -64,6 +65,8 @@ export type OwnProps = {
addRecentCustomEmoji: ({ documentId }: { documentId: string }) => void;
};
const INTERSECTION_THROTTLE = 200;
const EmojiTooltip: FC<OwnProps> = ({
isOpen,
emojis,
@ -83,6 +86,10 @@ const EmojiTooltip: FC<OwnProps> = ({
useHorizontalScroll(containerRef);
const {
observe: observeIntersection,
} = useIntersectionObserver({ rootRef: containerRef, throttleMs: INTERSECTION_THROTTLE, isDisabled: !isOpen });
const handleSelectEmoji = useCallback((emoji: Emoji) => {
onEmojiSelect(emoji.native);
addRecentEmoji({ emoji: emoji.id });
@ -148,6 +155,7 @@ const EmojiTooltip: FC<OwnProps> = ({
emoji={emoji}
focus={selectedIndex === index}
onClick={handleCustomEmojiClick}
observeIntersection={observeIntersection}
/>
)
))

View File

@ -27,6 +27,7 @@ interface Library {
byKeyword: Record<string, Emoji[]>;
names: string[];
byName: Record<string, Emoji[]>;
maxKeyLength: number;
}
let emojiDataPromise: Promise<EmojiModule>;
@ -34,6 +35,7 @@ let emojiRawData: EmojiRawData;
let emojiData: EmojiData;
let RE_EMOJI_SEARCH: RegExp;
let RE_LOWERCASE_TEST: RegExp;
const EMOJIS_LIMIT = 36;
const FILTER_MIN_LENGTH = 2;
@ -44,10 +46,12 @@ const prepareLibraryMemo = memoized(prepareLibrary);
const searchInLibraryMemo = memoized(searchInLibrary);
try {
RE_EMOJI_SEARCH = /(^|\s):[-+_:\p{L}\p{N}]*$/gui;
RE_EMOJI_SEARCH = /(^|\s):(?!\s)[-+_:'\s\p{L}\p{N}]*$/gui;
RE_LOWERCASE_TEST = /\p{Ll}/u;
} catch (e) {
// Support for older versions of firefox
RE_EMOJI_SEARCH = /(^|\s):[-+_:\d\wа-яё]*$/gi;
RE_EMOJI_SEARCH = /(^|\s):(?!\s)[-+_:'\s\d\wа-яёґєії]*$/gi;
RE_LOWERCASE_TEST = /[a-zяёґєії]/;
}
export default function useEmojiTooltip(
@ -141,12 +145,13 @@ export default function useEmojiTooltip(
if (!filter) {
matched = prepareRecentEmojisMemo(byId, recentEmojiIds, EMOJIS_LIMIT);
} else if (filter.length >= FILTER_MIN_LENGTH) {
} else if ((filter.length === 1 && RE_LOWERCASE_TEST.test(filter)) || filter.length >= FILTER_MIN_LENGTH) {
const library = prepareLibraryMemo(byId, baseEmojiKeywords, emojiKeywords);
matched = searchInLibraryMemo(library, filter, EMOJIS_LIMIT);
matched = searchInLibraryMemo(library, filter.toLowerCase(), EMOJIS_LIMIT);
}
if (!matched.length) {
updateFiltered(MEMO_EMPTY_ARRAY);
return;
}
@ -172,7 +177,7 @@ export default function useEmojiTooltip(
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);
@ -224,21 +229,27 @@ function prepareLibrary(
}, {} as Record<string, Emoji[]>);
const names = Object.keys(byName);
const maxKeyLength = keywords.reduce((max, keyword) => Math.max(max, keyword.length), 0);
return {
byKeyword,
keywords,
byName,
names,
maxKeyLength,
};
}
function searchInLibrary(library: Library, filter: string, limit: number) {
const {
byKeyword, keywords, byName, names,
byKeyword, keywords, byName, names, maxKeyLength,
} = library;
let matched: Emoji[] = MEMO_EMPTY_ARRAY;
let matched: Emoji[] = [];
if (filter.length > maxKeyLength) {
return MEMO_EMPTY_ARRAY;
}
const matchedKeywords = keywords.filter((keyword) => keyword.startsWith(filter)).sort();
matched = matched.concat(Object.values(pickTruthy(byKeyword!, matchedKeywords)).flat());
@ -249,5 +260,9 @@ function searchInLibrary(library: Library, filter: string, limit: number) {
matched = unique(matched);
if (!matched.length) {
return MEMO_EMPTY_ARRAY;
}
return matched.slice(0, limit);
}

View File

@ -25,7 +25,7 @@ try {
RE_USERNAME_SEARCH = /(^|\s)@[-_\p{L}\p{M}\p{N}]*$/gui;
} catch (e) {
// Support for older versions of Firefox
RE_USERNAME_SEARCH = /(^|\s)@[-_\d\wа-яё]*$/gi;
RE_USERNAME_SEARCH = /(^|\s)@[-_\d\wа-яёґєії]*$/gi;
}
export default function useMentionTooltip(

View File

@ -71,7 +71,7 @@ function scrollWithJs(container: HTMLElement, left: number, duration: number) {
if (t >= 1) {
container.style.scrollSnapType = '';
container.dataset.scrollId = undefined;
delete container.dataset.scrollId;
stopById.delete(id);
resolve();
}

View File

@ -4,7 +4,7 @@ try {
RE_NOT_LETTER = /[^\p{L}\p{M}]+/ui;
} catch (e) {
// Support for older versions of firefox
RE_NOT_LETTER = /[^\wа-яё]+/i;
RE_NOT_LETTER = /[^\wа-яёґєії]+/i;
}
export default function searchWords(haystack: string, needle: string | string[]) {