From 43b1f0d09993b008f150ab8b233d82d46c7e4bd2 Mon Sep 17 00:00:00 2001 From: danney-chun <63285271+danney-chun@users.noreply.github.com> Date: Mon, 1 Dec 2025 20:15:29 +0900 Subject: [PATCH 1/2] Add feature to scroll to top of new message instead of bottom --- apps/testing/src/pages/PlaygroundPage.tsx | 1 + src/lib/Sendbird/context/SendbirdProvider.tsx | 4 +++ src/lib/Sendbird/context/initialState.ts | 1 + src/lib/Sendbird/types.ts | 2 ++ src/modules/App/AppLayout.tsx | 3 ++ src/modules/App/DesktopLayout.tsx | 2 ++ src/modules/App/MobileLayout.tsx | 2 ++ src/modules/App/index.tsx | 4 +++ src/modules/App/types.ts | 1 + .../components/Message/MessageView.tsx | 29 +++++++++++++++++++ .../GroupChannel/components/Message/index.tsx | 4 +++ .../components/MessageList/index.tsx | 21 ++++++++++++++ .../context/GroupChannelProvider.tsx | 12 +++++++- .../context/hooks/useGroupChannel.ts | 7 +++++ src/modules/GroupChannel/context/types.ts | 3 ++ 15 files changed, 95 insertions(+), 1 deletion(-) diff --git a/apps/testing/src/pages/PlaygroundPage.tsx b/apps/testing/src/pages/PlaygroundPage.tsx index 13b7c1e31..2716b4b68 100644 --- a/apps/testing/src/pages/PlaygroundPage.tsx +++ b/apps/testing/src/pages/PlaygroundPage.tsx @@ -10,5 +10,6 @@ export function PlaygroundPage() { replyType: 'thread', } }} + // isFocusOnLastMessage={true} />; } diff --git a/src/lib/Sendbird/context/SendbirdProvider.tsx b/src/lib/Sendbird/context/SendbirdProvider.tsx index 1a3ecced5..fcca5fe62 100644 --- a/src/lib/Sendbird/context/SendbirdProvider.tsx +++ b/src/lib/Sendbird/context/SendbirdProvider.tsx @@ -72,6 +72,7 @@ const SendbirdContextManager = ({ sdkInitParams, customExtensionParams, isMultipleFilesMessageEnabled = false, + isFocusOnLastMessage = false, eventHandlers, htmlTextDirection = 'ltr', forceLeftToRightMessageLayout = false, @@ -288,6 +289,7 @@ const SendbirdContextManager = ({ setCurrentTheme, setCurrenttheme: setCurrentTheme, // deprecated: typo isMultipleFilesMessageEnabled, + isFocusOnLastMessage, uikitMultipleFilesMessageLimit, logger, pubSub, @@ -316,6 +318,7 @@ const SendbirdContextManager = ({ currentTheme, setCurrentTheme, isMultipleFilesMessageEnabled, + isFocusOnLastMessage, uikitMultipleFilesMessageLimit, logger, pubSub, @@ -395,6 +398,7 @@ const InternalSendbirdProvider = (props: SendbirdProviderProps & { logger: Logge }, disableMarkAsDelivered: props?.disableMarkAsDelivered, isMultipleFilesMessageEnabled: props?.isMultipleFilesMessageEnabled, + isFocusOnLastMessage: props?.isFocusOnLastMessage, }, eventHandlers: props?.eventHandlers, }); diff --git a/src/lib/Sendbird/context/initialState.ts b/src/lib/Sendbird/context/initialState.ts index 0a4d3b953..a5344dbb8 100644 --- a/src/lib/Sendbird/context/initialState.ts +++ b/src/lib/Sendbird/context/initialState.ts @@ -33,6 +33,7 @@ const config: SendbirdStateConfig = { forceLeftToRightMessageLayout: false, disableMarkAsDelivered: false, isMultipleFilesMessageEnabled: false, + isFocusOnLastMessage: false, htmlTextDirection: 'ltr', uikitUploadSizeLimit: DEFAULT_UPLOAD_SIZE_LIMIT, uikitMultipleFilesMessageLimit: DEFAULT_MULTIPLE_FILES_MESSAGE_LIMIT, diff --git a/src/lib/Sendbird/types.ts b/src/lib/Sendbird/types.ts index 729891eb1..f312f6398 100644 --- a/src/lib/Sendbird/types.ts +++ b/src/lib/Sendbird/types.ts @@ -218,6 +218,7 @@ export interface SendbirdProviderProps extends CommonUIKitConfigProps, React.Pro sdkInitParams?: SendbirdChatInitParams; customExtensionParams?: CustomExtensionParams; isMultipleFilesMessageEnabled?: boolean; + isFocusOnLastMessage?: boolean; // UserProfile renderUserProfile?: (props: RenderUserProfileProps) => React.ReactElement; onStartDirectMessage?: (channel: GroupChannel) => void; @@ -260,6 +261,7 @@ export interface SendbirdStateConfig { markAsDeliveredScheduler: MarkAsDeliveredSchedulerType; disableMarkAsDelivered: boolean; isMultipleFilesMessageEnabled: boolean; + isFocusOnLastMessage: boolean; // Remote configs set from dashboard by UIKit feature configuration common: { enableUsingDefaultUserProfile: SBUConfig['common']['enableUsingDefaultUserProfile']; diff --git a/src/modules/App/AppLayout.tsx b/src/modules/App/AppLayout.tsx index c0d160011..195303bc5 100644 --- a/src/modules/App/AppLayout.tsx +++ b/src/modules/App/AppLayout.tsx @@ -13,6 +13,7 @@ import useSendbird from '../../lib/Sendbird/context/hooks/useSendbird'; export const AppLayout = (props: AppLayoutProps) => { const { isMessageGroupingEnabled, + isFocusOnLastMessage, allowProfileEdit, onProfileEditSuccess, disableAutoSelect, @@ -50,6 +51,7 @@ export const AppLayout = (props: AppLayoutProps) => { showSearchIcon={showSearchIcon} isReactionEnabled={isReactionEnabled} isMessageGroupingEnabled={isMessageGroupingEnabled} + isFocusOnLastMessage={isFocusOnLastMessage} allowProfileEdit={allowProfileEdit} onProfileEditSuccess={onProfileEditSuccess} currentChannel={currentChannel} @@ -69,6 +71,7 @@ export const AppLayout = (props: AppLayoutProps) => { isReactionEnabled={isReactionEnabled} showSearchIcon={showSearchIcon} isMessageGroupingEnabled={isMessageGroupingEnabled} + isFocusOnLastMessage={isFocusOnLastMessage} allowProfileEdit={allowProfileEdit} onProfileEditSuccess={onProfileEditSuccess} disableAutoSelect={disableAutoSelect} diff --git a/src/modules/App/DesktopLayout.tsx b/src/modules/App/DesktopLayout.tsx index d68116ce0..0c5276c57 100644 --- a/src/modules/App/DesktopLayout.tsx +++ b/src/modules/App/DesktopLayout.tsx @@ -21,6 +21,7 @@ export const DesktopLayout: React.FC = (props: DesktopLayout replyType, isMessageGroupingEnabled, isMultipleFilesMessageEnabled, + isFocusOnLastMessage, allowProfileEdit, showSearchIcon, onProfileEditSuccess, @@ -104,6 +105,7 @@ export const DesktopLayout: React.FC = (props: DesktopLayout replyType: replyType, isMessageGroupingEnabled: isMessageGroupingEnabled, isMultipleFilesMessageEnabled: isMultipleFilesMessageEnabled, + isFocusOnLastMessage: isFocusOnLastMessage, // for GroupChannel animatedMessageId: highlightedMessage, onReplyInThreadClick: onClickThreadReply, diff --git a/src/modules/App/MobileLayout.tsx b/src/modules/App/MobileLayout.tsx index c1766fe8c..32d0eb2a7 100644 --- a/src/modules/App/MobileLayout.tsx +++ b/src/modules/App/MobileLayout.tsx @@ -32,6 +32,7 @@ export const MobileLayout: React.FC = (props: MobileLayoutPro replyType, isMessageGroupingEnabled, isMultipleFilesMessageEnabled, + isFocusOnLastMessage, allowProfileEdit, isReactionEnabled, showSearchIcon, @@ -155,6 +156,7 @@ export const MobileLayout: React.FC = (props: MobileLayoutPro replyType, isMessageGroupingEnabled, isMultipleFilesMessageEnabled, + isFocusOnLastMessage, // for GroupChannel animatedMessageId: highlightedMessage, onReplyInThreadClick: ({ message }) => { diff --git a/src/modules/App/index.tsx b/src/modules/App/index.tsx index b9d67cfcf..e0a761634 100644 --- a/src/modules/App/index.tsx +++ b/src/modules/App/index.tsx @@ -29,6 +29,7 @@ export interface AppProps { config?: SendbirdProviderProps['config']; voiceRecord?: SendbirdProviderProps['voiceRecord']; isMultipleFilesMessageEnabled?: SendbirdProviderProps['isMultipleFilesMessageEnabled']; + isFocusOnLastMessage?: SendbirdProviderProps['isFocusOnLastMessage']; colorSet?: SendbirdProviderProps['colorSet']; stringSet?: SendbirdProviderProps['stringSet']; allowProfileEdit?: SendbirdProviderProps['allowProfileEdit']; @@ -99,6 +100,7 @@ export default function App(props: AppProps) { customExtensionParams, eventHandlers, isMultipleFilesMessageEnabled, + isFocusOnLastMessage = false, isUserIdUsedForNickname = true, enableLegacyChannelModules = false, uikitOptions, @@ -138,6 +140,7 @@ export default function App(props: AppProps) { renderUserProfile={renderUserProfile} imageCompression={imageCompression} isMultipleFilesMessageEnabled={isMultipleFilesMessageEnabled} + isFocusOnLastMessage={isFocusOnLastMessage} voiceRecord={voiceRecord} onStartDirectMessage={(channel) => { setCurrentChannel(channel); @@ -159,6 +162,7 @@ export default function App(props: AppProps) { forceLeftToRightMessageLayout={forceLeftToRightMessageLayout} > void; + /** + * A function that forces scroll to message when new message is received. + */ + forceScrollToMessage?: (ref: React.MutableRefObject, message: CoreMessageType) => void; /** * @deprecated Please use `children` instead * @description Customizes all child components of the message. @@ -97,6 +101,10 @@ export interface MessageViewProps extends MessageProps { animatedMessageId: number | null; setAnimatedMessageId: React.Dispatch>; + + newMessageIds?: number[] | null; + setNewMessageIds?: (ids: number[]) => void; + onMessageAnimated?: () => void; /** @deprecated * */ highLightedMessageId?: number | null; @@ -119,6 +127,7 @@ const MessageView = (props: MessageViewProps) => { chainBottom, handleScroll, onNewMessageSeparatorVisibilityChange, + forceScrollToMessage, // MessageViewProps channel, @@ -147,6 +156,9 @@ const MessageView = (props: MessageViewProps) => { animatedMessageId, onMessageAnimated, usedInLegacy = true, + + newMessageIds, + setNewMessageIds, } = props; const { @@ -257,6 +269,23 @@ const MessageView = (props: MessageViewProps) => { }; }, [animatedMessageId, messageScrollRef.current, message.messageId]); + useLayoutEffect(() => { + if (newMessageIds?.length > 0 && newMessageIds.includes(message.messageId)) { + let rafId: number | null = null; + + rafId = requestAnimationFrame(() => { + forceScrollToMessage(messageScrollRef, message); + setNewMessageIds([]); + }); + + return () => { + if (rafId !== null) { + cancelAnimationFrame(rafId); + } + }; + } + }, [newMessageIds]); + const renderedCustomSeparator = useMemo(() => renderCustomSeparator?.({ message }) ?? null, [message, renderCustomSeparator]); const renderChildren = () => { diff --git a/src/modules/GroupChannel/components/Message/index.tsx b/src/modules/GroupChannel/components/Message/index.tsx index a725365f6..b0727e0f1 100644 --- a/src/modules/GroupChannel/components/Message/index.tsx +++ b/src/modules/GroupChannel/components/Message/index.tsx @@ -30,6 +30,7 @@ export const Message = (props: MessageProps): React.ReactElement => { onBeforeDownloadFileMessage, messages, markAsUnread, + newMessageIds, }, actions: { toggleReaction, @@ -40,6 +41,7 @@ export const Message = (props: MessageProps): React.ReactElement => { sendUserMessage, resendMessage, deleteMessage, + setNewMessageIds, }, } = useGroupChannel(); @@ -94,6 +96,8 @@ export const Message = (props: MessageProps): React.ReactElement => { renderRemoveMessageModal={(props) => } usedInLegacy={false} onBeforeDownloadFileMessage={onBeforeDownloadFileMessage} + newMessageIds={newMessageIds} + setNewMessageIds={setNewMessageIds} /> ); }; diff --git a/src/modules/GroupChannel/components/MessageList/index.tsx b/src/modules/GroupChannel/components/MessageList/index.tsx index 519ceaf7e..51ab78038 100644 --- a/src/modules/GroupChannel/components/MessageList/index.tsx +++ b/src/modules/GroupChannel/components/MessageList/index.tsx @@ -89,12 +89,14 @@ export const MessageList = (props: GroupChannelMessageListProps) => { scrollDistanceFromBottomRef, markAsUnreadSourceRef, readState, + isFocusOnLastMessage, }, actions: { scrollToBottom, setIsScrollBottomReached, markAsReadAll, markAsUnread, + scrollToMessage, }, } = useGroupChannel(); @@ -204,6 +206,24 @@ export const MessageList = (props: GroupChannelMessageListProps) => { } }; + /** + * Force scroll to message + * when new message is received + * and the message content height is over the current scroll height + */ + const forceScrollToMessage = (ref: React.MutableRefObject, message: CoreMessageType) => { + if (!isFocusOnLastMessage) return; + const messageComponent = ref.current; + const messageComponentHeight = messageComponent?.clientHeight; + const currentScrollHeight = scrollRef.current?.offsetHeight; + + if (messageComponentHeight > currentScrollHeight) { + scrollToMessage(message.createdAt, message.messageId); + } else if (isScrollBottomReached) { + scrollToBottom(); + } + }; + const renderer = { frozenNotification() { if (!currentChannel || !currentChannel.isFrozen) return null; @@ -331,6 +351,7 @@ export const MessageList = (props: GroupChannelMessageListProps) => { renderSuggestedReplies, renderCustomSeparator, onNewMessageSeparatorVisibilityChange: checkDisplayedNewMessageSeparator, + forceScrollToMessage, })} ); diff --git a/src/modules/GroupChannel/context/GroupChannelProvider.tsx b/src/modules/GroupChannel/context/GroupChannelProvider.tsx index 82c884683..8a33b21cc 100644 --- a/src/modules/GroupChannel/context/GroupChannelProvider.tsx +++ b/src/modules/GroupChannel/context/GroupChannelProvider.tsx @@ -56,6 +56,7 @@ const initialState = () => ({ isReactionEnabled: false, isMessageGroupingEnabled: true, isMultipleFilesMessageEnabled: false, + isFocusOnLastMessage: false, showSearchIcon: true, replyType: 'NONE', threadReplySelectType: ThreadReplySelectType.PARENT, @@ -83,6 +84,7 @@ export const InternalGroupChannelProvider = (props: GroupChannelProviderProps) = isReactionEnabled: props?.isReactionEnabled, isMessageGroupingEnabled: props?.isMessageGroupingEnabled, isMultipleFilesMessageEnabled: props?.isMultipleFilesMessageEnabled, + isFocusOnLastMessage: props?.isFocusOnLastMessage, showSearchIcon: props?.showSearchIcon, threadReplySelectType: props?.threadReplySelectType, disableMarkAsRead: props?.disableMarkAsRead, @@ -125,6 +127,7 @@ const GroupChannelManager :React.FC actions.scrollToBottom(true), 10); + if (!isFocusOnLastMessage) { + setTimeout(async () => actions.scrollToBottom(true), 10); + } else { + actions.setNewMessageIds(messages.map(it => it.messageId)); + } } }, onChannelDeleted: () => { @@ -271,6 +278,7 @@ const GroupChannelManager :React.FC { + // send message if (data.channel.url === state.currentChannel?.url) { actions.scrollToBottom(true); } @@ -339,6 +347,7 @@ const GroupChannelManager :React.FC Promise; updateUserMessage: (messageId: number, params: UserMessageUpdateParams) => Promise; + setNewMessageIds: (ids: number[]) => void; + // UI actions setQuoteMessage: (message: SendableMessageType | null) => void; setAnimatedMessageId: (messageId: number | null) => void; @@ -205,6 +207,10 @@ export const useGroupChannel = () => { store.setState(state => ({ ...state, firstUnreadMessageId: messageId })); }, []); + const setNewMessageIds = useCallback((newMessageIds: number[]) => { + store.setState(state => ({ ...state, newMessageIds })); + }, []); + const actions: GroupChannelActions = useMemo(() => { return { setCurrentChannel, @@ -213,6 +219,7 @@ export const useGroupChannel = () => { markAsUnread: state.markAsUnread, setReadStateChanged, setFirstUnreadMessageId, + setNewMessageIds, setQuoteMessage, scrollToBottom, scrollToMessage, diff --git a/src/modules/GroupChannel/context/types.ts b/src/modules/GroupChannel/context/types.ts index 3c647e719..6f1fd27e1 100644 --- a/src/modules/GroupChannel/context/types.ts +++ b/src/modules/GroupChannel/context/types.ts @@ -47,6 +47,7 @@ interface InternalGroupChannelState extends MessageDataSource { animatedMessageId: number | null; isScrollBottomReached: boolean; readState: string | null; + newMessageIds: number[] | null; // References - will be managed together scrollRef: React.RefObject; @@ -58,6 +59,7 @@ interface InternalGroupChannelState extends MessageDataSource { isReactionEnabled: boolean; isMessageGroupingEnabled: boolean; isMultipleFilesMessageEnabled: boolean; + isFocusOnLastMessage: boolean; showSearchIcon: boolean; replyType: ReplyType; threadReplySelectType: ThreadReplySelectType; @@ -86,6 +88,7 @@ export interface GroupChannelProviderProps extends PropsWithChildren< isReactionEnabled?: boolean; isMessageGroupingEnabled?: boolean; isMultipleFilesMessageEnabled?: boolean; + isFocusOnLastMessage?: boolean; showSearchIcon?: boolean; replyType?: ReplyType; threadReplySelectType?: ThreadReplySelectType; From db963cd3099692f4ea8b4b26f72f47a8284d6a19 Mon Sep 17 00:00:00 2001 From: danney-chun <63285271+danney-chun@users.noreply.github.com> Date: Tue, 2 Dec 2025 13:18:22 +0900 Subject: [PATCH 2/2] changed props name --- apps/testing/src/pages/PlaygroundPage.tsx | 2 +- src/lib/Sendbird/context/SendbirdProvider.tsx | 8 ++++---- src/lib/Sendbird/context/initialState.ts | 2 +- src/lib/Sendbird/types.ts | 4 ++-- src/modules/App/AppLayout.tsx | 6 +++--- src/modules/App/DesktopLayout.tsx | 4 ++-- src/modules/App/MobileLayout.tsx | 4 ++-- src/modules/App/index.tsx | 8 ++++---- src/modules/App/types.ts | 2 +- .../GroupChannel/components/Message/MessageView.tsx | 6 +++--- .../GroupChannel/components/MessageList/index.tsx | 8 ++++---- .../GroupChannel/context/GroupChannelProvider.tsx | 12 ++++++------ src/modules/GroupChannel/context/types.ts | 4 ++-- 13 files changed, 35 insertions(+), 35 deletions(-) diff --git a/apps/testing/src/pages/PlaygroundPage.tsx b/apps/testing/src/pages/PlaygroundPage.tsx index 2716b4b68..b8df058f7 100644 --- a/apps/testing/src/pages/PlaygroundPage.tsx +++ b/apps/testing/src/pages/PlaygroundPage.tsx @@ -10,6 +10,6 @@ export function PlaygroundPage() { replyType: 'thread', } }} - // isFocusOnLastMessage={true} + // autoscrollMessageOverflowToTop={true} />; } diff --git a/src/lib/Sendbird/context/SendbirdProvider.tsx b/src/lib/Sendbird/context/SendbirdProvider.tsx index fcca5fe62..4dcecaffb 100644 --- a/src/lib/Sendbird/context/SendbirdProvider.tsx +++ b/src/lib/Sendbird/context/SendbirdProvider.tsx @@ -72,7 +72,7 @@ const SendbirdContextManager = ({ sdkInitParams, customExtensionParams, isMultipleFilesMessageEnabled = false, - isFocusOnLastMessage = false, + autoscrollMessageOverflowToTop = false, eventHandlers, htmlTextDirection = 'ltr', forceLeftToRightMessageLayout = false, @@ -289,7 +289,7 @@ const SendbirdContextManager = ({ setCurrentTheme, setCurrenttheme: setCurrentTheme, // deprecated: typo isMultipleFilesMessageEnabled, - isFocusOnLastMessage, + autoscrollMessageOverflowToTop, uikitMultipleFilesMessageLimit, logger, pubSub, @@ -318,7 +318,7 @@ const SendbirdContextManager = ({ currentTheme, setCurrentTheme, isMultipleFilesMessageEnabled, - isFocusOnLastMessage, + autoscrollMessageOverflowToTop, uikitMultipleFilesMessageLimit, logger, pubSub, @@ -398,7 +398,7 @@ const InternalSendbirdProvider = (props: SendbirdProviderProps & { logger: Logge }, disableMarkAsDelivered: props?.disableMarkAsDelivered, isMultipleFilesMessageEnabled: props?.isMultipleFilesMessageEnabled, - isFocusOnLastMessage: props?.isFocusOnLastMessage, + autoscrollMessageOverflowToTop: props?.autoscrollMessageOverflowToTop, }, eventHandlers: props?.eventHandlers, }); diff --git a/src/lib/Sendbird/context/initialState.ts b/src/lib/Sendbird/context/initialState.ts index a5344dbb8..0e1f662d2 100644 --- a/src/lib/Sendbird/context/initialState.ts +++ b/src/lib/Sendbird/context/initialState.ts @@ -33,7 +33,7 @@ const config: SendbirdStateConfig = { forceLeftToRightMessageLayout: false, disableMarkAsDelivered: false, isMultipleFilesMessageEnabled: false, - isFocusOnLastMessage: false, + autoscrollMessageOverflowToTop: false, htmlTextDirection: 'ltr', uikitUploadSizeLimit: DEFAULT_UPLOAD_SIZE_LIMIT, uikitMultipleFilesMessageLimit: DEFAULT_MULTIPLE_FILES_MESSAGE_LIMIT, diff --git a/src/lib/Sendbird/types.ts b/src/lib/Sendbird/types.ts index f312f6398..1dc663f00 100644 --- a/src/lib/Sendbird/types.ts +++ b/src/lib/Sendbird/types.ts @@ -218,7 +218,7 @@ export interface SendbirdProviderProps extends CommonUIKitConfigProps, React.Pro sdkInitParams?: SendbirdChatInitParams; customExtensionParams?: CustomExtensionParams; isMultipleFilesMessageEnabled?: boolean; - isFocusOnLastMessage?: boolean; + autoscrollMessageOverflowToTop?: boolean; // UserProfile renderUserProfile?: (props: RenderUserProfileProps) => React.ReactElement; onStartDirectMessage?: (channel: GroupChannel) => void; @@ -261,7 +261,7 @@ export interface SendbirdStateConfig { markAsDeliveredScheduler: MarkAsDeliveredSchedulerType; disableMarkAsDelivered: boolean; isMultipleFilesMessageEnabled: boolean; - isFocusOnLastMessage: boolean; + autoscrollMessageOverflowToTop: boolean; // Remote configs set from dashboard by UIKit feature configuration common: { enableUsingDefaultUserProfile: SBUConfig['common']['enableUsingDefaultUserProfile']; diff --git a/src/modules/App/AppLayout.tsx b/src/modules/App/AppLayout.tsx index 195303bc5..601362500 100644 --- a/src/modules/App/AppLayout.tsx +++ b/src/modules/App/AppLayout.tsx @@ -13,7 +13,7 @@ import useSendbird from '../../lib/Sendbird/context/hooks/useSendbird'; export const AppLayout = (props: AppLayoutProps) => { const { isMessageGroupingEnabled, - isFocusOnLastMessage, + autoscrollMessageOverflowToTop, allowProfileEdit, onProfileEditSuccess, disableAutoSelect, @@ -51,7 +51,7 @@ export const AppLayout = (props: AppLayoutProps) => { showSearchIcon={showSearchIcon} isReactionEnabled={isReactionEnabled} isMessageGroupingEnabled={isMessageGroupingEnabled} - isFocusOnLastMessage={isFocusOnLastMessage} + autoscrollMessageOverflowToTop={autoscrollMessageOverflowToTop} allowProfileEdit={allowProfileEdit} onProfileEditSuccess={onProfileEditSuccess} currentChannel={currentChannel} @@ -71,7 +71,7 @@ export const AppLayout = (props: AppLayoutProps) => { isReactionEnabled={isReactionEnabled} showSearchIcon={showSearchIcon} isMessageGroupingEnabled={isMessageGroupingEnabled} - isFocusOnLastMessage={isFocusOnLastMessage} + autoscrollMessageOverflowToTop={autoscrollMessageOverflowToTop} allowProfileEdit={allowProfileEdit} onProfileEditSuccess={onProfileEditSuccess} disableAutoSelect={disableAutoSelect} diff --git a/src/modules/App/DesktopLayout.tsx b/src/modules/App/DesktopLayout.tsx index 0c5276c57..c63d6b15d 100644 --- a/src/modules/App/DesktopLayout.tsx +++ b/src/modules/App/DesktopLayout.tsx @@ -21,7 +21,7 @@ export const DesktopLayout: React.FC = (props: DesktopLayout replyType, isMessageGroupingEnabled, isMultipleFilesMessageEnabled, - isFocusOnLastMessage, + autoscrollMessageOverflowToTop, allowProfileEdit, showSearchIcon, onProfileEditSuccess, @@ -105,7 +105,7 @@ export const DesktopLayout: React.FC = (props: DesktopLayout replyType: replyType, isMessageGroupingEnabled: isMessageGroupingEnabled, isMultipleFilesMessageEnabled: isMultipleFilesMessageEnabled, - isFocusOnLastMessage: isFocusOnLastMessage, + autoscrollMessageOverflowToTop: autoscrollMessageOverflowToTop, // for GroupChannel animatedMessageId: highlightedMessage, onReplyInThreadClick: onClickThreadReply, diff --git a/src/modules/App/MobileLayout.tsx b/src/modules/App/MobileLayout.tsx index 32d0eb2a7..2a618929b 100644 --- a/src/modules/App/MobileLayout.tsx +++ b/src/modules/App/MobileLayout.tsx @@ -32,7 +32,7 @@ export const MobileLayout: React.FC = (props: MobileLayoutPro replyType, isMessageGroupingEnabled, isMultipleFilesMessageEnabled, - isFocusOnLastMessage, + autoscrollMessageOverflowToTop, allowProfileEdit, isReactionEnabled, showSearchIcon, @@ -156,7 +156,7 @@ export const MobileLayout: React.FC = (props: MobileLayoutPro replyType, isMessageGroupingEnabled, isMultipleFilesMessageEnabled, - isFocusOnLastMessage, + autoscrollMessageOverflowToTop, // for GroupChannel animatedMessageId: highlightedMessage, onReplyInThreadClick: ({ message }) => { diff --git a/src/modules/App/index.tsx b/src/modules/App/index.tsx index e0a761634..188c0247d 100644 --- a/src/modules/App/index.tsx +++ b/src/modules/App/index.tsx @@ -29,7 +29,7 @@ export interface AppProps { config?: SendbirdProviderProps['config']; voiceRecord?: SendbirdProviderProps['voiceRecord']; isMultipleFilesMessageEnabled?: SendbirdProviderProps['isMultipleFilesMessageEnabled']; - isFocusOnLastMessage?: SendbirdProviderProps['isFocusOnLastMessage']; + autoscrollMessageOverflowToTop?: SendbirdProviderProps['autoscrollMessageOverflowToTop']; colorSet?: SendbirdProviderProps['colorSet']; stringSet?: SendbirdProviderProps['stringSet']; allowProfileEdit?: SendbirdProviderProps['allowProfileEdit']; @@ -100,7 +100,7 @@ export default function App(props: AppProps) { customExtensionParams, eventHandlers, isMultipleFilesMessageEnabled, - isFocusOnLastMessage = false, + autoscrollMessageOverflowToTop = false, isUserIdUsedForNickname = true, enableLegacyChannelModules = false, uikitOptions, @@ -140,7 +140,7 @@ export default function App(props: AppProps) { renderUserProfile={renderUserProfile} imageCompression={imageCompression} isMultipleFilesMessageEnabled={isMultipleFilesMessageEnabled} - isFocusOnLastMessage={isFocusOnLastMessage} + autoscrollMessageOverflowToTop={autoscrollMessageOverflowToTop} voiceRecord={voiceRecord} onStartDirectMessage={(channel) => { setCurrentChannel(channel); @@ -162,7 +162,7 @@ export default function App(props: AppProps) { forceLeftToRightMessageLayout={forceLeftToRightMessageLayout} > , message: CoreMessageType) => void; + scrollMessageOverflowToTop?: (ref: React.MutableRefObject, message: CoreMessageType) => void; /** * @deprecated Please use `children` instead * @description Customizes all child components of the message. @@ -127,7 +127,7 @@ const MessageView = (props: MessageViewProps) => { chainBottom, handleScroll, onNewMessageSeparatorVisibilityChange, - forceScrollToMessage, + scrollMessageOverflowToTop, // MessageViewProps channel, @@ -274,7 +274,7 @@ const MessageView = (props: MessageViewProps) => { let rafId: number | null = null; rafId = requestAnimationFrame(() => { - forceScrollToMessage(messageScrollRef, message); + scrollMessageOverflowToTop(messageScrollRef, message); setNewMessageIds([]); }); diff --git a/src/modules/GroupChannel/components/MessageList/index.tsx b/src/modules/GroupChannel/components/MessageList/index.tsx index 51ab78038..87e5dcd44 100644 --- a/src/modules/GroupChannel/components/MessageList/index.tsx +++ b/src/modules/GroupChannel/components/MessageList/index.tsx @@ -89,7 +89,7 @@ export const MessageList = (props: GroupChannelMessageListProps) => { scrollDistanceFromBottomRef, markAsUnreadSourceRef, readState, - isFocusOnLastMessage, + autoscrollMessageOverflowToTop, }, actions: { scrollToBottom, @@ -211,8 +211,8 @@ export const MessageList = (props: GroupChannelMessageListProps) => { * when new message is received * and the message content height is over the current scroll height */ - const forceScrollToMessage = (ref: React.MutableRefObject, message: CoreMessageType) => { - if (!isFocusOnLastMessage) return; + const scrollMessageOverflowToTop = (ref: React.MutableRefObject, message: CoreMessageType) => { + if (!autoscrollMessageOverflowToTop) return; const messageComponent = ref.current; const messageComponentHeight = messageComponent?.clientHeight; const currentScrollHeight = scrollRef.current?.offsetHeight; @@ -351,7 +351,7 @@ export const MessageList = (props: GroupChannelMessageListProps) => { renderSuggestedReplies, renderCustomSeparator, onNewMessageSeparatorVisibilityChange: checkDisplayedNewMessageSeparator, - forceScrollToMessage, + scrollMessageOverflowToTop, })} ); diff --git a/src/modules/GroupChannel/context/GroupChannelProvider.tsx b/src/modules/GroupChannel/context/GroupChannelProvider.tsx index 8a33b21cc..ca01e1f5f 100644 --- a/src/modules/GroupChannel/context/GroupChannelProvider.tsx +++ b/src/modules/GroupChannel/context/GroupChannelProvider.tsx @@ -56,7 +56,7 @@ const initialState = () => ({ isReactionEnabled: false, isMessageGroupingEnabled: true, isMultipleFilesMessageEnabled: false, - isFocusOnLastMessage: false, + autoscrollMessageOverflowToTop: false, showSearchIcon: true, replyType: 'NONE', threadReplySelectType: ThreadReplySelectType.PARENT, @@ -84,7 +84,7 @@ export const InternalGroupChannelProvider = (props: GroupChannelProviderProps) = isReactionEnabled: props?.isReactionEnabled, isMessageGroupingEnabled: props?.isMessageGroupingEnabled, isMultipleFilesMessageEnabled: props?.isMultipleFilesMessageEnabled, - isFocusOnLastMessage: props?.isFocusOnLastMessage, + autoscrollMessageOverflowToTop: props?.autoscrollMessageOverflowToTop, showSearchIcon: props?.showSearchIcon, threadReplySelectType: props?.threadReplySelectType, disableMarkAsRead: props?.disableMarkAsRead, @@ -127,7 +127,7 @@ const GroupChannelManager :React.FC actions.scrollToBottom(true), 10); } else { actions.setNewMessageIds(messages.map(it => it.messageId)); @@ -347,7 +347,7 @@ const GroupChannelManager :React.FC