diff --git a/examples/vite/src/App.tsx b/examples/vite/src/App.tsx index 215d7d0a1..175ede371 100644 --- a/examples/vite/src/App.tsx +++ b/examples/vite/src/App.tsx @@ -40,6 +40,8 @@ import { humanId } from 'human-id'; import { chatViewSelectorItemSet } from './Sidebar/ChatViewSelectorItemSet.tsx'; import { useAppSettingsState } from './AppSettings'; +import { Search } from 'stream-chat-react/experimental'; + init({ data }); const parseUserIdFromToken = (token: string) => { @@ -67,7 +69,7 @@ const options: ChannelOptions = { state: true, }; // pinned_at param leads to BE not returning (empty) channels -const sort: ChannelSort = { last_message_at: -1, updated_at: -1 }; +const sort: ChannelSort = { pinned_at: -1, last_message_at: -1, updated_at: -1 }; // @ts-ignore const isMessageAIGenerated = (message: LocalMessage) => !!message?.ai_generated; @@ -140,6 +142,7 @@ const App = () => { }, { type: 'public' }, ], + archived: false, }), [userId], ); @@ -204,12 +207,12 @@ const App = () => { /> diff --git a/examples/vite/src/stream-imports-layout.scss b/examples/vite/src/stream-imports-layout.scss index 382dc52b2..e7444c89a 100644 --- a/examples/vite/src/stream-imports-layout.scss +++ b/examples/vite/src/stream-imports-layout.scss @@ -12,7 +12,7 @@ //@use 'stream-chat-react/dist/scss/v2/ChannelHeader/ChannelHeader-layout'; //@use 'stream-chat-react/dist/scss/v2/ChannelList/ChannelList-layout'; //@use 'stream-chat-react/dist/scss/v2/ChannelPreview/ChannelPreview-layout'; -@use 'stream-chat-react/dist/scss/v2/ChannelSearch/ChannelSearch-layout'; +// @use 'stream-chat-react/dist/scss/v2/ChannelSearch/ChannelSearch-layout'; @use 'stream-chat-react/dist/scss/v2/common/CTAButton/CTAButton-layout'; @use 'stream-chat-react/dist/scss/v2/common/CircleFAButton/CircleFAButton-layout'; //@use 'stream-chat-react/dist/scss/v2/Dialog/Dialog-layout'; @@ -39,7 +39,7 @@ @use 'stream-chat-react/dist/scss/v2/Notification/NotificationList-layout'; @use 'stream-chat-react/dist/scss/v2/Notification/Notification-layout'; //@use 'stream-chat-react/dist/scss/v2/Poll/Poll-layout'; -@use 'stream-chat-react/dist/scss/v2/Search/Search-layout'; +// @use 'stream-chat-react/dist/scss/v2/Search/Search-layout'; @use 'stream-chat-react/dist/scss/v2/Thread/Thread-layout'; @use 'stream-chat-react/dist/scss/v2/Tooltip/Tooltip-layout'; @use 'stream-chat-react/dist/scss/v2/TypingIndicator/TypingIndicator-layout'; diff --git a/examples/vite/src/stream-imports-theme.scss b/examples/vite/src/stream-imports-theme.scss index f4a9cee7b..527bedcc8 100644 --- a/examples/vite/src/stream-imports-theme.scss +++ b/examples/vite/src/stream-imports-theme.scss @@ -12,7 +12,7 @@ //@use 'stream-chat-react/dist/scss/v2/ChannelHeader/ChannelHeader-theme'; //@use 'stream-chat-react/dist/scss/v2/ChannelList/ChannelList-theme'; //@use 'stream-chat-react/dist/scss/v2/ChannelPreview/ChannelPreview-theme'; -@use 'stream-chat-react/dist/scss/v2/ChannelSearch/ChannelSearch-theme'; +// @use 'stream-chat-react/dist/scss/v2/ChannelSearch/ChannelSearch-theme'; //@use 'stream-chat-react/dist/scss/v2/Dialog/Dialog-theme'; //@use 'stream-chat-react/dist/scss/v2/DragAndDropContainer/DragAndDropContainer-theme'; //@use 'stream-chat-react/dist/scss/v2/DropzoneContainer/DropzoneContainer-theme'; @@ -33,7 +33,7 @@ @use 'stream-chat-react/dist/scss/v2/Notification/NotificationList-theme'; @use 'stream-chat-react/dist/scss/v2/Notification/Notification-theme'; //@use 'stream-chat-react/dist/scss/v2/Poll/Poll-theme'; -@use 'stream-chat-react/dist/scss/v2/Search/Search-theme'; +// @use 'stream-chat-react/dist/scss/v2/Search/Search-theme'; @use 'stream-chat-react/dist/scss/v2/Thread/Thread-theme'; @use 'stream-chat-react/dist/scss/v2/Tooltip/Tooltip-theme'; @use 'stream-chat-react/dist/scss/v2/TypingIndicator/TypingIndicator-theme'; diff --git a/src/components/ChannelList/ChannelList.tsx b/src/components/ChannelList/ChannelList.tsx index a1aebbcc5..04d4b4f8c 100644 --- a/src/components/ChannelList/ChannelList.tsx +++ b/src/components/ChannelList/ChannelList.tsx @@ -27,6 +27,7 @@ import { LoadingChannels } from '../Loading/LoadingChannels'; import { LoadMorePaginator } from '../LoadMore/LoadMorePaginator'; import { ChannelListContextProvider, + DialogManagerProvider, useChatContext, useComponentContext, } from '../../context'; @@ -43,6 +44,7 @@ import type { ChannelAvatarProps } from '../Avatar'; import type { TranslationContextValue } from '../../context/TranslationContext'; import type { PaginatorProps } from '../../types/types'; import type { LoadingErrorIndicatorProps } from '../Loading'; +import { useStableId } from '../UtilityComponents/useStableId'; const DEFAULT_FILTERS = {}; const DEFAULT_OPTIONS = {}; @@ -226,6 +228,9 @@ const UnMemoizedChannelList = (props: ChannelListProps) => { searchController.state, searchControllerStateSelector, ); + + const stableId = useStableId(); + /** * Set a channel with id {customActiveChannel} as active and move it to the top of the list. * If customActiveChannel prop is absent, then set the first channel in list as active channel. @@ -378,57 +383,59 @@ const UnMemoizedChannelList = (props: ChannelListProps) => { const showChannelList = (!searchActive && !searchIsActive) || additionalChannelSearchProps?.popupResults; return ( - -
- {showChannelSearch && - (Search ? ( - + +
+ {showChannelSearch && + (Search ? ( + + ) : ( + + ))} + {showChannelList && ( + - ) : ( - - ))} - {showChannelList && ( - - {!loadedChannels?.length ? ( - - ) : ( - - {renderChannels - ? renderChannels(loadedChannels, renderChannel) - : loadedChannels.map((channel) => renderChannel(channel))} - - )} - - )} -
-
+ > + {!loadedChannels?.length ? ( + + ) : ( + + {renderChannels + ? renderChannels(loadedChannels, renderChannel) + : loadedChannels.map((channel) => renderChannel(channel))} + + )} + + )} +
+
+ ); }; diff --git a/src/components/ChannelPreview/ChannelPreviewActionButtons.tsx b/src/components/ChannelPreview/ChannelPreviewActionButtons.tsx index 170ce9f49..3eb341c58 100644 --- a/src/components/ChannelPreview/ChannelPreviewActionButtons.tsx +++ b/src/components/ChannelPreview/ChannelPreviewActionButtons.tsx @@ -4,10 +4,16 @@ import type { Channel } from 'stream-chat'; import { useChannelMembershipState } from '../ChannelList'; import { useTranslationContext } from '../../context'; import { Button } from '../Button'; -import { IconArchive, IconMute, IconPin } from '../Icons'; +import { IconArchive, IconDotGrid1x3Horizontal, IconMute, IconPin } from '../Icons'; import clsx from 'clsx'; import { useIsChannelMuted } from './hooks/useIsChannelMuted'; +import { + ContextMenu, + ContextMenuButton, + useDialogIsOpen, + useDialogOnNearestManager, +} from '../Dialog'; export type ChannelPreviewActionButtonsProps = { channel: Channel; @@ -25,40 +31,33 @@ export function ChannelPreviewActionButtons({ channel.data?.member_count === 2 && channel.id?.startsWith('!members-'); - // const buttonRef = useRef>(null); - // const dialogId = `channel-action-buttons-${channel.id}`; - // const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId }); - // const dialogIsOpen = useDialogIsOpen(dialogId, dialogManager?.id); + const [referenceElement, setReferenceElement] = + React.useState(null); + const dialogId = `channel-action-buttons-${channel.id}`; + const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId }); + const dialogIsOpen = useDialogIsOpen(dialogId, dialogManager?.id); return (
{isDirectMessageChannel ? (
); } diff --git a/src/components/ChannelPreview/styling/ChannelPreview.scss b/src/components/ChannelPreview/styling/ChannelPreview.scss index d8d23f1e3..7aef7abb4 100644 --- a/src/components/ChannelPreview/styling/ChannelPreview.scss +++ b/src/components/ChannelPreview/styling/ChannelPreview.scss @@ -3,6 +3,7 @@ padding: var(--spacing-xxs); position: relative; + &:has(.str-chat__channel-preview__action-buttons--active), &:hover { .str-chat__channel-preview__action-buttons { display: flex; @@ -35,6 +36,10 @@ border-bottom: 1px solid var(--border-core-subtle); } +.str-chat__channel-preview__action-buttons-context-menu { + min-width: 150px; +} + .str-chat__channel-preview { display: flex; gap: var(--spacing-md); diff --git a/src/components/Chat/Chat.tsx b/src/components/Chat/Chat.tsx index 3f42b32d8..b078a5b74 100644 --- a/src/components/Chat/Chat.tsx +++ b/src/components/Chat/Chat.tsx @@ -81,8 +81,8 @@ export const Chat = (props: PropsWithChildren) => { new SearchController({ sources: [ new ChannelSearchSource(client), - new UserSearchSource(client), - new MessageSearchSource(client), + // new UserSearchSource(client), + // new MessageSearchSource(client), ], }), [client, customChannelSearchController], diff --git a/src/experimental/Search/SearchBar/SearchBar.tsx b/src/experimental/Search/SearchBar/SearchBar.tsx index 474427e16..fdc0bb306 100644 --- a/src/experimental/Search/SearchBar/SearchBar.tsx +++ b/src/experimental/Search/SearchBar/SearchBar.tsx @@ -5,6 +5,7 @@ import { useSearchContext } from '../SearchContext'; import { useSearchQueriesInProgress } from '../hooks'; import { useTranslationContext } from '../../../context'; import { useStateStore } from '../../../store'; +import { Button, IconCrossSmall, IconMagnifyingGlassSearch } from '../../../components'; import type { SearchControllerState } from 'stream-chat'; @@ -47,7 +48,7 @@ export const SearchBar = () => { 'str-chat__search-input--wrapper-active': isActive, })} > -
+ { value={searchQuery} /> {searchQuery && ( - + + )}
- {isActive ? ( + {/* TODO: return button once designs are in */} + {/* {isActive && ( - ) : null} + )} */} ); }; diff --git a/src/experimental/Search/SearchResults/SearchResultsHeader.tsx b/src/experimental/Search/SearchResults/SearchResultsHeader.tsx index c2ea49fc2..5e13d7195 100644 --- a/src/experimental/Search/SearchResults/SearchResultsHeader.tsx +++ b/src/experimental/Search/SearchResults/SearchResultsHeader.tsx @@ -59,6 +59,10 @@ const SearchSourceFilterButton = ({ source }: SearchSourceFilterButtonProps) => export const SearchResultsHeader = () => { const { searchController } = useSearchContext(); + + // render nothing if there's only one source (can't change filters) + if (searchController.sources.length < 2) return null; + return (