Skip to content

Commit a007d4a

Browse files
committed
fix: message input focus responsiveness
1 parent 1ceaf7f commit a007d4a

File tree

7 files changed

+53
-21
lines changed

7 files changed

+53
-21
lines changed

package/src/components/Channel/Channel.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ export type ChannelPropsWithContext = Pick<ChannelContextValue, 'channel'> &
304304
| 'CardCover'
305305
| 'CardFooter'
306306
| 'CardHeader'
307+
| 'customMessageSwipeAction'
307308
| 'DateHeader'
308309
| 'deletedMessagesVisibilityType'
309310
| 'disableTypingIndicator'
@@ -550,6 +551,7 @@ const ChannelWithContext = (props: PropsWithChildren<ChannelPropsWithContext>) =
550551
compressImageQuality,
551552
CooldownTimer = CooldownTimerDefault,
552553
CreatePollContent,
554+
customMessageSwipeAction,
553555
DateHeader = DateHeaderDefault,
554556
deletedMessagesVisibilityType = 'always',
555557
disableKeyboardCompatibleView = false,
@@ -1814,6 +1816,7 @@ const ChannelWithContext = (props: PropsWithChildren<ChannelPropsWithContext>) =
18141816
CardFooter,
18151817
CardHeader,
18161818
channelId,
1819+
customMessageSwipeAction,
18171820
DateHeader,
18181821
deletedMessagesVisibilityType,
18191822
deleteMessage,

