Browse Source

improve scroll

master
PhilReact 1 week ago
parent
commit
09e690e43f
  1. 2
      src/components/Chat/ChatDirect.tsx
  2. 2
      src/components/Chat/ChatGroup.tsx
  3. 52
      src/components/Chat/ChatList.tsx
  4. 6
      src/components/Chat/MessageItem.tsx
  5. 15
      src/components/Chat/TipTap.tsx

2
src/components/Chat/ChatDirect.tsx

@ -265,7 +265,7 @@ const clearEditorContent = () => {
}}>
<Tiptap setEditorRef={setEditorRef} onEnter={sendMessage} />
<Tiptap setEditorRef={setEditorRef} onEnter={sendMessage} isChat />
</div>
<CustomButton
onClick={()=> {

2
src/components/Chat/ChatGroup.tsx

@ -334,7 +334,7 @@ const clearEditorContent = () => {
}}>
<Tiptap setEditorRef={setEditorRef} onEnter={sendMessage} />
<Tiptap setEditorRef={setEditorRef} onEnter={sendMessage} isChat />
</div>
<CustomButton
onClick={()=> {

52
src/components/Chat/ChatList.tsx

@ -19,8 +19,10 @@ export const ChatList = ({ initialMessages, myAddress }) => {
}, [])
const handleMessageSeen = useCallback((messageId) => {
setMessages((prevMessages) =>
prevMessages.map((msg) =>
msg.id === messageId ? { ...msg, unread: false } : msg
prevMessages.map((msg) => {
return { ...msg, unread: false }
}
)
);
}, []);
@ -36,6 +38,18 @@ export const ChatList = ({ initialMessages, myAddress }) => {
}
};
const debounce = (func, delay) => {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
func(...args);
}, delay);
};
};
const handleScrollDebounced = debounce(handleScroll, 100);
const scrollToBottom = () => {
if (listRef.current) {
listRef.current?.recomputeRowHeights();
@ -50,6 +64,21 @@ export const ChatList = ({ initialMessages, myAddress }) => {
}
};
const preserveScrollPosition = (callback) => {
if (listRef.current) {
const scrollContainer = listRef.current.Grid._scrollingContainer;
const currentScrollTop = scrollContainer.scrollTop; // Get current scroll position
callback(); // Perform the action that could change the layout (e.g., recompute row heights)
// Restore the scroll position after the layout change
setTimeout(() => {
scrollContainer.scrollTop = currentScrollTop;
}, 0);
}
};
const rowRenderer = ({ index, key, parent, style }) => {
const message = messages[index];
@ -60,23 +89,24 @@ export const ChatList = ({ initialMessages, myAddress }) => {
parent={parent}
columnIndex={0}
rowIndex={index}
>
>
{({ measure }) => (
<div style={style}>
<div onLoad={measure} style={{
<div
onLoad={() => preserveScrollPosition(measure)} // Prevent jumps while measuring
style={{
marginBottom: '10px',
width: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center'
}}>
<MessageItem message={message} onSeen={handleMessageSeen} />
alignItems: 'center',
}}
>
<MessageItem isLast={index === messages.length - 1} message={message} onSeen={handleMessageSeen} />
</div>
</div>
)}
</CellMeasurer>
</CellMeasurer>
);
};
@ -116,7 +146,7 @@ export const ChatList = ({ initialMessages, myAddress }) => {
rowCount={messages.length}
rowHeight={cache.rowHeight}
rowRenderer={rowRenderer}
onScroll={handleScroll}
onScroll={handleScrollDebounced}
deferredMeasurementCache={cache}
/>
)}

6
src/components/Chat/MessageItem.tsx

@ -7,10 +7,10 @@ import { formatTimestamp } from "../../utils/time";
import { getBaseApi } from "../../background";
import { getBaseApiReact } from "../../App";
export const MessageItem = ({ message, onSeen }) => {
export const MessageItem = ({ message, onSeen, isLast }) => {
const { ref, inView } = useInView({
threshold: 1.0, // Fully visible
threshold: 0.7, // Fully visible
triggerOnce: true, // Only trigger once when it becomes visible
});
@ -22,7 +22,7 @@ export const MessageItem = ({ message, onSeen }) => {
return (
<div
ref={ref}
ref={isLast ? ref : null}
style={{
padding: "10px",
backgroundColor: "#232428",

15
src/components/Chat/TipTap.tsx

@ -25,7 +25,7 @@ import CustomImage from './CustomImage';
import Compressor from 'compressorjs'
import ImageResize from 'tiptap-extension-resize-image'; // Import the ResizeImage extension
const MenuBar = ({ setEditorRef }) => {
const MenuBar = ({ setEditorRef, isChat }) => {
const { editor } = useCurrentEditor();
const fileInputRef = useRef(null);
if (!editor) {
@ -222,6 +222,8 @@ const MenuBar = ({ setEditorRef }) => {
>
<RedoIcon />
</IconButton>
{!isChat && (
<>
<IconButton
onClick={triggerImageUpload}
sx={{
@ -237,6 +239,9 @@ const MenuBar = ({ setEditorRef }) => {
onChange={handleImageUpload}
accept="image/*" // Limit file types to images only
/>
</>
)}
</div>
</div>
);
@ -263,11 +268,13 @@ const extensions = [
const content = ``;
export default ({ setEditorRef, onEnter, disableEnter }) => {
export default ({ setEditorRef, onEnter, disableEnter, isChat }) => {
console.log('exte', extensions)
const extensionsFiltered = isChat ? extensions.filter((item)=> item?.name !== 'image') : extensions
return (
<EditorProvider
slotBefore={<MenuBar setEditorRef={setEditorRef} />}
extensions={extensions}
slotBefore={<MenuBar setEditorRef={setEditorRef} isChat={isChat} />}
extensions={extensionsFiltered}
content={content}
editorProps={{
handleKeyDown(view, event) {

Loading…
Cancel
Save