[🐛] The InputBox and SendButton goes wrong when users copy and paste multiple times in the textarea
Issue
The send button doesn't activate when users copy and paste multiple times. The textarea also should expand depending on the number of lines. However, it doesn't change either. Once the user starts editing in the situation, the send button is activated and the textarea is expanded
Steps to reproduce
Steps to reproduce the behavior:
- Go to any channels
- Copy and paste a previous message in textarea
- Send it to the chat
- Copy and paste a previous message in textarea again
Expected behavior
InputBox and SendButton should work properly regardless to the number of copying and pasting
Project Related Information
Customization
Click To Expand
- Create sample app using it as a reference
import React, { useContext, useEffect, useMemo, useState } from 'react';
import { I18nManager, LogBox, Platform, SafeAreaView, useColorScheme, View } from 'react-native';
import { DarkTheme, DefaultTheme, NavigationContainer, RouteProp } from '@react-navigation/native';
import { createStackNavigator, StackNavigationProp } from '@react-navigation/stack';
import { useHeaderHeight } from '@react-navigation/elements';
import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context';
import { Channel as ChannelType, ChannelSort, StreamChat } from 'stream-chat';
import {
Channel,
ChannelList,
Chat,
MessageInput,
MessageList,
OverlayProvider,
Streami18n,
Thread,
ThreadContextValue,
useAttachmentPickerContext,
useOverlayContext,
} from 'stream-chat-expo';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { useStreamChatTheme } from './src/hooks/useStreamChatTheme';
LogBox.ignoreAllLogs(true);
type LocalAttachmentType = Record<string, unknown>;
type LocalChannelType = Record<string, unknown>;
type LocalCommandType = string;
type LocalEventType = Record<string, unknown>;
type LocalMessageType = Record<string, unknown>;
type LocalReactionType = Record<string, unknown>;
type LocalUserType = Record<string, unknown>;
type StreamChatGenerics = {
attachmentType: LocalAttachmentType;
channelType: LocalChannelType;
commandType: LocalCommandType;
eventType: LocalEventType;
messageType: LocalMessageType;
reactionType: LocalReactionType;
userType: LocalUserType;
};
const options = {
presence: true,
state: true,
watch: true,
limit: 30,
};
I18nManager.forceRTL(false);
const chatClient = StreamChat.getInstance<StreamChatGenerics>('MY_APP_ID');
const userToken = 'MY_USER_TOKEN';
const user = {
id: 'MY_USER_ID',
};
const filters = {
members: { $in: ['MY_USER_ID''] },
type: 'Coaching',
};
const sort: ChannelSort<StreamChatGenerics> = { last_updated: -1 };
/**
* Start playing with streami18n instance here:
* Please refer to description of this PR for details: https://github.com/GetStream/stream-chat-react-native/pull/150
*/
const streami18n = new Streami18n({
language: 'en',
});
type ChannelListScreenProps = {
navigation: StackNavigationProp<NavigationParamsList, 'ChannelList'>;
};
const ChannelListScreen: React.FC<ChannelListScreenProps> = ({ navigation }) => {
const { setChannel } = useContext(AppContext);
const memoizedFilters = useMemo(() => filters, []);
return (
<View style={{ height: '100%' }}>
<ChannelList<StreamChatGenerics>
filters={memoizedFilters}
onSelect={(channel) => {
setChannel(channel);
navigation.navigate('Channel');
}}
options={options}
sort={sort}
/>
</View>
);
};
type ChannelScreenProps = {
navigation: StackNavigationProp<NavigationParamsList, 'Channel'>;
};
const ChannelScreen: React.FC<ChannelScreenProps> = ({ navigation }) => {
const { channel, setThread, thread } = useContext(AppContext);
const headerHeight = useHeaderHeight();
const { setTopInset } = useAttachmentPickerContext();
const { overlay } = useOverlayContext();
useEffect(() => {
navigation.setOptions({
gestureEnabled: Platform.OS === 'ios' && overlay === 'none',
});
}, [overlay]);
useEffect(() => {
setTopInset(headerHeight);
}, [headerHeight]);
if (channel === undefined) {
return null;
}
return (
<SafeAreaView>
<Channel channel={channel} keyboardVerticalOffset={headerHeight} thread={thread}>
<View style={{ flex: 1 }}>
<MessageList<StreamChatGenerics>
onThreadSelect={(thread) => {
setThread(thread);
if (channel?.id) {
navigation.navigate('Thread');
}
}}
/>
<MessageInput />
</View>
</Channel>
</SafeAreaView>
);
};
type ThreadScreenProps = {
navigation: StackNavigationProp<ThreadRoute, 'Thread'>;
route: RouteProp<ThreadRoute, 'Thread'>;
};
const ThreadScreen: React.FC<ThreadScreenProps> = ({ navigation }) => {
const { channel, setThread, thread } = useContext(AppContext);
const headerHeight = useHeaderHeight();
const { overlay } = useOverlayContext();
useEffect(() => {
navigation.setOptions({
gestureEnabled: Platform.OS === 'ios' && overlay === 'none',
});
}, [overlay]);
if (!channel) return null;
return (
<SafeAreaView>
<Channel channel={channel} keyboardVerticalOffset={headerHeight} thread={thread} threadList>
<View
style={{
flex: 1,
justifyContent: 'flex-start',
}}
>
<Thread<StreamChatGenerics> onThreadDismount={() => setThread(null)} />
</View>
</Channel>
</SafeAreaView>
);
};
type ChannelRoute = { Channel: undefined };
type ChannelListRoute = { ChannelList: undefined };
type ThreadRoute = { Thread: undefined };
type NavigationParamsList = ChannelRoute & ChannelListRoute & ThreadRoute;
const Stack = createStackNavigator<NavigationParamsList>();
type AppContextType = {
channel: ChannelType<StreamChatGenerics> | undefined;
setChannel: React.Dispatch<React.SetStateAction<ChannelType<StreamChatGenerics> | undefined>>;
setThread: React.Dispatch<
React.SetStateAction<ThreadContextValue<StreamChatGenerics>['thread'] | undefined>
>;
thread: ThreadContextValue<StreamChatGenerics>['thread'] | undefined;
};
const AppContext = React.createContext({} as AppContextType);
const App = () => {
const colorScheme = useColorScheme();
const { bottom } = useSafeAreaInsets();
const theme = useStreamChatTheme();
const [channel, setChannel] = useState<ChannelType<StreamChatGenerics>>();
const [clientReady, setClientReady] = useState(false);
const [thread, setThread] = useState<ThreadContextValue<StreamChatGenerics>['thread']>();
useEffect(() => {
const setupClient = async () => {
const connectPromise = chatClient.connectUser(user, userToken);
setClientReady(true);
await connectPromise;
};
setupClient();
}, []);
return (
<NavigationContainer
theme={{
colors: {
...(colorScheme === 'dark' ? DarkTheme : DefaultTheme).colors,
background: theme.colors?.white_snow || '#FCFCFC',
},
dark: colorScheme === 'dark',
}}
>
<AppContext.Provider value={{ channel, setChannel, setThread, thread }}>
<GestureHandlerRootView style={{ flex: 1 }}>
<OverlayProvider<StreamChatGenerics>
bottomInset={bottom}
i18nInstance={streami18n}
value={{ style: theme }}
>
<Chat client={chatClient} i18nInstance={streami18n}>
{clientReady && (
<Stack.Navigator
initialRouteName='ChannelList'
screenOptions={{
headerTitleStyle: { alignSelf: 'center', fontWeight: 'bold' },
}}
>
<Stack.Screen
component={ChannelScreen}
name='Channel'
options={() => ({
headerBackTitle: 'Back',
headerRight: () => <></>,
headerTitle: channel?.data?.name,
})}
/>
<Stack.Screen
component={ChannelListScreen}
name='ChannelList'
options={{ headerTitle: 'Channel List' }}
/>
<Stack.Screen
component={ThreadScreen}
name='Thread'
options={() => ({ headerBackTitle: 'back' })}
/>
</Stack.Navigator>
)}
</Chat>
</OverlayProvider>
</GestureHandlerRootView>
</AppContext.Provider>
</NavigationContainer>
);
};
export default () => {
const theme = useStreamChatTheme();
return (
<SafeAreaProvider style={{ backgroundColor: theme.colors?.white_snow || '#FCFCFC' }}>
<App />
</SafeAreaProvider>
);
};
Offline support
- [ ] I have enabled offline support.
- [x] The feature I'm having does not occur when offline support is disabled. (stripe out if not applicable)
Environment
Click To Expand
package.json:
"dependencies": {
"@expo/vector-icons": "^13.0.0",
"@react-navigation/elements": "^1.3.3",
"@react-navigation/native": "^6.0.10",
"@react-navigation/stack": "^6.2.1",
"expo": "^48.0.0",
"expo-application": "~5.1.1",
"expo-av": "~13.2.1",
"expo-clipboard": "~4.1.2",
"expo-constants": "~14.2.1",
"expo-dev-client": "~2.2.1",
"expo-document-picker": "~11.2.2",
"expo-file-system": "~15.2.2",
"expo-haptics": "~12.2.1",
"expo-image-manipulator": "~11.1.1",
"expo-image-picker": "~14.1.1",
"expo-keep-awake": "~12.0.1",
"expo-linking": "~4.0.1",
"expo-localization": "~14.1.1",
"expo-location": "~15.1.1",
"expo-media-library": "~15.2.3",
"expo-sharing": "~11.2.2",
"expo-splash-screen": "~0.18.2",
"expo-status-bar": "~1.4.4",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-native": "0.71.8",
"react-native-safe-area-context": "4.5.0",
"react-native-screens": "~3.20.0",
"react-native-storage": "^1.0.1",
"react-native-svg": "13.4.0",
"react-native-web": "~0.18.7",
"stream-chat-expo": "5.22.1",
},
react-native info output:
OUTPUT GOES HERE
-
Platform that you're experiencing the issue on:
- [x] iOS
- [ ] Android
- [ ] iOS but have not tested behavior on Android
- [ ] Android but have not tested behavior on iOS
- [ ] Both
-
stream-chat-react-nativeversion you're using that has this issue:-
"stream-chat-expo": "5.22.1"
-
- Device/Emulator info:
- [x] I am using a physical device
- OS version:
iOS 16.1.1,Android13,Android14,Android15 - Device/Emulator:
iPhone 12,Pixel 3a,Pixel 4,Pixel6
Additional context
Screenshots
Click To Expand
Hey @atsss, this isn't reproducible for us on the iPhone simulator as the one that you have shared in the video.
Ref:
https://github.com/GetStream/stream-chat-react-native/assets/39884168/1e85e04a-f286-419f-bbbe-977569100191
@khushal87 Thanks for your response. It's happening to me both simulators and real devices. Can you share your code which doesn't have problems and the simulator/OS version? I'm having this problem with the following sample code. I just copied and pasted the sample and changed app credentials.
https://github.com/GetStream/stream-chat-react-native/blob/4250706d374e06267e161b410bd8d1b2ef0b4896/examples/TypeScriptMessaging/App.tsx
Closing this issue because of not being able to reproduce it. Please feel free to open it if you see it's still relevant. Test it on our example apps as well.