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. 78
      src/components/Chat/ChatList.tsx
  4. 6
      src/components/Chat/MessageItem.tsx
  5. 17
      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> </div>
<CustomButton <CustomButton
onClick={()=> { 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> </div>
<CustomButton <CustomButton
onClick={()=> { onClick={()=> {

78
src/components/Chat/ChatList.tsx

@ -19,8 +19,10 @@ export const ChatList = ({ initialMessages, myAddress }) => {
}, []) }, [])
const handleMessageSeen = useCallback((messageId) => { const handleMessageSeen = useCallback((messageId) => {
setMessages((prevMessages) => setMessages((prevMessages) =>
prevMessages.map((msg) => prevMessages.map((msg) => {
msg.id === messageId ? { ...msg, unread: false } : 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 = () => { const scrollToBottom = () => {
if (listRef.current) { if (listRef.current) {
listRef.current?.recomputeRowHeights(); listRef.current?.recomputeRowHeights();
@ -50,33 +64,49 @@ 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 rowRenderer = ({ index, key, parent, style }) => {
const message = messages[index]; const message = messages[index];
return ( return (
<CellMeasurer <CellMeasurer
key={key} key={key}
cache={cache} cache={cache}
parent={parent} parent={parent}
columnIndex={0} columnIndex={0}
rowIndex={index} rowIndex={index}
>
{({ measure }) => (
<div style={style}>
<div
onLoad={() => preserveScrollPosition(measure)} // Prevent jumps while measuring
style={{
marginBottom: '10px',
width: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
> >
{({ measure }) => ( <MessageItem isLast={index === messages.length - 1} message={message} onSeen={handleMessageSeen} />
<div style={style}> </div>
</div>
<div onLoad={measure} style={{ )}
marginBottom: '10px', </CellMeasurer>
width: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center'
}}>
<MessageItem message={message} onSeen={handleMessageSeen} />
</div>
</div>
)}
</CellMeasurer>
); );
}; };
@ -116,7 +146,7 @@ export const ChatList = ({ initialMessages, myAddress }) => {
rowCount={messages.length} rowCount={messages.length}
rowHeight={cache.rowHeight} rowHeight={cache.rowHeight}
rowRenderer={rowRenderer} rowRenderer={rowRenderer}
onScroll={handleScroll} onScroll={handleScrollDebounced}
deferredMeasurementCache={cache} deferredMeasurementCache={cache}
/> />
)} )}

6
src/components/Chat/MessageItem.tsx

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

17
src/components/Chat/TipTap.tsx

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

Loading…
Cancel
Save