|
|
|
|
@ -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({
|
|
|
|
|
|