0.6.0
This commit is contained in:
@@ -40,7 +40,10 @@ export const MessageEditArea = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={mjChatCls(['msg-edit-textarea-wrapper'], 'w-full')}
|
||||
className={mjChatCls(
|
||||
['msg-edit-textarea-wrapper'],
|
||||
'w-full max-h-[70vh] overflow-auto rounded-xl border-2 border-white/30',
|
||||
)}
|
||||
style={{
|
||||
height: wrapHeight,
|
||||
}}
|
||||
|
||||
@@ -112,7 +112,7 @@ export const MessageItem = React.memo((props: MessageItemProps) => {
|
||||
await onEdit(id, editedMessage);
|
||||
setIsEditing(false);
|
||||
|
||||
setTimeout(() => scrollMessageIntoView(), 50);
|
||||
setTimeout(() => scrollMessageIntoView('end', 'smooth'), 100);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -212,7 +212,7 @@ export const MessageItem = React.memo((props: MessageItemProps) => {
|
||||
: originalMessage.swipes[activeSwipeId],
|
||||
);
|
||||
// 滚动到消息位置
|
||||
setTimeout(() => scrollMessageIntoView('nearest', 'smooth'), 10);
|
||||
setTimeout(() => scrollMessageIntoView('end', 'smooth'), 100);
|
||||
}}
|
||||
/>
|
||||
<MessageActions
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Message as MessageType } from '@mujian/js-sdk/react';
|
||||
import { Thread, type VListHandle } from '@mujian/js-sdk/react';
|
||||
import { throttle } from 'lodash-es';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useThrottleFn } from 'ahooks';
|
||||
import React, { useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import { MessageItem } from './MessageItem/';
|
||||
|
||||
@@ -29,13 +29,14 @@ export const MessageList = React.memo(
|
||||
onSwipe,
|
||||
onNeedMore,
|
||||
}: MsgProps) => {
|
||||
const prevLastMesRef = useRef<string | undefined>(undefined);
|
||||
const prevDataLength = useRef(0);
|
||||
const prevLastMsgId = useRef('');
|
||||
const { activePersona, projectInfo } = useGlobalStore();
|
||||
const vListRef = useRef<VListHandle>(null);
|
||||
const [visibleRange, setVisibleRange] = useState<[number, number]>([0, 0]);
|
||||
const [shifting, setShifting] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
useLayoutEffect(() => {
|
||||
const vl = vListRef.current;
|
||||
if (!vl) {
|
||||
return;
|
||||
@@ -44,21 +45,29 @@ export const MessageList = React.memo(
|
||||
vl.viewportSize + vl.scrollOffset + 16 >= vl.scrollSize;
|
||||
|
||||
const lastMessage = data[data.length - 1];
|
||||
const shouldScroll = [
|
||||
lastMessage?.id !== prevLastMesRef.current, // 新消息
|
||||
lastMessage?.isStreaming && isScrolledBottom(), // 正在生成
|
||||
const shouldScrollToBottom = [
|
||||
data.length !== prevDataLength.current &&
|
||||
prevLastMsgId.current !== lastMessage?.id, // 新消息
|
||||
lastMessage?.isStreaming && isScrolledBottom(),
|
||||
].some(Boolean);
|
||||
|
||||
if (shouldScroll) {
|
||||
vListRef.current?.scrollTo(
|
||||
prevLastMesRef.current ? vl.scrollSize : 9999999,
|
||||
);
|
||||
if (shouldScrollToBottom) {
|
||||
vl.scrollTo(prevDataLength.current ? vl.scrollSize : 9999999);
|
||||
}
|
||||
|
||||
prevLastMesRef.current = lastMessage?.id;
|
||||
// 因为最后一条消息的ID会在生成完毕后改变,会导致最后一条消息被滚动出去。这里进行滚动位置恢复
|
||||
const shouldRecoverScroll =
|
||||
prevDataLength.current === data.length &&
|
||||
prevLastMsgId.current !== lastMessage?.id;
|
||||
if (shouldRecoverScroll) {
|
||||
vl.scrollTo(vl.scrollOffset);
|
||||
}
|
||||
|
||||
prevDataLength.current = data.length;
|
||||
prevLastMsgId.current = lastMessage?.id;
|
||||
}, [data]);
|
||||
|
||||
const onScroll = throttle(
|
||||
const { run: onScroll } = useThrottleFn(
|
||||
() => {
|
||||
const vl = vListRef.current;
|
||||
if (!vl) {
|
||||
@@ -79,8 +88,8 @@ export const MessageList = React.memo(
|
||||
});
|
||||
}
|
||||
},
|
||||
300,
|
||||
{
|
||||
wait: 300,
|
||||
leading: false,
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user