stream-chat-react
Version:
React components to create chat conversations or livestream style chat
60 lines (59 loc) • 3.3 kB
JavaScript
import React, { useEffect, useState } from 'react';
import Picker from '@emoji-mart/react';
import { EmojiPickerIcon } from './icons';
import { useMessageInputContext, useTranslationContext } from '../../context';
import { useMessageComposer } from '../../components';
import { usePopoverPosition } from '../../components/Dialog/hooks/usePopoverPosition';
const isShadowRoot = (node) => !!node.host;
const classNames = {
buttonClassName: 'str-chat__emoji-picker-button',
pickerContainerClassName: 'str-chat__message-textarea-emoji-picker-container',
wrapperClassName: 'str-chat__message-textarea-emoji-picker',
};
export const EmojiPicker = (props) => {
const { t } = useTranslationContext('EmojiPicker');
const { textareaRef } = useMessageInputContext('EmojiPicker');
const { textComposer } = useMessageComposer();
const [displayPicker, setDisplayPicker] = useState(false);
const [referenceElement, setReferenceElement] = useState(null);
const [popperElement, setPopperElement] = useState(null);
const { refs, strategy, x, y } = usePopoverPosition({
placement: props.placement ?? 'top-end',
});
useEffect(() => {
refs.setReference(referenceElement);
}, [referenceElement, refs]);
useEffect(() => {
refs.setFloating(popperElement);
}, [popperElement, refs]);
const { buttonClassName, pickerContainerClassName, wrapperClassName } = classNames;
const { ButtonIconComponent = EmojiPickerIcon } = props;
useEffect(() => {
if (!popperElement || !referenceElement)
return;
const handlePointerDown = (e) => {
const target = e.target;
const rootNode = target.getRootNode();
if (popperElement.contains(isShadowRoot(rootNode) ? rootNode.host : target) ||
referenceElement.contains(target)) {
return;
}
setDisplayPicker(false);
};
window.addEventListener('pointerdown', handlePointerDown);
return () => window.removeEventListener('pointerdown', handlePointerDown);
}, [referenceElement, popperElement]);
return (React.createElement("div", { className: props.wrapperClassName ?? wrapperClassName },
displayPicker && (React.createElement("div", { className: props.pickerContainerClassName ?? pickerContainerClassName, ref: setPopperElement, style: { left: x ?? 0, position: strategy, top: y ?? 0 } },
React.createElement(Picker, { data: async () => (await import('@emoji-mart/data')).default, onEmojiSelect: (e) => {
const textarea = textareaRef.current;
if (!textarea)
return;
textComposer.insertText({ text: e.native });
textarea.focus();
if (props.closeOnEmojiSelect) {
setDisplayPicker(false);
}
}, ...props.pickerProps }))),
React.createElement("button", { "aria-expanded": displayPicker, "aria-label": t('aria/Emoji picker'), className: props.buttonClassName ?? buttonClassName, onClick: () => setDisplayPicker((cv) => !cv), ref: setReferenceElement, type: 'button' }, ButtonIconComponent && React.createElement(ButtonIconComponent, null))));
};