import { Placement } from '@popperjs/core'; import clsx from 'clsx'; import React, { useEffect, useState } from 'react'; import { usePopper } from 'react-popper'; import { Emoji, HStack } from 'soapbox/components/ui'; import { useSoapboxConfig } from 'soapbox/hooks'; interface IEmojiButton { /** Unicode emoji character. */ emoji: string, /** Event handler when the emoji is clicked. */ onClick(emoji: string): void /** Extra class name on the ); }; interface IEmojiSelector { onClose?(): void /** Event handler when an emoji is clicked. */ onReact(emoji: string): void /** Element that triggers the EmojiSelector Popper */ referenceElement: HTMLElement | null placement?: Placement /** Whether the selector should be visible. */ visible?: boolean } /** Panel with a row of emoji buttons. */ const EmojiSelector: React.FC = ({ referenceElement, onClose, onReact, placement = 'top', visible = false, }): JSX.Element => { const soapboxConfig = useSoapboxConfig(); // `useRef` won't trigger a re-render, while `useState` does. // https://popper.js.org/react-popper/v2/ const [popperElement, setPopperElement] = useState(null); const handleClickOutside = (event: MouseEvent) => { if (referenceElement?.contains(event.target as Node) || popperElement?.contains(event.target as Node)) { return; } if (onClose) { onClose(); } }; const { styles, attributes, update } = usePopper(referenceElement, popperElement, { placement, modifiers: [ { name: 'offset', options: { offset: [-10, 0], }, }, ], }); useEffect(() => { document.addEventListener('mousedown', handleClickOutside); return () => { document.removeEventListener('mousedown', handleClickOutside); }; }, [referenceElement]); useEffect(() => { if (visible && update) { update(); } }, [visible, update]); return (
{Array.from(soapboxConfig.allowedEmoji).map((emoji, i) => ( ))}
); }; export default EmojiSelector;