UNPKG

stream-chat-react

Version:

React components to create chat conversations or livestream style chat

60 lines (59 loc) 3.3 kB
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)))); };