diff --git a/web/src/components/MemoEditor/Editor/index.tsx b/web/src/components/MemoEditor/Editor/index.tsx index 1b66b9bb6..0ef458f9e 100644 --- a/web/src/components/MemoEditor/Editor/index.tsx +++ b/web/src/components/MemoEditor/Editor/index.tsx @@ -52,6 +52,26 @@ const Editor = forwardRef(function Editor(props: EditorProps, ref: React.Forward } }, [handleContentChangeCallback, updateEditorHeight]); + const scrollToCaret = useCallback((options: { force?: boolean } = {}) => { + const editor = editorRef.current; + if (!editor) return; + + const { force = false } = options; + const caret = getCaretCoordinates(editor, editor.selectionEnd); + + if (force) { + editor.scrollTop = Math.max(0, caret.top - editor.clientHeight / 2); + return; + } + + const lineHeight = parseFloat(getComputedStyle(editor).lineHeight) || 24; + const viewportBottom = editor.scrollTop + editor.clientHeight; + // Scroll if cursor is near or beyond bottom edge (within 2 lines) + if (caret.top + lineHeight * 2 > viewportBottom) { + editor.scrollTop = Math.max(0, caret.top - editor.clientHeight / 2); + } + }, []); + useEffect(() => { if (editorRef.current && initialContent) { editorRef.current.value = initialContent; @@ -75,12 +95,7 @@ const Editor = forwardRef(function Editor(props: EditorProps, ref: React.Forward getEditor: () => editorRef.current, focus: () => editorRef.current?.focus(), scrollToCursor: () => { - const editor = editorRef.current; - if (!editor) return; - - const caret = getCaretCoordinates(editor, editor.selectionEnd); - // Scroll to center cursor vertically - editor.scrollTop = Math.max(0, caret.top - editor.clientHeight / 2); + scrollToCaret({ force: true }); }, insertText: (content = "", prefix = "", suffix = "") => { const editor = editorRef.current; @@ -143,7 +158,7 @@ const Editor = forwardRef(function Editor(props: EditorProps, ref: React.Forward updateContent(); }, }), - [updateContent], + [updateContent, scrollToCaret], ); useImperativeHandle(ref, () => editorActions, [editorActions]); @@ -155,18 +170,9 @@ const Editor = forwardRef(function Editor(props: EditorProps, ref: React.Forward // Auto-scroll to keep cursor visible when typing // See: https://github.com/usememos/memos/issues/5469 - const editor = editorRef.current; - const caret = getCaretCoordinates(editor, editor.selectionEnd); - const lineHeight = parseFloat(getComputedStyle(editor).lineHeight) || 24; - - // Scroll if cursor is near or beyond bottom edge (within 2 lines) - const viewportBottom = editor.scrollTop + editor.clientHeight; - if (caret.top + lineHeight * 2 > viewportBottom) { - // Scroll to center cursor vertically - editor.scrollTop = Math.max(0, caret.top - editor.clientHeight / 2); - } + scrollToCaret(); } - }, [handleContentChangeCallback, updateEditorHeight]); + }, [handleContentChangeCallback, updateEditorHeight, scrollToCaret]); // Auto-complete markdown lists when pressing Enter useListCompletion({