Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
2badc51
refactor!: introduce WithComponents context provider
oliverlaz Apr 8, 2026
b6c0a96
fix: populate defaultComponents, fix circular dep, update tests
oliverlaz Apr 8, 2026
c94fa39
refactor!: move remaining component overrides to ComponentsContext
oliverlaz Apr 8, 2026
034ef79
refactor: update SampleApp to use WithComponents for component overrides
oliverlaz Apr 8, 2026
bad66b1
fix: re-add componentsContext export to contexts barrel
oliverlaz Apr 8, 2026
b90ea46
refactor: update ExpoMessaging to use WithComponents
oliverlaz Apr 8, 2026
efac0d8
refactor: simplify ComponentsContext by deriving type from defaults
oliverlaz Apr 8, 2026
2a7aba9
refactor: rename WithComponents prop from value to overrides
oliverlaz Apr 9, 2026
b77d631
fix: split LoadingIndicator into ChannelList and MessageList variants
oliverlaz Apr 9, 2026
c0f6234
merge: resolve conflicts with develop
oliverlaz Apr 10, 2026
31ef8c8
docs: update PLAN.md with current state and reference notes
oliverlaz Apr 10, 2026
617b3db
refactor: migrate remaining component overrides to WithComponents
oliverlaz Apr 14, 2026
980fd64
perf: make WithComponents and useComponentsContext return stable refe…
oliverlaz Apr 14, 2026
b34c3f0
chore: remove accidentally committed test artifact
oliverlaz Apr 14, 2026
ac309ec
fix: resolve build and lint errors from component migration
oliverlaz Apr 14, 2026
af246b5
fix: remove redundant overrides
isekovanic Apr 14, 2026
48e52c7
Merge branch 'develop' into with-component-context
isekovanic Apr 14, 2026
d6b48a9
fix: lint md
isekovanic Apr 14, 2026
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
34 changes: 18 additions & 16 deletions examples/ExpoMessaging/app/channel/[cid]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
useChatContext,
ThreadContextValue,
MessageList,
WithComponents,
} from 'stream-chat-expo';
import { Stack, useLocalSearchParams, useRouter } from 'expo-router';
import { AuthProgressLoader } from '../../../components/AuthProgressLoader';
Expand Down Expand Up @@ -70,22 +71,23 @@ export default function ChannelScreen() {
<Stack.Screen
options={{ title: 'Channel Screen', contentStyle: { backgroundColor: 'white' } }}
/>
<Channel
audioRecordingEnabled={true}
channel={channel}
onPressMessage={onPressMessage}
keyboardVerticalOffset={headerHeight}
MessageLocation={MessageLocation}
thread={thread}
>
<MessageList
onThreadSelect={(thread: ThreadContextValue['thread']) => {
setThread(thread);
router.push(`/channel/${channel.cid}/thread/${thread?.cid ?? ''}`);
}}
/>
<MessageComposer InputButtons={InputButtons} />
</Channel>
<WithComponents overrides={{ MessageLocation, InputButtons }}>
<Channel
audioRecordingEnabled={true}
channel={channel}
onPressMessage={onPressMessage}
keyboardVerticalOffset={headerHeight}
thread={thread}
>
<MessageList
onThreadSelect={(thread: ThreadContextValue['thread']) => {
setThread(thread);
router.push(`/channel/${channel.cid}/thread/${thread?.cid ?? ''}`);
}}
/>
<MessageComposer />
</Channel>
</WithComponents>
</View>
);
}
Expand Down
5 changes: 3 additions & 2 deletions examples/ExpoMessaging/components/InputButtons.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React, { useState } from 'react';
import { Pressable, StyleSheet } from 'react-native';
import { Channel, InputButtons as DefaultInputButtons } from 'stream-chat-expo';
import type { ComponentOverrides } from 'stream-chat-expo';
import { InputButtons as DefaultInputButtons } from 'stream-chat-expo';
import { ShareLocationIcon } from '../icons/ShareLocationIcon';
import { LiveLocationCreateModal } from './LocationSharing/CreateLocationModal';

