UNPKG

@chayns-components/emoji-input

Version:
247 lines (244 loc) • 8.77 kB
// @ts-nocheck import { useCombinedRefs, useIsMeasuredClone } from '@chayns-components/core'; import emojiLib from 'emojilib'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import germanEmojiLib from '../../../constants/emoji-de-DE.json'; import { useEmojiHistory } from '../../../hooks/emojiHistory'; import Emoji from './emoji/Emoji'; import { StyledEmojiPickerEmojis, StyledEmojiPickerEmojisNoContentInfo } from './EmojiPickerEmojis.styles'; const EmojiPickerEmojis = ({ accessToken, onSelect, personId, searchString, selectedCategory }) => { const [shouldPreventScroll, setShouldPreventScroll] = useState(false); const [shouldShowSkinTonePopup, setShouldShowSkinTonePopup] = useState(false); const [focusedIndex, setFocusedIndex] = useState(0); const [emojiCategories, setEmojiCategories] = useState([]); const [emojiList, setEmojiList] = useState([]); useEffect(() => { void import('unicode-emoji-json/data-by-group.json').then(({ default: categories }) => { setEmojiCategories(categories); }); void import('unicode-emoji-json/data-by-emoji.json').then(({ default: emojis }) => { setEmojiList(emojis); }); }, []); const [shouldPreventListener, ref] = useIsMeasuredClone(); const emojiRef = useRef(null); const shouldPreventEmojiControlsRef = useRef(false); const combinedRef = useCombinedRefs(emojiRef, ref); const { addOrUpdateEmojiInHistory, historyEmojis } = useEmojiHistory({ accessToken, personId, selectedCategory }); const handlePopupVisibilityChange = useCallback(isVisible => { setShouldShowSkinTonePopup(isVisible); shouldPreventEmojiControlsRef.current = isVisible; setShouldPreventScroll(isVisible); }, []); const handleSelect = useCallback(({ emoji, name, skin_tone_support, index }) => { onSelect(emoji); if (index) { setFocusedIndex(index); } void addOrUpdateEmojiInHistory({ emoji, name, skin_tone_support }); }, [addOrUpdateEmojiInHistory, onSelect]); useEffect(() => { if (selectedCategory) { setFocusedIndex(0); const container = emojiRef.current; if (!container) { return; } container.scrollTop = 0; } }, [selectedCategory]); useEffect(() => { const handleKeyDown = event => { if (shouldPreventListener) { return; } if (!shouldPreventEmojiControlsRef.current && (event.key === 'ArrowUp' || event.key === 'ArrowDown' || event.key === 'ArrowLeft' || event.key === 'ArrowRight')) { event.preventDefault(); const children = emojiRef.current?.children; if (children && children.length > 0) { const container = emojiRef.current; let newIndex = focusedIndex !== null ? focusedIndex : 0; if (event.ctrlKey) { return; } if (event.key === 'ArrowUp') { newIndex = (newIndex - 6) % children.length; } else if (event.key === 'ArrowDown') { newIndex = (newIndex + 6) % children.length; } else if (event.key === 'ArrowLeft') { newIndex = (newIndex - 1) % children.length; } else if (event.key === 'ArrowRight') { newIndex = (newIndex + 1) % children.length; } // remove focus from the old element if (focusedIndex !== null) { const prevElement = children[focusedIndex]; prevElement.tabIndex = -1; } if (newIndex < 0) { newIndex = children.length - 1; } else if (newIndex > children.length - 1) { newIndex = 0; } setFocusedIndex(newIndex); // Set focus to the element const newElement = children[newIndex]; newElement.tabIndex = 0; const containerRect = container.getBoundingClientRect(); const elementRect = newElement.getBoundingClientRect(); if (elementRect.bottom > containerRect.bottom) { container.scrollTop += elementRect.bottom - containerRect.bottom; } else if (elementRect.top < containerRect.top) { container.scrollTop -= containerRect.top - elementRect.top; } } } else if (event.key === 'Enter' && !shouldPreventEmojiControlsRef.current && focusedIndex !== null) { if (event.ctrlKey) { setShouldShowSkinTonePopup(true); return; } const { dataset } = emojiRef.current?.children[focusedIndex]; const { emoji, name, skinToneSupport } = dataset; if (!emoji || !name || !skinToneSupport) { return; } handleSelect({ emoji, name, skin_tone_support: skinToneSupport === 'true' }); } }; document.addEventListener('keydown', handleKeyDown); return () => { document.removeEventListener('keydown', handleKeyDown); }; }, [focusedIndex, handleSelect, shouldPreventListener]); const handleRightClick = useCallback(index => { setFocusedIndex(index); }, []); const emojis = useMemo(() => { if (searchString.trim() !== '') { const lowerSearchString = searchString.toLowerCase(); const searchResults = []; Object.entries(emojiList).forEach(([emoji, { name, skin_tone_support }], index) => { const keywords = emojiLib[emoji]; const germanKeywords = germanEmojiLib[emoji]; if (name.includes(lowerSearchString) || keywords?.some(keyword => keyword.includes(lowerSearchString)) || germanKeywords?.some(keyword => keyword.includes(lowerSearchString))) { searchResults.push(/*#__PURE__*/React.createElement(Emoji, { shouldShowSkinTonePopup: index === focusedIndex && skin_tone_support && shouldShowSkinTonePopup, isSelected: index === focusedIndex, emoji: emoji, index: index, onRightClick: handleRightClick, isSkinToneSupported: skin_tone_support, key: name, name: name, onPopupVisibilityChange: handlePopupVisibilityChange, onSelect: e => handleSelect({ emoji: e, name, skin_tone_support, index }), emojiList: emojiList })); } }); return searchResults; } if (selectedCategory === 'history') { return historyEmojis.map(({ emoji, name, skin_tone_support }, index) => /*#__PURE__*/React.createElement(Emoji, { isSelected: index === focusedIndex, shouldShowSkinTonePopup: index === focusedIndex && skin_tone_support && shouldShowSkinTonePopup, emoji: emoji, name: name, key: name, index: index, onRightClick: handleRightClick, onPopupVisibilityChange: handlePopupVisibilityChange, onSelect: e => handleSelect({ emoji: e, name, skin_tone_support, index }), isSkinToneSupported: false, emojiList: emojiList })); } return emojiCategories.find(({ slug }) => slug === selectedCategory)?.emojis.map(({ emoji, name, skin_tone_support }, index) => /*#__PURE__*/React.createElement(Emoji, { isSelected: index === focusedIndex, shouldShowSkinTonePopup: index === focusedIndex && skin_tone_support && shouldShowSkinTonePopup, emoji: emoji, name: name, index: index, onRightClick: handleRightClick, isSkinToneSupported: skin_tone_support, key: name, onPopupVisibilityChange: handlePopupVisibilityChange, onSelect: e => handleSelect({ emoji: e, name, skin_tone_support, index }), emojiList: emojiList })); }, [searchString, selectedCategory, focusedIndex, shouldShowSkinTonePopup, handleRightClick, handlePopupVisibilityChange, handleSelect, historyEmojis]); const shouldShowNoContentInfo = !emojis || emojis.length === 0; return /*#__PURE__*/React.createElement(StyledEmojiPickerEmojis, { className: "chayns-scrollbar", $shouldPreventScroll: shouldPreventScroll, $shouldShowNoContentInfo: shouldShowNoContentInfo, ref: combinedRef }, emojis, shouldShowNoContentInfo && /*#__PURE__*/React.createElement(StyledEmojiPickerEmojisNoContentInfo, null, "Hier werden die zuletzt verwendeten Emojis angezeigt, die \xFCber diese Auswahl gew\xE4hlt wurden.")); }; EmojiPickerEmojis.displayName = 'EmojiPickerEmojis'; export default EmojiPickerEmojis; //# sourceMappingURL=EmojiPickerEmojis.js.map