import { cx } from 'flairup'; import * as React from 'react'; import { useEffect } from 'react'; import { ClassNames } from '../../DomUtils/classNames'; import { focusFirstVisibleEmoji } from '../../DomUtils/keyboardNavigation'; import { buttonFromTarget, elementHeight, emojiTrueOffsetTop, emojiTruOffsetLeft, } from '../../DomUtils/selectors'; import { darkMode, stylesheet } from '../../Stylesheet/stylesheet'; import { useEmojiStyleConfig, useGetEmojiUrlConfig, } from '../../config/useConfig'; import { emojiHasVariations, emojiUnified, emojiVariations, } from '../../dataUtils/emojiSelectors'; import { useAnchoredEmojiRef, useBodyRef, useSetAnchoredEmojiRef, useVariationPickerRef, } from '../context/ElementRefContext'; import { useEmojiVariationPickerState } from '../context/PickerContext'; import { ClickableEmoji } from '../emoji/Emoji'; import SVGTriangle from './svg/triangle.svg'; enum Direction { Up, Down, } // eslint-disable-next-line complexity export function EmojiVariationPicker() { const AnchoredEmojiRef = useAnchoredEmojiRef(); const VariationPickerRef = useVariationPickerRef(); const [emoji] = useEmojiVariationPickerState(); const emojiStyle = useEmojiStyleConfig(); const { getTop, getMenuDirection } = useVariationPickerTop(VariationPickerRef); const setAnchoredEmojiRef = useSetAnchoredEmojiRef(); const getPointerStyle = usePointerStyle(VariationPickerRef); const getEmojiUrl = useGetEmojiUrlConfig(); const button = buttonFromTarget(AnchoredEmojiRef.current); const visible = Boolean( emoji && button && emojiHasVariations(emoji) && button.classList.contains(ClassNames.emojiHasVariations), ); useEffect(() => { if (!visible) { return; } focusFirstVisibleEmoji(VariationPickerRef.current); }, [VariationPickerRef, visible, AnchoredEmojiRef]); let top, pointerStyle; if (!visible && AnchoredEmojiRef.current) { setAnchoredEmojiRef(null); } else { top = getTop(); pointerStyle = getPointerStyle(); } return (
{visible && emoji ? [emojiUnified(emoji)] .concat(emojiVariations(emoji)) .slice(0, 6) .map((unified) => ( )) : null}
); } function usePointerStyle(VariationPickerRef: React.RefObject) { const AnchoredEmojiRef = useAnchoredEmojiRef(); return function getPointerStyle() { const style: React.CSSProperties = {}; if (!VariationPickerRef.current) { return style; } if (AnchoredEmojiRef.current) { const button = buttonFromTarget(AnchoredEmojiRef.current); const offsetLeft = emojiTruOffsetLeft(button); if (!button) { return style; } // half of the button style.left = offsetLeft + button?.clientWidth / 2; } return style; }; } function useVariationPickerTop( VariationPickerRef: React.RefObject, ) { const AnchoredEmojiRef = useAnchoredEmojiRef(); const BodyRef = useBodyRef(); let direction = Direction.Up; return { getMenuDirection, getTop, }; function getMenuDirection() { return direction; } function getTop() { direction = Direction.Up; let emojiOffsetTop = 0; if (!VariationPickerRef.current) { return 0; } const height = elementHeight(VariationPickerRef.current); if (AnchoredEmojiRef.current) { const bodyRef = BodyRef.current; const button = buttonFromTarget(AnchoredEmojiRef.current); const buttonHeight = elementHeight(button); emojiOffsetTop = emojiTrueOffsetTop(button); const scrollTop = bodyRef?.scrollTop ?? 0; if (scrollTop > emojiOffsetTop - height) { direction = Direction.Down; emojiOffsetTop += buttonHeight + height; } } return emojiOffsetTop - height; } } const styles = stylesheet.create({ variationPicker: { '.': ClassNames.variationPicker, position: 'absolute', right: '15px', left: '15px', padding: '5px', boxShadow: '0px 2px 5px rgba(0, 0, 0, 0.2)', borderRadius: '3px', display: 'flex', alignItems: 'center', justifyContent: 'space-around', opacity: '0', visibility: 'hidden', pointerEvents: 'none', top: '-100%', border: '1px solid var(--epr-picker-border-color)', height: 'var(--epr-emoji-variation-picker-height)', zIndex: 'var(--epr-skin-variation-picker-z-index)', background: 'var(--epr-emoji-variation-picker-bg-color)', transform: 'scale(0.9)', transition: 'transform 0.1s ease-out, opacity 0.2s ease-out', }, visible: { opacity: '1', visibility: 'visible', pointerEvents: 'all', transform: 'scale(1)', }, pointingUp: { '.': 'pointing-up', transformOrigin: 'center 0%', transform: 'scale(0.9)', }, '.pointing-up': { pointer: { top: '0', transform: 'rotate(180deg) translateY(100%) translateX(18px)', }, }, pointer: { '.': 'epr-emoji-pointer', content: '', position: 'absolute', width: '25px', height: '15px', backgroundRepeat: 'no-repeat', backgroundPosition: '0 0', backgroundSize: '50px 15px', top: '100%', transform: 'translateX(-18px)', backgroundImage: `url(${SVGTriangle})`, }, ...darkMode('pointer', { backgroundPosition: '-25px 0', }), });