const InputButtons: NonNullable<React.ComponentProps<typeof Channel>['InputButtons']> = (props) => {
const InputButtons: NonNullable<ComponentOverrides['InputButtons']> = (props) => {
const [modalVisible, setModalVisible] = useState(false);

const onRequestClose = () => {
Expand Down
36 changes: 18 additions & 18 deletions examples/SampleApp/src/screens/ChannelListScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@ import {
View,
} from 'react-native';
import { useNavigation, useScrollToTop } from '@react-navigation/native';
import {
ChannelList,
useTheme,
useStableCallback,
ChannelActionItem,
} from 'stream-chat-react-native';
import { ChannelList, useTheme, useStableCallback, ChannelActionItem, WithComponents } from 'stream-chat-react-native';
import { Channel } from 'stream-chat';
import { ChannelPreview } from '../components/ChannelPreview';
import { ChatScreenHeader } from '../components/ChatScreenHeader';
Expand Down Expand Up @@ -254,18 +249,23 @@ export const ChannelListScreen: React.FC = () => {
)}
<View style={{ flex: searchQuery ? 0 : 1 }}>
<View style={[styles.channelListContainer, { opacity: searchQuery ? 0 : 1 }]}>
<ChannelList
additionalFlatListProps={additionalFlatListProps}
filters={filters}
HeaderNetworkDownIndicator={HeaderNetworkDownIndicator}
maxUnreadCount={99}
onSelect={onSelect}
options={options}
Preview={ChannelPreview}
setFlatListRef={setScrollRef}
getChannelActionItems={getChannelActionItems}
sort={sort}
/>
<WithComponents
overrides={{
HeaderNetworkDownIndicator,
Preview: ChannelPreview,
}}
>
<ChannelList
additionalFlatListProps={additionalFlatListProps}
filters={filters}
maxUnreadCount={99}
onSelect={onSelect}
options={options}
setFlatListRef={setScrollRef}
getChannelActionItems={getChannelActionItems}
sort={sort}
/>
</WithComponents>
</View>
</View>
</View>
Expand Down
14 changes: 10 additions & 4 deletions examples/SampleApp/src/screens/ChannelScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
MessageActionsParams,
ChannelAvatar,
PortalWhileClosingView,
WithComponents,
} from 'stream-chat-react-native';
import { Pressable, StyleSheet, View } from 'react-native';
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
Expand Down Expand Up @@ -265,19 +266,23 @@ export const ChannelScreen: React.FC<ChannelScreenProps> = ({ navigation, route

return (
<View style={[styles.flex, { backgroundColor: 'transparent' }]}>
<WithComponents
overrides={{
// AttachmentPickerSelectionBar: CustomAttachmentPickerSelectionBar,
AttachmentPickerContent: CustomAttachmentPickerContent,
MessageLocation,
NetworkDownIndicator: () => null,
}}
>
<Channel
audioRecordingEnabled={true}
// AttachmentPickerSelectionBar={CustomAttachmentPickerSelectionBar}
AttachmentPickerContent={CustomAttachmentPickerContent}
channel={channel}
messageInputFloating={messageInputFloating}
onPressMessage={onPressMessage}
initialScrollToFirstUnreadMessage
keyboardVerticalOffset={0}
messageActions={messageActions}
MessageLocation={MessageLocation}
messageId={messageId}
NetworkDownIndicator={() => null}
onAlsoSentToChannelHeaderPress={onAlsoSentToChannelHeaderPress}
thread={selectedThread}
maximumMessageLimit={messageListPruning}
Expand Down Expand Up @@ -306,6 +311,7 @@ export const ChannelScreen: React.FC<ChannelScreenProps> = ({ navigation, route
/>
)}
</Channel>
</WithComponents>
</View>
);
};
Expand Down
54 changes: 30 additions & 24 deletions examples/SampleApp/src/screens/NewDirectMessagingScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
MessageList,
UserAdd,
useTheme,
WithComponents,
} from 'stream-chat-react-native';

import { User } from '../icons/User';
Expand Down Expand Up @@ -338,32 +339,37 @@ export const NewDirectMessagingScreen: React.FC<NewDirectMessagingScreenProps> =
},
]}
>
<Channel
additionalTextInputProps={{
onFocus: () => {
setFocusOnMessageInput(true);
setFocusOnSearchInput(false);
if (messageInputRef.current) {
messageInputRef.current.focus();
}
},
<WithComponents
overrides={{
EmptyStateIndicator: EmptyMessagesIndicator,
SendButton: NewDirectMessagingSendButton,
}}
audioRecordingEnabled={true}
channel={currentChannel.current}
EmptyStateIndicator={EmptyMessagesIndicator}
enforceUniqueReaction
keyboardVerticalOffset={0}
onChangeText={setMessageInputText}
overrideOwnCapabilities={{ sendMessage: true }}
SendButton={NewDirectMessagingSendButton}
setInputRef={(ref) => (messageInputRef.current = ref)}
>
{renderUserSearch({ inSafeArea: true })}
{results && results.length >= 0 && !focusOnSearchInput && focusOnMessageInput && (
<MessageList />
)}
<MessageComposer />
</Channel>
<Channel
additionalTextInputProps={{
onFocus: () => {
setFocusOnMessageInput(true);
setFocusOnSearchInput(false);
if (messageInputRef.current) {
messageInputRef.current.focus();
}
},
}}
audioRecordingEnabled={true}
channel={currentChannel.current}
enforceUniqueReaction
keyboardVerticalOffset={0}
onChangeText={setMessageInputText}
overrideOwnCapabilities={{ sendMessage: true }}
setInputRef={(ref) => (messageInputRef.current = ref)}
>
{renderUserSearch({ inSafeArea: true })}
{results && results.length >= 0 && !focusOnSearchInput && focusOnMessageInput && (
<MessageList />
)}
<MessageComposer />
</Channel>
</WithComponents>
</SafeAreaView>
);
};
47 changes: 26 additions & 21 deletions examples/SampleApp/src/screens/SharedGroupsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { NavigationProp, RouteProp, useNavigation } from '@react-navigation/native';
import {
ChannelList,
ChannelListView,
ChannelListViewProps,
ChannelPreviewViewProps,
getChannelPreviewDisplayAvatar,
GroupAvatar,
Expand All @@ -13,6 +11,7 @@ import {
useTheme,
Avatar,
getInitialsFromName,
WithComponents,
} from 'stream-chat-react-native';

import { ScreenHeader } from '../components/ScreenHeader';
Expand Down Expand Up @@ -145,18 +144,19 @@ const EmptyListComponent = () => {
);
};

