UNPKG

@chayns-components/core

Version:

A set of beautiful React components for developing your own applications with chayns.

124 lines 4.27 kB
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