@chayns-components/emoji-input
Version:
Input field that supports HTML elements and emojis
120 lines (118 loc) • 3.98 kB
JavaScript
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import emojiComponents from 'unicode-emoji-json/data-emoji-components.json';
import { addSkinToneToEmoji } from '../../../../../utils/emoji';
import { StyledMotionSkinTonePopup, StyledSkinTonePopupContent, StyledSkinTonePopupContentEmoji, StyledSkinTonePopupOverlay } from './SkinTonePopup.styles';
const SkinTonePopup = ({
anchorAlignment,
anchorOffset,
emoji,
onHidePopup,
onSelect,
overlayPosition,
position,
emojiList
}) => {
const [focusedIndex, setFocusedIndex] = useState(0);
const skinToneRef = useRef(null);
const handleOverlayClick = useCallback(event => {
event.preventDefault();
event.stopPropagation();
onHidePopup();
}, [onHidePopup]);
useEffect(() => {
const handleKeyDown = event => {
if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
event.preventDefault();
const children = skinToneRef.current?.children;
if (children && children.length > 0) {
let newIndex = focusedIndex !== null ? focusedIndex : 0;
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;
newElement.focus();
}
} else if (event.key === 'Enter' && focusedIndex !== null) {
const {
dataset
} = skinToneRef.current?.children[focusedIndex];
const {
skinTone
} = dataset;
if (!skinTone) {
return;
}
onSelect(skinTone);
onHidePopup();
} else if (event.key === 'Escape' && event.shiftKey) {
event.preventDefault();
onHidePopup();
}
};
document.addEventListener('keydown', handleKeyDown);
return () => {
document.removeEventListener('keydown', handleKeyDown);
};
}, [focusedIndex, onHidePopup, onSelect]);
const emojis = useMemo(() => {
const result = [];
Object.entries(emojiComponents).forEach(([key, value], index) => {
if (key.includes('skin_tone')) {
const emojiWithSkinTone = addSkinToneToEmoji(emojiList, emoji, value);
const handleClick = event => {
event.preventDefault();
event.stopPropagation();
onSelect(emojiWithSkinTone);
onHidePopup();
};
result.push(/*#__PURE__*/React.createElement(StyledSkinTonePopupContentEmoji, {
key: key,
"data-skin-tone": emojiWithSkinTone,
$isSelected: index === focusedIndex,
onClick: handleClick
}, emojiWithSkinTone));
}
});
return result;
}, [emoji, emojiList, focusedIndex, onHidePopup, onSelect]);
return /*#__PURE__*/React.createElement(StyledMotionSkinTonePopup, {
animate: {
opacity: 1
},
exit: {
opacity: 0
},
initial: {
opacity: 0
},
transition: {
duration: 0.1
}
}, /*#__PURE__*/React.createElement(StyledSkinTonePopupContent, {
ref: skinToneRef,
$anchorAlignment: anchorAlignment,
$anchorOffset: anchorOffset,
style: position
}, emojis), /*#__PURE__*/React.createElement(StyledSkinTonePopupOverlay, {
onClick: handleOverlayClick,
style: overlayPosition
}));
};
SkinTonePopup.displayName = 'SkinTonePopup';
export default SkinTonePopup;
//# sourceMappingURL=SkinTonePopup.js.map