From 457de7596639537b165cbaf660f79bde3203672d Mon Sep 17 00:00:00 2001 From: Anton Arnautov Date: Mon, 16 Mar 2026 16:31:31 +0100 Subject: [PATCH 1/3] Allow exiting search on blur, fix behavior --- examples/vite/src/ChatLayout/Panels.tsx | 7 +++++- src/experimental/Search/Search.tsx | 12 +++++++--- .../Search/SearchBar/SearchBar.tsx | 24 +++++++++++++++---- src/experimental/Search/SearchContext.tsx | 16 ++++++------- .../SearchResults/SearchResultsHeader.tsx | 8 +++---- 5 files changed, 44 insertions(+), 23 deletions(-) diff --git a/examples/vite/src/ChatLayout/Panels.tsx b/examples/vite/src/ChatLayout/Panels.tsx index 491d62c3a9..ada0ac2b34 100644 --- a/examples/vite/src/ChatLayout/Panels.tsx +++ b/examples/vite/src/ChatLayout/Panels.tsx @@ -7,6 +7,7 @@ import { ChannelAvatar, ChannelHeader, ChannelList, + ChannelSearchProps, ChatView, MessageInput, MessageList, @@ -42,6 +43,10 @@ const ChannelThreadPanel = () => { ); }; +const CustomChannelSearch = (props: ChannelSearchProps) => ( + +); + export const ChannelsPanels = ({ filters, initialChannelId, @@ -65,7 +70,7 @@ export const ChannelsPanels = ({ ref={channelsLayoutRef} > ({ isActive: nextValue.isActive }); export type SearchProps = { + /** The type of channel to create on user result select, defaults to `messaging` */ directMessagingChannelType?: string; /** Sets the input element into disabled state */ disabled?: boolean; - /** Clear search state / results on every click outside the search input, defaults to false */ + /** Clear the search state/results on every click outside the search input, defaults to `false` */ exitSearchOnInputBlur?: boolean; /** Custom placeholder text to be displayed in the search input */ placeholder?: string; @@ -29,11 +30,13 @@ export type SearchProps = { export const Search = ({ directMessagingChannelType = 'messaging', disabled, - exitSearchOnInputBlur, + exitSearchOnInputBlur = false, placeholder, }: SearchProps) => { const { SearchBar = DefaultSearchBar, SearchResults = DefaultSearchResults } = useComponentContext(); + const containerRef = useRef(null); + const filterButtonsContainerRef = useRef(null); const { searchController } = useChatContext(); @@ -45,9 +48,11 @@ export const Search = ({ return ( diff --git a/src/experimental/Search/SearchBar/SearchBar.tsx b/src/experimental/Search/SearchBar/SearchBar.tsx index 6dd140fd20..165f621fff 100644 --- a/src/experimental/Search/SearchBar/SearchBar.tsx +++ b/src/experimental/Search/SearchBar/SearchBar.tsx @@ -16,9 +16,15 @@ const searchControllerStateSelector = (nextValue: SearchControllerState) => ({ export const SearchBar = () => { const { t } = useTranslationContext(); - const { disabled, exitSearchOnInputBlur, placeholder, searchController } = - useSearchContext(); + const { + disabled, + exitSearchOnInputBlur, + filterButtonsContainerRef, + placeholder, + searchController, + } = useSearchContext(); const queriesInProgress = useSearchQueriesInProgress(searchController); + const clearButtonRef = React.useRef(null); const [input, setInput] = useState(null); const { isActive, searchQuery } = useStateStore( @@ -53,8 +59,16 @@ export const SearchBar = () => { className='str-chat__search-bar__input' data-testid='search-input' disabled={disabled} - onBlur={() => { - if (exitSearchOnInputBlur) searchController.exit(); + onBlur={({ relatedTarget }) => { + if ( + exitSearchOnInputBlur && + // clicking on filter buttons or clear button shouldn't trigger exit search on blur + !filterButtonsContainerRef.current?.contains(relatedTarget) && + // clicking clear button shouldn't trigger exit search on blur + (!clearButtonRef.current || relatedTarget !== clearButtonRef.current) + ) { + searchController.exit(); + } }} onChange={(event: React.ChangeEvent) => { if (event.target.value) { @@ -80,6 +94,7 @@ export const SearchBar = () => { searchController.clear(); input?.focus(); }} + ref={clearButtonRef} size='xs' variant='secondary' > @@ -87,7 +102,6 @@ export const SearchBar = () => { )} - {/* TODO: return button once designs are in */} {isActive && (