type ListComponentProps = ChannelListViewProps;

// If the length of channels is 1, which means we only got 1:1-distinct channel,
// And we don't want to show 1:1-distinct channel in this list.
const ListComponent: React.FC<ListComponentProps> = (props) => {
// Custom empty state that also shows when there's only the 1:1 direct channel
const SharedGroupsEmptyState = () => {
const { channels, loadingChannels, refreshing } = useChannelsContext();

if (channels && channels.length <= 1 && !loadingChannels && !refreshing) {
if (loadingChannels || refreshing) {
return null;
}

if (!channels || channels.length <= 1) {
return <EmptyListComponent />;
}

return <ChannelListView {...props} />;
return null;
};

type SharedGroupsScreenRouteProp = RouteProp<StackNavigatorParamList, 'SharedGroupsScreen'>;
Expand All @@ -179,19 +179,24 @@ export const SharedGroupsScreen: React.FC<SharedGroupsScreenProps> = ({
return (
<View style={styles.container}>
<ScreenHeader titleText='Shared Groups' />
<ChannelList
filters={{
$and: [{ members: { $in: [chatClient?.user?.id] } }, { members: { $in: [user.id] } }],
<WithComponents
overrides={{
EmptyStateIndicator: SharedGroupsEmptyState,
Preview: CustomPreview,
}}
List={ListComponent}
options={{
watch: false,
}}
Preview={CustomPreview}
sort={{
last_updated: -1,
}}
/>
>
<ChannelList
filters={{
$and: [{ members: { $in: [chatClient?.user?.id] } }, { members: { $in: [user.id] } }],
}}
options={{
watch: false,
}}
sort={{
last_updated: -1,
}}
/>
</WithComponents>
</View>
);
};
10 changes: 8 additions & 2 deletions examples/SampleApp/src/screens/ThreadScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
useTranslationContext,
useTypingString,
PortalWhileClosingView,
WithComponents,
} from 'stream-chat-react-native';
import { useStateStore } from 'stream-chat-react-native';

Expand Down Expand Up @@ -148,15 +149,19 @@ export const ThreadScreen: React.FC<ThreadScreenProps> = ({

return (
<View style={[styles.container, { backgroundColor: white }]}>
<WithComponents
overrides={{
// AttachmentPickerSelectionBar: CustomAttachmentPickerSelectionBar,
MessageLocation,
}}
>
<Channel
audioRecordingEnabled={true}
// AttachmentPickerSelectionBar={CustomAttachmentPickerSelectionBar}
channel={channel}
enforceUniqueReaction
keyboardVerticalOffset={0}
messageActions={messageActions}
messageInputFloating={messageInputFloating}
MessageLocation={MessageLocation}
onPressMessage={onPressMessage}
thread={thread}
threadList
Expand All @@ -174,6 +179,7 @@ export const ThreadScreen: React.FC<ThreadScreenProps> = ({
shouldUseFlashList={messageListImplementation === 'flashlist'}
/>
</Channel>
</WithComponents>
</View>
);
};
Binary file removed package/foobar.db-journal
Binary file not shown.
Loading
Loading