2022-03-19 21:18:56 +01:00

119 lines
3.2 KiB
TypeScript

import React, {
FC, memo, useCallback, useEffect, useRef,
} from '../../../lib/teact/teact';
import buildClassName from '../../../util/buildClassName';
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 { useKeyboardNavigation } from './hooks/useKeyboardNavigation';
import Loading from '../../ui/Loading';
import EmojiButton from './EmojiButton';
import './EmojiTooltip.scss';
const VIEWPORT_MARGIN = 8;
const EMOJI_BUTTON_WIDTH = 44;
const CLOSE_DURATION = 350;
function setItemVisible(index: number, containerRef: Record<string, any>) {
const container = containerRef.current!;
if (!container) {
return;
}
const { visibleIndexes, allElements } = findInViewport(
container,
'.EmojiButton',
VIEWPORT_MARGIN,
true,
true,
true,
);
if (!allElements.length || !allElements[index]) {
return;
}
const first = visibleIndexes[0];
if (!visibleIndexes.includes(index)
|| (index === first && !isFullyVisible(container, allElements[first], true))) {
const position = index > visibleIndexes[visibleIndexes.length - 1] ? 'start' : 'end';
const newLeft = position === 'start' ? index * EMOJI_BUTTON_WIDTH : 0;
fastSmoothScrollHorizontal(container, newLeft);
}
}
export type OwnProps = {
isOpen: boolean;
onEmojiSelect: (text: string) => void;
onClose: NoneToVoidFunction;
addRecentEmoji: AnyToVoidFunction;
emojis: Emoji[];
};
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 handleSelectEmoji = useCallback((emoji: Emoji) => {
onEmojiSelect(emoji.native);
addRecentEmoji({ emoji: emoji.id });
}, [addRecentEmoji, onEmojiSelect]);
const handleClick = useCallback((native: string, id: string) => {
onEmojiSelect(native);
addRecentEmoji({ emoji: id });
}, [addRecentEmoji, onEmojiSelect]);
const selectedIndex = useKeyboardNavigation({
isActive: isOpen,
isHorizontal: true,
items: emojis,
onSelect: handleSelectEmoji,
onClose,
});
useEffect(() => {
setItemVisible(selectedIndex, containerRef);
}, [selectedIndex]);
const className = buildClassName(
'EmojiTooltip composer-tooltip custom-scroll-x',
transitionClassNames,
);
return (
<div
ref={containerRef}
className={className}
>
{shouldRender && listEmojis ? (
listEmojis.map((emoji, index) => (
<EmojiButton
key={emoji.id}
emoji={emoji}
focus={selectedIndex === index}
onClick={handleClick}
/>
))
) : shouldRender ? (
<Loading />
) : undefined}
</div>
);
};
export default memo(EmojiTooltip);