package/src/components/Channel/hooks/useCreateMessagesContext.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const useCreateMessagesContext = ({
1212
CardFooter,
1313
CardHeader,
1414
channelId,
15+
customMessageSwipeAction,
1516
DateHeader,
1617
deletedMessagesVisibilityType,
1718
deleteMessage,
@@ -128,6 +129,7 @@ export const useCreateMessagesContext = ({
128129
CardCover,
129130
CardFooter,
130131
CardHeader,
132+
customMessageSwipeAction,
131133
DateHeader,
132134
deletedMessagesVisibilityType,
133135
deleteMessage,

package/src/components/Message/MessageSimple/MessageSimple.tsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useCallback, useMemo, useState } from 'react';
1+
import React, { useMemo, useState } from 'react';
22
import { Dimensions, LayoutChangeEvent, StyleSheet, View } from 'react-native';
33

44
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
@@ -24,6 +24,7 @@ import {
2424
} from '../../../contexts/messagesContext/MessagesContext';
2525
import { useTheme } from '../../../contexts/themeContext/ThemeContext';
2626

27+
import { useStableCallback } from '../../../hooks/useStableCallback';
2728
import { NativeHandlers } from '../../../native';
2829

2930
import { checkMessageEquality, checkQuotedMessageEquality } from '../../../utils/utils';
@@ -74,6 +75,7 @@ export type MessageSimplePropsWithContext = Pick<
7475
> &
7576
Pick<
7677
MessagesContextValue,
78+
| 'customMessageSwipeAction'
7779
| 'enableMessageGroupingByUser'
7880
| 'enableSwipeToReply'
7981
| 'myMessageTheme'
@@ -106,6 +108,8 @@ const MessageSimpleWithContext = (props: MessageSimplePropsWithContext) => {
106108
const { width } = Dimensions.get('screen');
107109
const {
108110
alignment,
111+
channel,
112+
customMessageSwipeAction,
109113
enableMessageGroupingByUser,
110114
enableSwipeToReply,
111115
groupStyles,
@@ -215,9 +219,13 @@ const MessageSimpleWithContext = (props: MessageSimplePropsWithContext) => {
215219
shouldRenderSwipeableWrapper,
216220
);
217221

218-
const onSwipeToReply = useCallback(() => {
222+
const onSwipeActionHandler = useStableCallback(() => {
223+
if (customMessageSwipeAction) {
224+
customMessageSwipeAction({ channel, message });
225+
return;
226+
}
219227
setQuotedMessage(message);
220-
}, [setQuotedMessage, message]);
228+
});
221229

222230
const THRESHOLD = 25;
223231

@@ -260,7 +268,7 @@ const MessageSimpleWithContext = (props: MessageSimplePropsWithContext) => {
260268
})
261269
.onEnd(() => {
262270
if (translateX.value >= THRESHOLD) {
263-
runOnJS(onSwipeToReply)();
271+
runOnJS(onSwipeActionHandler)();
264272
if (triggerHaptic) {
265273
runOnJS(triggerHaptic)('impactMedium');
266274
}
@@ -284,7 +292,7 @@ const MessageSimpleWithContext = (props: MessageSimplePropsWithContext) => {
284292
[
285293
isSwiping,
286294
messageSwipeToReplyHitSlop,
287-
onSwipeToReply,
295+
onSwipeActionHandler,
288296
touchStart,
289297
translateX,
290298
triggerHaptic,
@@ -603,6 +611,7 @@ export const MessageSimple = (props: MessageSimpleProps) => {
603611
setQuotedMessage,
604612
} = useMessageContext();
605613
const {
614+
customMessageSwipeAction,
606615
enableMessageGroupingByUser,
607616
enableSwipeToReply,
608617
MessageAvatar,
@@ -631,6 +640,7 @@ export const MessageSimple = (props: MessageSimpleProps) => {
631640
{...{
632641
alignment,
633642
channel,
643+
customMessageSwipeAction,
634644
enableMessageGroupingByUser,
635645
enableSwipeToReply,
636646
groupStyles,

package/src/components/MessageInput/MessageInput.tsx

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import React, { useCallback, useEffect, useMemo, useState } from 'react';
2-
import { Modal, SafeAreaView, StyleSheet, TextInput, TextInputProps, View } from 'react-native';
2+
import {
3+
Modal,
4+
Pressable,
5+
SafeAreaView,
6+
StyleSheet,
7+
TextInput,
8+
TextInputProps,
9+
View,
10+
} from 'react-native';
311

412
import {
513
Gesture,
@@ -52,6 +60,7 @@ import {
5260
useTranslationContext,
5361
} from '../../contexts/translationContext/TranslationContext';
5462

63+
import { useStableCallback } from '../../hooks/useStableCallback';
5564
import { useStateStore } from '../../hooks/useStateStore';
5665
import {
5766
isAudioRecorderAvailable,
@@ -432,6 +441,10 @@ const MessageInputWithContext = (props: MessageInputPropsWithContext) => {
432441
const shouldDisplayStopAIGeneration =
433442
[AIStates.Thinking, AIStates.Generating].includes(aiState) && !!StopMessageStreamingButton;
434443

444+
const onFocusHandler = useStableCallback(() => {
445+
inputBoxRef.current?.focus();
446+
});
447+
435448
return (
436449
<>
437450
<View
@@ -489,7 +502,8 @@ const MessageInputWithContext = (props: MessageInputPropsWithContext) => {
489502
<View style={[styles.optionsContainer, optionsContainer]}>
490503
{InputButtons && <InputButtons />}
491504
</View>
492-
<View
505+
<Pressable
506+
onPress={onFocusHandler}
493507
style={[
494508
styles.inputBoxContainer,
495509
{
@@ -517,7 +531,7 @@ const MessageInputWithContext = (props: MessageInputPropsWithContext) => {
517531
/>
518532
</View>
519533
)}
520-
</View>
534+
</Pressable>
521535
</>
522536
)}
523537

package/src/components/MessageList/MessageList.tsx

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,23 +1143,14 @@ const MessageListWithContext = (props: MessageListPropsWithContext) => {
11431143
}
11441144
}
11451145

1146-
const ItemSeparatorComponent = additionalFlatListProps?.ItemSeparatorComponent;
1147-
const WrappedItemSeparatorComponent = useCallback(() => {
1148-
return ItemSeparatorComponent ? <ItemSeparatorComponent /> : null;
1149-
}, [ItemSeparatorComponent]);
1150-
11511146
// We need to omit the style related props from the additionalFlatListProps and add them directly instead of spreading
11521147
let additionalFlatListPropsExcludingStyle:
1153-
| Omit<
1154-
NonNullable<typeof additionalFlatListProps>,
1155-
'style' | 'contentContainerStyle' | 'ItemSeparatorComponent'
1156-
>
1148+
| Omit<NonNullable<typeof additionalFlatListProps>, 'style' | 'contentContainerStyle'>
11571149
| undefined;
11581150

11591151
if (additionalFlatListProps) {
11601152
// eslint-disable-next-line @typescript-eslint/no-unused-vars
1161-
const { contentContainerStyle, ItemSeparatorComponent, style, ...rest } =
1162-
additionalFlatListProps;
1153+
const { contentContainerStyle, style, ...rest } = additionalFlatListProps;
11631154
additionalFlatListPropsExcludingStyle = rest;
11641155
}
11651156

@@ -1206,7 +1197,6 @@ const MessageListWithContext = (props: MessageListPropsWithContext) => {
12061197
data={processedMessageList}
12071198
extraData={disabled}
12081199
inverted={inverted}
1209-
ItemSeparatorComponent={WrappedItemSeparatorComponent}
12101200
keyboardShouldPersistTaps='handled'
12111201
keyExtractor={keyExtractor}
12121202
ListFooterComponent={FooterComponent}

package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ exports[`Thread should match thread snapshot 1`] = `
3434
testID="message-flat-list-wrapper"
3535
>
3636
<RCTScrollView
37-
ItemSeparatorComponent={[Function]}
3837
ListFooterComponent={null}
3938
ListHeaderComponent={[Function]}
4039
contentContainerStyle={

package/src/contexts/messagesContext/MessagesContext.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { PressableProps, ViewProps } from 'react-native';
44

55
import type {
66
Attachment,
7+
Channel,
78
ChannelState,
89
CommandSuggestion,
910
LocalMessage,
@@ -362,6 +363,19 @@ export type MessagesContextValue = Pick<MessageContextValue, 'isMessageAIGenerat
362363
*/
363364
CardHeader?: React.ComponentType<CardProps>;
364365

366+
/**
367+
* Custom handler to handle message swipe action.
368+
*
369+
* The default behaviour is swipe to reply for this.
370+
*/
371+
customMessageSwipeAction?: ({
372+
channel,
373+
message,
374+
}: {
375+
channel: Channel;
376+
message: LocalMessage;
377+
}) => void;
378+
365379
/**
366380
* Full override of the delete message button in the Message Actions
367381
*

0 commit comments

Comments
 (0)