UNPKG

stream-chat-react

Version:

React components to create chat conversations or livestream style chat

68 lines (67 loc) 3.96 kB
import React, { useCallback, useEffect, useRef, useState } from 'react'; import clsx from 'clsx'; import { MenuIcon as DefaultMenuIcon, SearchIcon as DefaultSearchInputIcon, ReturnIcon, XIcon, } from './icons'; import { SearchInput as DefaultSearchInput } from './SearchInput'; const SearchBarButton = ({ children, className, onClick, }) => (React.createElement("button", { className: clsx('str-chat__channel-search-bar-button', className), "data-testid": 'search-bar-button', onClick: onClick }, children)); // todo: add context menu control logic export const SearchBar = (props) => { const { activateSearch, AppMenu, ClearInputIcon = XIcon, exitSearch, ExitSearchIcon = ReturnIcon, inputIsFocused, MenuIcon = DefaultMenuIcon, searchBarRef, SearchInput = DefaultSearchInput, SearchInputIcon = DefaultSearchInputIcon, ...inputProps } = props; const [menuIsOpen, setMenuIsOpen] = useState(false); const appMenuRef = useRef(null); useEffect(() => { if (!appMenuRef.current) return; const handleKeyDown = (event) => { if (menuIsOpen && event.key === 'Escape') { setMenuIsOpen(false); } }; const clickListener = (e) => { if (!(e.target instanceof HTMLElement) || !menuIsOpen || appMenuRef.current?.contains(e.target)) return; setMenuIsOpen(false); }; document.addEventListener('keydown', handleKeyDown); document.addEventListener('click', clickListener); return () => { document.removeEventListener('keydown', handleKeyDown); document.removeEventListener('click', clickListener); }; }, [menuIsOpen]); useEffect(() => { if (!props.inputRef.current) return; const input = props.inputRef.current; const handleFocus = () => { activateSearch(); }; const handleBlur = (e) => { e.stopPropagation(); // handle blur/focus state with React state }; input.addEventListener('focus', handleFocus); input.addEventListener('blur', handleBlur); return () => { input.removeEventListener('focus', handleFocus); input.removeEventListener('blur', handleBlur); }; }, [activateSearch, props.inputRef]); const handleClearClick = useCallback(() => { exitSearch(); inputProps.inputRef.current?.focus(); }, [exitSearch, inputProps.inputRef]); const closeAppMenu = useCallback(() => setMenuIsOpen(false), []); return (React.createElement("div", { className: 'str-chat__channel-search-bar', "data-testid": 'search-bar', ref: searchBarRef }, inputIsFocused ? (React.createElement(SearchBarButton, { className: 'str-chat__channel-search-bar-button--exit-search', onClick: exitSearch }, React.createElement(ExitSearchIcon, null))) : AppMenu ? (React.createElement(SearchBarButton, { className: 'str-chat__channel-search-bar-button--menu', onClick: () => setMenuIsOpen((prev) => !prev) }, React.createElement(MenuIcon, null))) : null, React.createElement("div", { className: clsx('str-chat__channel-search-input--wrapper', inputProps.query && 'str-chat__channel-search-input--wrapper-active') }, React.createElement("div", { className: 'str-chat__channel-search-input--icon' }, React.createElement(SearchInputIcon, null)), React.createElement(SearchInput, { ...inputProps }), React.createElement("button", { className: 'str-chat__channel-search-input--clear-button', "data-testid": 'clear-input-button', disabled: !inputProps.query, onClick: handleClearClick }, React.createElement(ClearInputIcon, null))), menuIsOpen && AppMenu && (React.createElement("div", { ref: appMenuRef }, React.createElement(AppMenu, { close: closeAppMenu }))))); };