stream-chat-react
Version:
React components to create chat conversations or livestream style chat
51 lines (50 loc) • 2.98 kB
JavaScript
import clsx from 'clsx';
import React, { useEffect, useState } from 'react';
import { CommandItem } from './CommandItem';
import { EmoticonItem } from './EmoticonItem';
import { SuggestionListItem as DefaultSuggestionListItem } from './SuggestionListItem';
import { UserItem } from './UserItem';
import { useComponentContext } from '../../../context/ComponentContext';
import { useStateStore } from '../../../store';
import { InfiniteScrollPaginator } from '../../InfiniteScrollPaginator/InfiniteScrollPaginator';
import { useMessageComposer } from '../../MessageInput';
const textComposerStateSelector = (state) => ({
suggestions: state.suggestions,
});
const searchSourceStateSelector = (nextValue) => ({
items: nextValue.items ?? [],
});
export const defaultComponents = {
'/': (props) => (React.createElement(CommandItem, { entity: props.entity })),
':': (props) => (React.createElement(EmoticonItem, { entity: props.entity })),
'@': (props) => (React.createElement(UserItem, { entity: props.entity })),
};
export const SuggestionList = ({ className, closeOnClickOutside = true, containerClassName, focusedItemIndex, setFocusedItemIndex, suggestionItemComponents = defaultComponents, }) => {
const { AutocompleteSuggestionItem = DefaultSuggestionListItem } = useComponentContext();
const messageComposer = useMessageComposer();
const { textComposer } = messageComposer;
const { suggestions } = useStateStore(textComposer.state, textComposerStateSelector);
const { items } = useStateStore(suggestions?.searchSource.state, searchSourceStateSelector) ?? {};
const [container, setContainer] = useState(null);
const component = suggestions?.trigger
? suggestionItemComponents[suggestions?.trigger]
: undefined;
useEffect(() => {
if (!closeOnClickOutside || !suggestions || !container)
return;
const handleClick = (event) => {
if (container.contains(event.target))
return;
textComposer.closeSuggestions();
};
document.addEventListener('click', handleClick);
return () => {
document.removeEventListener('click', handleClick);
};
}, [closeOnClickOutside, suggestions, container, textComposer]);
if (!suggestions || !items?.length || !component)
return null;
return (React.createElement("div", { className: clsx('str-chat__suggestion-list-container', containerClassName), ref: setContainer },
React.createElement(InfiniteScrollPaginator, { loadNextOnScrollToBottom: suggestions.searchSource.search, threshold: 100 },
React.createElement("ul", { className: clsx('str-chat__suggestion-list str-chat__suggestion-list--react', className) }, items.map((item, i) => (React.createElement(AutocompleteSuggestionItem, { component: component, focused: focusedItemIndex === i, item: item, key: item.id.toString(), onMouseEnter: () => setFocusedItemIndex?.(i) })))))));
};