Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions examples/vite/src/ChatLayout/Panels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,20 @@ export const ChannelsPanels = ({
})}
ref={channelsLayoutRef}
>
<ChannelList
Avatar={ChannelAvatar}
customActiveChannel={initialChannelId}
filters={filters}
options={options}
sort={sort}
showChannelSearch
/>
<WithComponents
overrides={{
// @ts-expect-error TODO: adjust the sizing
Avatar: ChannelAvatar,
}}
>
<ChannelList
customActiveChannel={initialChannelId}
filters={filters}
options={options}
sort={sort}
showChannelSearch
/>
</WithComponents>
<SidebarResizeHandle layoutRef={channelsLayoutRef} />
<WithComponents overrides={{ TypingIndicator }}>
<Channel>
Expand Down
42 changes: 10 additions & 32 deletions src/components/ChannelList/ChannelList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,11 @@ import {
usePrepareShapeHandlers,
} from './hooks/useChannelListShape';
import { useStateStore } from '../../store';
import type { ChannelListMessengerProps } from './ChannelListMessenger';
import { ChannelListMessenger } from './ChannelListMessenger';
import type { ChannelAvatarProps } from '../Avatar';
import { Avatar as DefaultAvatar } from '../Avatar';
import type { ChannelListItemUIProps } from '../ChannelListItem/ChannelListItem';
import { ChannelListUI as DefaultChannelListUI } from './ChannelListUI';
import { ChannelListItem } from '../ChannelListItem/ChannelListItem';
import { Search as DefaultSearch } from '../Search';
import type { EmptyStateIndicatorProps } from '../EmptyStateIndicator';
import { EmptyStateIndicator as DefaultEmptyStateIndicator } from '../EmptyStateIndicator';
import { LoadingChannels } from '../Loading/LoadingChannels';
import type { LoadMorePaginatorProps } from '../LoadMore/LoadMorePaginator';
import { LoadMorePaginator } from '../LoadMore/LoadMorePaginator';
import { NotificationList as DefaultNotificationList } from '../Notifications';
Expand All @@ -39,11 +34,9 @@ import {
useChatContext,
useComponentContext,
} from '../../context';
import { NullComponent } from '../UtilityComponents';
import { moveChannelUpwards } from './utils';
import type { TranslationContextValue } from '../../context/TranslationContext';
import type { PaginatorProps } from '../../types/types';
import type { LoadingErrorIndicatorProps } from '../Loading';
import { ChannelListHeader } from './ChannelListHeader';
import { useStableId } from '../UtilityComponents/useStableId';

