@sendbird/uikit-react-native 3.10.1 → 3.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/components/ChannelInput/EditInput.js +5 -3
- package/lib/commonjs/components/ChannelInput/EditInput.js.map +1 -1
- package/lib/commonjs/components/ChannelInput/SendInput.js +19 -4
- package/lib/commonjs/components/ChannelInput/SendInput.js.map +1 -1
- package/lib/commonjs/components/ChannelInput/index.js +16 -4
- package/lib/commonjs/components/ChannelInput/index.js.map +1 -1
- package/lib/commonjs/domain/groupChannel/component/GroupChannelMessageList.js +29 -5
- package/lib/commonjs/domain/groupChannel/component/GroupChannelMessageList.js.map +1 -1
- package/lib/commonjs/domain/groupChannel/module/moduleContext.js +36 -2
- package/lib/commonjs/domain/groupChannel/module/moduleContext.js.map +1 -1
- package/lib/commonjs/domain/groupChannel/types.js.map +1 -1
- package/lib/commonjs/fragments/createGroupChannelFragment.js +3 -1
- package/lib/commonjs/fragments/createGroupChannelFragment.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/commonjs/version.js.map +1 -1
- package/lib/module/components/ChannelInput/EditInput.js +5 -3
- package/lib/module/components/ChannelInput/EditInput.js.map +1 -1
- package/lib/module/components/ChannelInput/SendInput.js +20 -5
- package/lib/module/components/ChannelInput/SendInput.js.map +1 -1
- package/lib/module/components/ChannelInput/index.js +17 -5
- package/lib/module/components/ChannelInput/index.js.map +1 -1
- package/lib/module/domain/groupChannel/component/GroupChannelMessageList.js +29 -5
- package/lib/module/domain/groupChannel/component/GroupChannelMessageList.js.map +1 -1
- package/lib/module/domain/groupChannel/module/moduleContext.js +36 -2
- package/lib/module/domain/groupChannel/module/moduleContext.js.map +1 -1
- package/lib/module/domain/groupChannel/types.js.map +1 -1
- package/lib/module/fragments/createGroupChannelFragment.js +3 -1
- package/lib/module/fragments/createGroupChannelFragment.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/module/version.js.map +1 -1
- package/lib/typescript/src/components/ChannelInput/index.d.ts +2 -1
- package/lib/typescript/src/containers/SendbirdUIKitContainer.d.ts +1 -1
- package/lib/typescript/src/domain/groupChannel/component/GroupChannelInput.d.ts +1 -1
- package/lib/typescript/src/domain/groupChannel/types.d.ts +12 -1
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +5 -5
- package/src/components/ChannelInput/EditInput.tsx +2 -0
- package/src/components/ChannelInput/SendInput.tsx +16 -1
- package/src/components/ChannelInput/index.tsx +37 -5
- package/src/domain/groupChannel/component/GroupChannelMessageList.tsx +25 -4
- package/src/domain/groupChannel/module/moduleContext.tsx +40 -5
- package/src/domain/groupChannel/types.ts +14 -1
- package/src/fragments/createGroupChannelFragment.tsx +2 -0
- package/src/version.ts +1 -1
|
@@ -31,6 +31,7 @@ export interface GroupChannelProps {
|
|
|
31
31
|
flatListProps?: GroupChannelProps['MessageList']['flatListProps'];
|
|
32
32
|
sortComparator?: UseGroupChannelMessagesOptions['sortComparator'];
|
|
33
33
|
searchItem?: GroupChannelProps['MessageList']['searchItem'];
|
|
34
|
+
partialTextInputProps?: GroupChannelProps['Input']['partialTextInputProps'];
|
|
34
35
|
/**
|
|
35
36
|
* @description You can specify the query parameters for the message list.
|
|
36
37
|
* @example
|
|
@@ -57,7 +58,7 @@ export interface GroupChannelProps {
|
|
|
57
58
|
onNewLineSeenChange?: (hasSeenNewLine: boolean) => void;
|
|
58
59
|
onUserMarkedAsUnreadChange?: (hasUserMarkedAsUnread: boolean) => void;
|
|
59
60
|
};
|
|
60
|
-
Input: PickPartial<ChannelInputProps, 'shouldRenderInput' | 'onPressSendUserMessage' | 'onPressSendFileMessage' | 'onPressUpdateUserMessage' | 'onPressUpdateFileMessage' | 'SuggestedMentionList' | 'AttachmentsButton', 'inputDisabled'>;
|
|
61
|
+
Input: PickPartial<ChannelInputProps, 'shouldRenderInput' | 'onPressSendUserMessage' | 'onPressSendFileMessage' | 'onPressUpdateUserMessage' | 'onPressUpdateFileMessage' | 'SuggestedMentionList' | 'AttachmentsButton' | 'partialTextInputProps', 'inputDisabled'>;
|
|
61
62
|
SuggestedMentionList: SuggestedMentionListProps;
|
|
62
63
|
Provider: {
|
|
63
64
|
channel: SendbirdGroupChannel;
|
|
@@ -129,6 +130,16 @@ export interface GroupChannelContextsType {
|
|
|
129
130
|
timeout?: number;
|
|
130
131
|
viewPosition?: number;
|
|
131
132
|
}) => void;
|
|
133
|
+
/**
|
|
134
|
+
* Call the FlatList function asynchronously to scroll to a message by messageId lazily.
|
|
135
|
+
* to avoid scrolling before data rendering has been committed.
|
|
136
|
+
* */
|
|
137
|
+
lazyScrollToMessageId: (params?: {
|
|
138
|
+
messageId?: number;
|
|
139
|
+
animated?: boolean;
|
|
140
|
+
timeout?: number;
|
|
141
|
+
viewPosition?: number;
|
|
142
|
+
}) => void;
|
|
132
143
|
onPressReplyMessageInThread?: (parentMessage: SendbirdSendableMessage, startingPoint?: number) => void;
|
|
133
144
|
}>;
|
|
134
145
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const VERSION = "3.10.
|
|
1
|
+
declare const VERSION = "3.10.3";
|
|
2
2
|
export default VERSION;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sendbird/uikit-react-native",
|
|
3
|
-
"version": "3.10.
|
|
3
|
+
"version": "3.10.3",
|
|
4
4
|
"description": "Sendbird UIKit for React Native: A feature-rich and customizable chat UI kit with messaging, channel management, and user authentication.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sendbird",
|
|
@@ -60,10 +60,10 @@
|
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
62
|
"@openspacelabs/react-native-zoomable-view": "^2.1.5",
|
|
63
|
-
"@sendbird/uikit-chat-hooks": "3.10.
|
|
64
|
-
"@sendbird/uikit-react-native-foundation": "3.10.
|
|
63
|
+
"@sendbird/uikit-chat-hooks": "3.10.3",
|
|
64
|
+
"@sendbird/uikit-react-native-foundation": "3.10.3",
|
|
65
65
|
"@sendbird/uikit-tools": "0.0.15",
|
|
66
|
-
"@sendbird/uikit-utils": "3.10.
|
|
66
|
+
"@sendbird/uikit-utils": "3.10.3"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@bam.tech/react-native-image-resizer": "^3.0.4",
|
|
@@ -218,5 +218,5 @@
|
|
|
218
218
|
]
|
|
219
219
|
]
|
|
220
220
|
},
|
|
221
|
-
"gitHead": "
|
|
221
|
+
"gitHead": "2f85a74e995069845ec6876d1339a66b299b642b"
|
|
222
222
|
}
|
|
@@ -31,6 +31,7 @@ const EditInput = forwardRef<RNTextInput, EditInputProps>(function EditInput(
|
|
|
31
31
|
autoFocus,
|
|
32
32
|
mentionedUsers,
|
|
33
33
|
inputDisabled,
|
|
34
|
+
partialTextInputProps,
|
|
34
35
|
},
|
|
35
36
|
ref,
|
|
36
37
|
) {
|
|
@@ -70,6 +71,7 @@ const EditInput = forwardRef<RNTextInput, EditInputProps>(function EditInput(
|
|
|
70
71
|
<View style={styles.editInputContainer}>
|
|
71
72
|
<View style={styles.inputWrapper}>
|
|
72
73
|
<TextInput
|
|
74
|
+
{...partialTextInputProps}
|
|
73
75
|
ref={ref}
|
|
74
76
|
multiline
|
|
75
77
|
disableFullscreenUI
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { forwardRef } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
NativeSyntheticEvent,
|
|
4
|
+
Platform,
|
|
4
5
|
TextInput as RNTextInput,
|
|
5
6
|
TextInputSelectionChangeEventData,
|
|
6
7
|
TouchableOpacity,
|
|
@@ -54,6 +55,7 @@ const SendInput = forwardRef<RNTextInput, SendInputProps>(function SendInput(
|
|
|
54
55
|
messageToReply,
|
|
55
56
|
setMessageToReply,
|
|
56
57
|
messageForThread,
|
|
58
|
+
partialTextInputProps,
|
|
57
59
|
},
|
|
58
60
|
ref,
|
|
59
61
|
) {
|
|
@@ -116,7 +118,19 @@ const SendInput = forwardRef<RNTextInput, SendInputProps>(function SendInput(
|
|
|
116
118
|
...messageReplyParams,
|
|
117
119
|
}).catch(onFailureToSend);
|
|
118
120
|
|
|
119
|
-
onChangeText('')
|
|
121
|
+
// On iOS with autoCorrect enabled, calling onChangeText('') immediately after sending
|
|
122
|
+
// can be ignored due to the keyboard's autocorrect not being committed yet.
|
|
123
|
+
// Delay the clear call slightly to allow the autocorrected text to be applied first.
|
|
124
|
+
if (Platform.OS === 'ios') {
|
|
125
|
+
const textInputRef = ref as React.MutableRefObject<RNTextInput | undefined>;
|
|
126
|
+
if (textInputRef.current) {
|
|
127
|
+
setTimeout(() => {
|
|
128
|
+
onChangeText('');
|
|
129
|
+
}, 10);
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
onChangeText('');
|
|
133
|
+
}
|
|
120
134
|
setMessageToReply?.();
|
|
121
135
|
};
|
|
122
136
|
|
|
@@ -186,6 +200,7 @@ const SendInput = forwardRef<RNTextInput, SendInputProps>(function SendInput(
|
|
|
186
200
|
<View style={styles.sendInputContainer}>
|
|
187
201
|
{AttachmentsButton && <AttachmentsButton onPress={() => openSheet({ sheetItems })} disabled={inputDisabled} />}
|
|
188
202
|
<TextInput
|
|
203
|
+
{...partialTextInputProps}
|
|
189
204
|
ref={ref}
|
|
190
205
|
multiline
|
|
191
206
|
disableFullscreenUI
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Keyboard,
|
|
4
|
+
KeyboardAvoidingView,
|
|
5
|
+
Platform,
|
|
6
|
+
StyleProp,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
TextInput,
|
|
9
|
+
TextInputProps,
|
|
10
|
+
TextStyle,
|
|
11
|
+
View,
|
|
12
|
+
} from 'react-native';
|
|
3
13
|
|
|
4
14
|
import { createStyleSheet, useUIKitTheme } from '@sendbird/uikit-react-native-foundation';
|
|
5
15
|
import {
|
|
@@ -79,13 +89,16 @@ export type ChannelInputProps = {
|
|
|
79
89
|
AttachmentsButton?: (props: AttachmentsButtonProps) => React.ReactNode | null;
|
|
80
90
|
MessageToReplyPreview?: (props: MessageToReplyPreviewProps) => React.ReactNode | null;
|
|
81
91
|
VoiceMessageInput?: (props: VoiceMessageInputProps) => React.ReactNode | null;
|
|
92
|
+
|
|
93
|
+
// TextInput props - only safe properties that don't interfere with UIKit functionality
|
|
94
|
+
partialTextInputProps?: Partial<Pick<TextInputProps, 'autoCorrect'>>;
|
|
82
95
|
};
|
|
83
96
|
|
|
84
97
|
const AUTO_FOCUS = Platform.select({ ios: false, android: true, default: false });
|
|
85
|
-
const
|
|
98
|
+
const isAndroidApi35Plus = Platform.OS === 'android' && Platform.Version >= 35;
|
|
86
99
|
const KEYBOARD_AVOID_VIEW_BEHAVIOR = Platform.select({
|
|
87
100
|
ios: 'padding' as const,
|
|
88
|
-
android:
|
|
101
|
+
android: isAndroidApi35Plus ? ('padding' as const) : undefined,
|
|
89
102
|
default: undefined,
|
|
90
103
|
});
|
|
91
104
|
|
|
@@ -109,7 +122,9 @@ const ChannelInput = (props: ChannelInputProps) => {
|
|
|
109
122
|
* For older Android versions, we manually subtract the safe area bottom padding to avoid overlapping with system UI.
|
|
110
123
|
* See: https://developer.android.com/develop/ui/views/layout/edge-to-edge
|
|
111
124
|
*/
|
|
112
|
-
const keyboardVerticalOffset =
|
|
125
|
+
const keyboardVerticalOffset = isAndroidApi35Plus
|
|
126
|
+
? keyboardAvoidOffset
|
|
127
|
+
: -safeArea.paddingBottom + keyboardAvoidOffset;
|
|
113
128
|
const { colors, typography } = useUIKitTheme();
|
|
114
129
|
const { sbOptions, mentionManager } = useSendbirdChat();
|
|
115
130
|
|
|
@@ -146,6 +161,23 @@ const ChannelInput = (props: ChannelInputProps) => {
|
|
|
146
161
|
onChangeText(replace(text, searchStringRange.start, searchStringRange.end, mentionedMessageText), { user, range });
|
|
147
162
|
};
|
|
148
163
|
|
|
164
|
+
const [keyboardShown, setKeyboardShown] = useState(false);
|
|
165
|
+
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
const keyboardDidShow = () => setKeyboardShown(true);
|
|
168
|
+
const keyboardDidHide = () => setKeyboardShown(false);
|
|
169
|
+
|
|
170
|
+
const showSubscription = Keyboard.addListener('keyboardDidShow', keyboardDidShow);
|
|
171
|
+
const hideSubscription = Keyboard.addListener('keyboardDidHide', keyboardDidHide);
|
|
172
|
+
|
|
173
|
+
return () => {
|
|
174
|
+
showSubscription.remove();
|
|
175
|
+
hideSubscription.remove();
|
|
176
|
+
};
|
|
177
|
+
}, []);
|
|
178
|
+
|
|
179
|
+
const shouldShowSafeAreaBottom = !isAndroidApi35Plus || (isAndroidApi35Plus && !keyboardShown);
|
|
180
|
+
|
|
149
181
|
if (!props.shouldRenderInput) {
|
|
150
182
|
return <SafeAreaBottom height={safeArea.paddingBottom} />;
|
|
151
183
|
}
|
|
@@ -192,7 +224,7 @@ const ChannelInput = (props: ChannelInputProps) => {
|
|
|
192
224
|
/>
|
|
193
225
|
)}
|
|
194
226
|
</View>
|
|
195
|
-
{
|
|
227
|
+
{shouldShowSafeAreaBottom && <SafeAreaBottom height={safeArea.paddingBottom} />}
|
|
196
228
|
</View>
|
|
197
229
|
</KeyboardAvoidingView>
|
|
198
230
|
{mentionAvailable && props.SuggestedMentionList && (
|
|
@@ -26,7 +26,7 @@ const GroupChannelMessageList = (props: GroupChannelProps['MessageList']) => {
|
|
|
26
26
|
const { sdk, sbOptions, groupChannelFragmentOptions } = useSendbirdChat();
|
|
27
27
|
const { setMessageToEdit, setMessageToReply } = useContext(GroupChannelContexts.Fragment);
|
|
28
28
|
const groupChannelPubSub = useContext(GroupChannelContexts.PubSub);
|
|
29
|
-
const { flatListRef, lazyScrollToBottom,
|
|
29
|
+
const { flatListRef, lazyScrollToBottom, lazyScrollToMessageId, onPressReplyMessageInThread } = useContext(
|
|
30
30
|
GroupChannelContexts.MessageList,
|
|
31
31
|
);
|
|
32
32
|
|
|
@@ -40,6 +40,7 @@ const GroupChannelMessageList = (props: GroupChannelProps['MessageList']) => {
|
|
|
40
40
|
const viewableMessages = useRef<SendbirdMessage[]>();
|
|
41
41
|
const hasUserMarkedAsUnreadRef = useRef(false);
|
|
42
42
|
const [unreadFirstMessage, setUnreadFirstMessage] = useState<SendbirdMessage | undefined>(undefined);
|
|
43
|
+
const pendingBottomReachedRef = useRef<{ timeout: number; timestamp: number } | null>(null);
|
|
43
44
|
|
|
44
45
|
const updateHasSeenNewLine = useCallback(
|
|
45
46
|
(hasSeenNewLine: boolean) => {
|
|
@@ -63,14 +64,16 @@ const GroupChannelMessageList = (props: GroupChannelProps['MessageList']) => {
|
|
|
63
64
|
|
|
64
65
|
const scrollToMessageWithCreatedAt = useFreshCallback(
|
|
65
66
|
(createdAt: number, focusAnimated: boolean, timeout: number): boolean => {
|
|
66
|
-
const
|
|
67
|
-
const isIncludedInList =
|
|
67
|
+
const foundMessage = props.messages.find((it) => it.createdAt === createdAt);
|
|
68
|
+
const isIncludedInList = !!foundMessage;
|
|
69
|
+
pendingBottomReachedRef.current = null;
|
|
68
70
|
|
|
69
71
|
if (isIncludedInList) {
|
|
70
72
|
if (focusAnimated) {
|
|
71
73
|
setTimeout(() => props.onUpdateSearchItem({ startingPoint: createdAt }), MESSAGE_FOCUS_ANIMATION_DELAY);
|
|
72
74
|
}
|
|
73
|
-
|
|
75
|
+
pendingBottomReachedRef.current = { timeout, timestamp: Date.now() };
|
|
76
|
+
lazyScrollToMessageId({ messageId: foundMessage.messageId, animated: true, timeout });
|
|
74
77
|
} else {
|
|
75
78
|
if (props.channel.messageOffsetTimestamp <= createdAt) {
|
|
76
79
|
if (focusAnimated) {
|
|
@@ -346,6 +349,23 @@ const GroupChannelMessageList = (props: GroupChannelProps['MessageList']) => {
|
|
|
346
349
|
},
|
|
347
350
|
);
|
|
348
351
|
|
|
352
|
+
const onBottomReached = useFreshCallback(() => {
|
|
353
|
+
if (props.hasNext()) {
|
|
354
|
+
if (pendingBottomReachedRef.current) {
|
|
355
|
+
const currentTime = Date.now();
|
|
356
|
+
const elapsedTime = currentTime - pendingBottomReachedRef.current.timestamp;
|
|
357
|
+
|
|
358
|
+
const timeoutThreshold = 500;
|
|
359
|
+
if (elapsedTime >= pendingBottomReachedRef.current.timeout + timeoutThreshold) {
|
|
360
|
+
props.onBottomReached?.();
|
|
361
|
+
pendingBottomReachedRef.current = null;
|
|
362
|
+
}
|
|
363
|
+
} else {
|
|
364
|
+
props.onBottomReached?.();
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
|
|
349
369
|
return (
|
|
350
370
|
<ChannelMessageList
|
|
351
371
|
{...props}
|
|
@@ -359,6 +379,7 @@ const GroupChannelMessageList = (props: GroupChannelProps['MessageList']) => {
|
|
|
359
379
|
onPressNewMessagesButton={scrollToBottom}
|
|
360
380
|
onPressScrollToBottomButton={scrollToBottom}
|
|
361
381
|
onPressMarkAsUnreadMessage={onPressMarkAsUnreadMessage}
|
|
382
|
+
onBottomReached={onBottomReached}
|
|
362
383
|
unreadFirstMessage={unreadFirstMessage}
|
|
363
384
|
unreadMessagesFloatingProps={unreadMessagesFloatingPropsRef.current}
|
|
364
385
|
/>
|
|
@@ -46,6 +46,9 @@ export const GroupChannelContexts: GroupChannelContextsType = {
|
|
|
46
46
|
lazyScrollToIndex: () => {
|
|
47
47
|
// noop
|
|
48
48
|
},
|
|
49
|
+
lazyScrollToMessageId: () => {
|
|
50
|
+
// noop
|
|
51
|
+
},
|
|
49
52
|
} as MessageListContextValue),
|
|
50
53
|
};
|
|
51
54
|
|
|
@@ -68,10 +71,11 @@ export const GroupChannelContextsProvider: GroupChannelModule['Provider'] = ({
|
|
|
68
71
|
const [messageToEdit, setMessageToEdit] = useState<SendbirdUserMessage | SendbirdFileMessage>();
|
|
69
72
|
const [messageToReply, setMessageToReply] = useState<SendbirdUserMessage | SendbirdFileMessage>();
|
|
70
73
|
|
|
71
|
-
const { flatListRef, lazyScrollToIndex, lazyScrollToBottom, scrollToMessage } =
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
const { flatListRef, lazyScrollToIndex, lazyScrollToBottom, scrollToMessage, lazyScrollToMessageId } =
|
|
75
|
+
useScrollActions({
|
|
76
|
+
messages,
|
|
77
|
+
onUpdateSearchItem,
|
|
78
|
+
});
|
|
75
79
|
|
|
76
80
|
const updateInputMode = (mode: 'send' | 'edit' | 'reply', message?: SendbirdUserMessage | SendbirdFileMessage) => {
|
|
77
81
|
if (mode === 'send' || !message) {
|
|
@@ -143,6 +147,7 @@ export const GroupChannelContextsProvider: GroupChannelModule['Provider'] = ({
|
|
|
143
147
|
scrollToMessage,
|
|
144
148
|
lazyScrollToIndex,
|
|
145
149
|
lazyScrollToBottom,
|
|
150
|
+
lazyScrollToMessageId,
|
|
146
151
|
onPressReplyMessageInThread,
|
|
147
152
|
}}
|
|
148
153
|
>
|
|
@@ -159,9 +164,11 @@ type MessageListContextValue = ContextValue<GroupChannelContextsType['MessageLis
|
|
|
159
164
|
const useScrollActions = (params: Pick<GroupChannelProps['Provider'], 'messages' | 'onUpdateSearchItem'>) => {
|
|
160
165
|
const { messages, onUpdateSearchItem } = params;
|
|
161
166
|
const flatListRef = useRef<FlatList<SendbirdMessage>>(null);
|
|
167
|
+
const messagesRef = useRef(messages);
|
|
168
|
+
messagesRef.current = messages;
|
|
162
169
|
|
|
163
170
|
// FIXME: Workaround, should run after data has been applied to UI.
|
|
164
|
-
const lazyScrollToBottom = useFreshCallback<MessageListContextValue['
|
|
171
|
+
const lazyScrollToBottom = useFreshCallback<MessageListContextValue['lazyScrollToBottom']>((params) => {
|
|
165
172
|
if (!flatListRef.current) {
|
|
166
173
|
logFlatListRefWarning();
|
|
167
174
|
return;
|
|
@@ -188,6 +195,33 @@ const useScrollActions = (params: Pick<GroupChannelProps['Provider'], 'messages'
|
|
|
188
195
|
}, params?.timeout ?? 0);
|
|
189
196
|
});
|
|
190
197
|
|
|
198
|
+
// FIXME: Workaround, should run after data has been applied to UI.
|
|
199
|
+
const lazyScrollToMessageId = useFreshCallback<MessageListContextValue['lazyScrollToMessageId']>((params) => {
|
|
200
|
+
if (!flatListRef.current) {
|
|
201
|
+
logFlatListRefWarning();
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
setTimeout(() => {
|
|
206
|
+
let messageIndex = 0;
|
|
207
|
+
if (params?.messageId) {
|
|
208
|
+
const foundMessageIndex = messagesRef.current.findIndex((it) => it.messageId === params.messageId);
|
|
209
|
+
if (foundMessageIndex > -1) {
|
|
210
|
+
messageIndex = foundMessageIndex;
|
|
211
|
+
} else {
|
|
212
|
+
Logger.warn('Message with messageId not found:', params.messageId);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
flatListRef.current?.scrollToIndex({
|
|
218
|
+
index: messageIndex,
|
|
219
|
+
animated: params?.animated ?? false,
|
|
220
|
+
viewPosition: params?.viewPosition ?? 0.5,
|
|
221
|
+
});
|
|
222
|
+
}, params?.timeout ?? 0);
|
|
223
|
+
});
|
|
224
|
+
|
|
191
225
|
const scrollToMessage = useFreshCallback<MessageListContextValue['scrollToMessage']>((messageId, options) => {
|
|
192
226
|
if (!flatListRef.current) {
|
|
193
227
|
logFlatListRefWarning();
|
|
@@ -221,6 +255,7 @@ const useScrollActions = (params: Pick<GroupChannelProps['Provider'], 'messages'
|
|
|
221
255
|
lazyScrollToIndex,
|
|
222
256
|
lazyScrollToBottom,
|
|
223
257
|
scrollToMessage,
|
|
258
|
+
lazyScrollToMessageId,
|
|
224
259
|
};
|
|
225
260
|
};
|
|
226
261
|
|
|
@@ -53,6 +53,8 @@ export interface GroupChannelProps {
|
|
|
53
53
|
|
|
54
54
|
searchItem?: GroupChannelProps['MessageList']['searchItem'];
|
|
55
55
|
|
|
56
|
+
partialTextInputProps?: GroupChannelProps['Input']['partialTextInputProps'];
|
|
57
|
+
|
|
56
58
|
/**
|
|
57
59
|
* @description You can specify the query parameters for the message list.
|
|
58
60
|
* @example
|
|
@@ -111,7 +113,8 @@ export interface GroupChannelProps {
|
|
|
111
113
|
| 'onPressUpdateUserMessage'
|
|
112
114
|
| 'onPressUpdateFileMessage'
|
|
113
115
|
| 'SuggestedMentionList'
|
|
114
|
-
| 'AttachmentsButton'
|
|
116
|
+
| 'AttachmentsButton'
|
|
117
|
+
| 'partialTextInputProps',
|
|
115
118
|
'inputDisabled'
|
|
116
119
|
>;
|
|
117
120
|
|
|
@@ -183,6 +186,16 @@ export interface GroupChannelContextsType {
|
|
|
183
186
|
timeout?: number;
|
|
184
187
|
viewPosition?: number;
|
|
185
188
|
}) => void;
|
|
189
|
+
/**
|
|
190
|
+
* Call the FlatList function asynchronously to scroll to a message by messageId lazily.
|
|
191
|
+
* to avoid scrolling before data rendering has been committed.
|
|
192
|
+
* */
|
|
193
|
+
lazyScrollToMessageId: (params?: {
|
|
194
|
+
messageId?: number;
|
|
195
|
+
animated?: boolean;
|
|
196
|
+
timeout?: number;
|
|
197
|
+
viewPosition?: number;
|
|
198
|
+
}) => void;
|
|
186
199
|
|
|
187
200
|
onPressReplyMessageInThread?: (parentMessage: SendbirdSendableMessage, startingPoint?: number) => void;
|
|
188
201
|
}>;
|
|
@@ -70,6 +70,7 @@ const createGroupChannelFragment = (initModule?: Partial<GroupChannelModule>): G
|
|
|
70
70
|
flatListComponent,
|
|
71
71
|
flatListProps,
|
|
72
72
|
messageListQueryParams,
|
|
73
|
+
partialTextInputProps,
|
|
73
74
|
collectionCreator,
|
|
74
75
|
}) => {
|
|
75
76
|
const { playerService, recorderService } = usePlatformService();
|
|
@@ -341,6 +342,7 @@ const createGroupChannelFragment = (initModule?: Partial<GroupChannelModule>): G
|
|
|
341
342
|
onPressSendFileMessage={onPressSendFileMessage}
|
|
342
343
|
onPressUpdateUserMessage={onPressUpdateUserMessage}
|
|
343
344
|
onPressUpdateFileMessage={onPressUpdateFileMessage}
|
|
345
|
+
partialTextInputProps={partialTextInputProps}
|
|
344
346
|
/>
|
|
345
347
|
</StatusComposition>
|
|
346
348
|
</GroupChannelModule.Provider>
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const VERSION = '3.10.
|
|
1
|
+
const VERSION = '3.10.3';
|
|
2
2
|
export default VERSION;
|