@chayns-components/core
Version:
A set of beautiful React components for developing your own applications with chayns.
124 lines • 4.27 kB
JavaScript
import { AnimatePresence } from 'motion/react';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import MentionFinderItem from './mention-finder-item/MentionFinderItem';
import { StyledMentionFinder, StyledMotionMentionFinderPopup } from './MentionFinder.styles';
const MentionFinder = _ref => {
let {
inputValue,
members,
onSelect,
popupAlignment
} = _ref;
const [activeMember, setActiveMember] = useState(members[0]);
const [focusedIndex, setFocusedIndex] = useState(0);
const ref = useRef(null);
const [fullMatch, searchString] = useMemo(() => {
// eslint-disable-next-line no-irregular-whitespace
const regExpMatchArray = inputValue.match(/@([^\s]*)/);
return [regExpMatchArray?.[0], regExpMatchArray?.[1]?.toLowerCase() ?? ''];
}, [inputValue]);
const filteredMembers = useMemo(() => searchString !== '' ? members.filter(_ref2 => {
let {
id,
info,
name
} = _ref2;
return id.toLowerCase().includes(searchString) || info?.replace('chayns', '').toLowerCase().includes(searchString) || name.toLowerCase().includes(searchString);
}) : members, [members, searchString]);
const handleKeyDown = useCallback(event => {
if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
event.preventDefault();
const children = ref.current?.children;
if (children && children.length > 0) {
const newIndex = focusedIndex !== null ? (focusedIndex + (event.key === 'ArrowUp' ? -1 : 1) + children.length) % children.length : 0;
if (focusedIndex !== null) {
const prevElement = children[focusedIndex];
prevElement.tabIndex = -1;
}
setFocusedIndex(newIndex);
const member = filteredMembers[newIndex];
setActiveMember(member);
const newElement = children[newIndex];
newElement.tabIndex = 0;
newElement.focus();
}
} else if (event.key === 'Enter') {
event.preventDefault();
event.stopPropagation();
if (fullMatch && activeMember) {
onSelect({
fullMatch,
member: activeMember
});
}
}
}, [activeMember, filteredMembers, focusedIndex, fullMatch, onSelect]);
const handleMemberClick = useCallback(member => {
if (fullMatch) {
onSelect({
fullMatch,
member
});
}
}, [fullMatch, onSelect]);
const handleMemberHover = useCallback(member => {
setActiveMember(member);
}, []);
useEffect(() => {
if (filteredMembers.length > 0) {
const isActiveMemberShown = filteredMembers.some(_ref3 => {
let {
id
} = _ref3;
return id === activeMember?.id;
});
if (!isActiveMemberShown) {
setActiveMember(filteredMembers[0]);
}
}
}, [activeMember?.id, filteredMembers]);
const items = useMemo(() => filteredMembers.map(member => /*#__PURE__*/React.createElement(MentionFinderItem, {
isActive: member.id === activeMember?.id,
key: member.id,
member: member,
onClick: handleMemberClick,
onHover: handleMemberHover
})), [activeMember, filteredMembers, handleMemberClick, handleMemberHover]);
const shouldShowPopup = useMemo(() => fullMatch && items.length > 0, [fullMatch, items.length]);
useEffect(() => {
if (shouldShowPopup) {
window.addEventListener('keydown', handleKeyDown, true);
}
return () => {
window.removeEventListener('keydown', handleKeyDown, true);
};
}, [handleKeyDown, shouldShowPopup]);
return /*#__PURE__*/React.createElement(StyledMentionFinder, {
className: "beta-chayns-mention-finder"
}, /*#__PURE__*/React.createElement(AnimatePresence, {
initial: false
}, shouldShowPopup && /*#__PURE__*/React.createElement(StyledMotionMentionFinderPopup, {
ref: ref,
animate: {
height: 'auto',
opacity: 1
},
className: "prevent-lose-focus",
exit: {
height: 0,
opacity: 0
},
initial: {
height: 0,
opacity: 0
},
$popupAlignment: popupAlignment,
transition: {
duration: 0.15
},
tabIndex: 0
}, items)));
};
MentionFinder.displayName = 'MentionFinder';
export default MentionFinder;
//# sourceMappingURL=MentionFinder.js.map