Expand All @@ -63,8 +56,6 @@ export type ChannelListProps = {
* to false, which will prevent channels not in the list from incrementing the list. The default is true.
*/
allowNewMessagesFromUnfilteredChannels?: boolean;
/** UI component to display an avatar, defaults to [Avatar](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Avatar/Avatar.tsx) component and accepts the same props as: [ChannelAvatar](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Avatar/ChannelAvatar.tsx) */
Avatar?: React.ComponentType<ChannelAvatarProps>;
/** Optional function to filter channels prior to loading in the DOM. Do not use any complex or async logic that would delay the loading of the ChannelList. We recommend using a pure function with array methods like filter/sort/reduce. */
channelRenderFilterFn?: (channels: Array<Channel>) => Array<Channel>;
// FIXME: how is this even legal (WHY IS IT STRING?!)
Expand All @@ -83,12 +74,6 @@ export type ChannelListProps = {
userLanguage: TranslationContextValue['userLanguage'],
isMessageAIGenerated?: ChatContextValue['isMessageAIGenerated'],
) => ReactNode;
/** Custom UI component to display the container for the queried channels, defaults to and accepts same props as: [ChannelListMessenger](https://github.com/GetStream/stream-chat-react/blob/master/src/components/ChannelList/ChannelListMessenger.tsx) */
List?: React.ComponentType<ChannelListMessengerProps>;
/** Custom UI component to display the loading error indicator, defaults to component that renders null */
LoadingErrorIndicator?: React.ComponentType<LoadingErrorIndicatorProps>;
/** Custom UI component to display the loading state, defaults to and accepts same props as: [LoadingChannels](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Loading/LoadingChannels.tsx) */
LoadingIndicator?: React.ComponentType;
/** When true, channels won't dynamically sort by most recent message */
lockChannelOrder?: boolean;
/** Function to override the default behavior when a user is added to a channel, corresponds to [notification.added\_to\_channel](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */
Expand Down Expand Up @@ -140,8 +125,6 @@ export type ChannelListProps = {
options?: ChannelOptions;
/** Custom UI component to handle channel pagination logic, defaults to and accepts same props as: [LoadMorePaginator](https://github.com/GetStream/stream-chat-react/blob/master/src/components/LoadMore/LoadMorePaginator.tsx) */
Paginator?: React.ComponentType<PaginatorProps | LoadMorePaginatorProps>;
/** Custom UI component to display the channel preview in the list, defaults to and accepts same props as: [ChannelPreviewMessenger](https://github.com/GetStream/stream-chat-react/blob/master/src/components/ChannelPreview/ChannelPreviewMessenger.tsx) */
Preview?: React.ComponentType<ChannelListItemUIProps>;
/**
* Custom interval during which the recovery channel list queries will be prevented.
* This is to avoid firing unnecessary queries during internet connection fluctuation.
Expand Down Expand Up @@ -169,16 +152,12 @@ export type ChannelListProps = {
const UnMemoizedChannelList = (props: ChannelListProps) => {
const {
allowNewMessagesFromUnfilteredChannels = true,
Avatar = DefaultAvatar,
channelRenderFilterFn,
customActiveChannel,
customQueryChannels,
EmptyStateIndicator = DefaultEmptyStateIndicator,
filters = {},
getLatestMessagePreview,
List = ChannelListMessenger,
LoadingErrorIndicator = NullComponent,
LoadingIndicator = LoadingChannels,
lockChannelOrder = false,
onAddedToChannel,
onChannelDeleted,
Expand All @@ -191,7 +170,6 @@ const UnMemoizedChannelList = (props: ChannelListProps) => {
onRemovedFromChannel,
options,
Paginator = LoadMorePaginator,
Preview,
recoveryThrottleIntervalMs,
renderChannels,
sendChannelsToList = false,
Expand All @@ -215,8 +193,12 @@ const UnMemoizedChannelList = (props: ChannelListProps) => {
theme,
useImageFlagEmojisOnWindows,
} = useChatContext('ChannelList');
const { NotificationList = DefaultNotificationList, Search = DefaultSearch } =
useComponentContext(); // FIXME: use component context to retrieve ChannelListItemUI components too
const {
ChannelListUI = DefaultChannelListUI,
NotificationList = DefaultNotificationList,
Search = DefaultSearch,
} = useComponentContext();

const channelListRef = useRef<HTMLDivElement | null>(null);
const [channelUpdateCount, setChannelUpdateCount] = useState(0);

Expand Down Expand Up @@ -334,12 +316,10 @@ const UnMemoizedChannelList = (props: ChannelListProps) => {
const renderChannel = (item: Channel) => {
const previewProps = {
activeChannel: channel,
Avatar,
channel: item,
// forces the update of preview component on channel update
channelUpdateCount,
getLatestMessagePreview,
Preview,
setActiveChannel,
watchers,
};
Expand All @@ -351,7 +331,7 @@ const UnMemoizedChannelList = (props: ChannelListProps) => {
const className = clsx(
customClasses?.chat ?? 'str-chat',
theme,
customClasses?.channelList ?? `${baseClass} ${baseClass}-react`,
customClasses?.channelList ?? `${baseClass}`,
{
'str-chat--windows-flags':
useImageFlagEmojisOnWindows && navigator.userAgent.match(/Win/),
Expand All @@ -369,15 +349,13 @@ const UnMemoizedChannelList = (props: ChannelListProps) => {
<ChannelListHeader />
{showChannelSearch && <Search />}
{showChannelList && (
<List
<ChannelListUI
error={channelsQueryState.error}
loadedChannels={sendChannelsToList ? loadedChannels : undefined}
loading={
!!channelsQueryState.queryInProgress &&
['reload', 'uninitialized'].includes(channelsQueryState.queryInProgress)
}
LoadingErrorIndicator={LoadingErrorIndicator}
LoadingIndicator={LoadingIndicator}
setChannels={setChannels}
>
{!loadedChannels?.length ? (
Expand All @@ -393,7 +371,7 @@ const UnMemoizedChannelList = (props: ChannelListProps) => {
: loadedChannels.map((channel) => renderChannel(channel))}
</Paginator>
)}
</List>
</ChannelListUI>
)}
<NotificationList panel='channel-list' />
</div>
Expand Down
69 changes: 0 additions & 69 deletions src/components/ChannelList/ChannelListMessenger.tsx

This file was deleted.

44 changes: 44 additions & 0 deletions src/components/ChannelList/ChannelListUI.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react';
import type { PropsWithChildren } from 'react';
import type { APIErrorResponse, Channel, ErrorFromResponse } from 'stream-chat';

import { LoadingChannels } from '../Loading/LoadingChannels';
import { NullComponent } from '../UtilityComponents';
import { useComponentContext, useTranslationContext } from '../../context';

export type ChannelListUIProps = {
/** Whether the channel query request returned an errored response */
error: ErrorFromResponse<APIErrorResponse> | null;
/** The channels currently loaded in the list, only defined if `sendChannelsToList` on `ChannelList` is true */
loadedChannels?: Channel[];
/** Whether the channels are currently loading */
loading?: boolean;
/** Local state hook that resets the currently loaded channels */
setChannels?: React.Dispatch<React.SetStateAction<Channel[]>>;
};

/**
* A preview list of channels, allowing you to select the channel you want to open
*/
export const ChannelListUI = (props: PropsWithChildren<ChannelListUIProps>) => {
const { children, error = null, loading = false } = props;
const { LoadingErrorIndicator = NullComponent, LoadingIndicator = LoadingChannels } =
useComponentContext('ChannelListUI');
const { t } = useTranslationContext('ChannelListUI');

if (error) {
return <LoadingErrorIndicator error={error} />;
}

return (
<div className='str-chat__channel-list-inner'>
<div
aria-label={t('aria/Channel list')}
className='str-chat__channel-list-inner__main'
role='listbox'
>
{loading ? <LoadingIndicator /> : children}
</div>
</div>
);
};
4 changes: 2 additions & 2 deletions src/components/ChannelList/__tests__/ChannelList.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import {
useChatContext,
WithComponents,
} from '../../../context';
import { ChannelListMessenger } from '../ChannelListMessenger';
import { ChannelListUI } from '../ChannelListUI';

expect.extend(toHaveNoViolations);

Expand Down Expand Up @@ -391,7 +391,7 @@ describe('ChannelList', () => {

const ChannelListMessengerPropsInterceptor = (props) => {
channelListMessengerLoadingHistory.push(props.loading);
return <ChannelListMessenger {...props} />;
return <ChannelListUI {...props} />;
};

await render(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import { cleanup, render } from '@testing-library/react';
import '@testing-library/jest-dom';

import { ChannelListMessenger } from '../ChannelListMessenger';
import { ChannelListUI } from '../ChannelListUI';
import { TranslationProvider } from '../../../context';
import { mockTranslationContext } from '../../../mock-builders';

Expand All @@ -12,15 +12,15 @@ console.warn = () => null;

const Component = ({ error = false, loading = false }) => (
<TranslationProvider value={mockTranslationContext}>
<ChannelListMessenger
<ChannelListUI
error={error}
loading={loading}
LoadingErrorIndicator={() => <div>Loading Error Indicator</div>}
LoadingIndicator={() => <div>Loading Indicator</div>}
>
<div>children 1</div>
<div>children 2</div>
</ChannelListMessenger>
</ChannelListUI>
</TranslationProvider>
);

Expand Down
2 changes: 1 addition & 1 deletion src/components/ChannelList/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from './ChannelList';
export * from './ChannelListMessenger';
export * from './ChannelListUI';
export * from './hooks';
export * from './utils';
4 changes: 2 additions & 2 deletions src/components/ChannelList/styling/ChannelList.scss
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,12 @@
@include utils.scrollable-y;
@include utils.component-layer-overrides('channel-list');

.str-chat__channel-list-messenger {
.str-chat__channel-list-inner {
height: 100%;
overflow: hidden;
padding-bottom: var(--str-chat__spacing-2_5);

.str-chat__channel-list-messenger__main {
.str-chat__channel-list-inner__main {
height: 100%;
overflow-y: auto;

Expand Down
3 changes: 0 additions & 3 deletions src/components/ChannelListItem/ChannelListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { getLatestMessagePreview as defaultGetLatestMessagePreview } from './uti
import { useTranslationContext } from '../../context/TranslationContext';
import { useMessageDeliveryStatus } from './hooks/useMessageDeliveryStatus';
import type { MessageDeliveryStatus } from './hooks/useMessageDeliveryStatus';
import type { ChannelAvatarProps } from '../Avatar/ChannelAvatar';
import type { GroupChannelDisplayInfo } from './utils';
import {
type ChatContextValue,
Expand Down Expand Up @@ -47,8 +46,6 @@ export type ChannelListItemProps = {
active?: boolean;
/** Current selected channel object */
activeChannel?: Channel;
/** UI component to display an avatar, defaults to [Avatar](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Avatar/Avatar.tsx) component and accepts the same props as: [ChannelAvatar](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Avatar/ChannelAvatar.tsx) */
Avatar?: React.ComponentType<ChannelAvatarProps>;
/** Forces the update of preview component on channel update */
channelUpdateCount?: number;
/** Custom class for the channel preview root */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ export function ChannelListItemTimestamp({ lastMessage }: ChannelListItemTimesta
if (!when) return null;

return (
<time className='str-chat__channel-list-item-timestamp' dateTime={normalizedTimestamp}>
<time
className='str-chat__channel-list-item-timestamp'
dateTime={normalizedTimestamp}
>
{when}
</time>
);
Expand Down
Loading
Loading