Intelligent readonly editor updates, to preserve scroll

This commit is contained in:
Gregory Schier
2024-10-14 10:40:09 -07:00
parent 8090e67b9e
commit dffe6e0a16
3 changed files with 28 additions and 3 deletions

View File

@@ -8,12 +8,12 @@ import classNames from 'classnames';
import { EditorView } from 'codemirror';
import type { MutableRefObject, ReactNode } from 'react';
import {
useEffect,
Children,
cloneElement,
forwardRef,
isValidElement,
useCallback,
useEffect,
useImperativeHandle,
useMemo,
useRef,
@@ -343,6 +343,33 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
[forceUpdateKey],
);
// For read-only mode, update content when `defaultValue` changes
useEffect(() => {
if (!readOnly || cm.current?.view == null || defaultValue == null) return;
// Replace codemirror contents
const currentDoc = cm.current.view.state.doc.toString();
if (defaultValue.startsWith(currentDoc)) {
// If we're just appending, append only the changes. This preserves
// things like scroll position.
cm.current.view.dispatch({
changes: cm.current.view.state.changes({
from: currentDoc.length,
insert: defaultValue.slice(currentDoc.length),
}),
});
} else {
// If we're replacing everything, reset the entire content
cm.current.view.dispatch({
changes: cm.current.view.state.changes({
from: 0,
to: currentDoc.length,
insert: currentDoc,
}),
});
}
}, [defaultValue, readOnly]);
// Add bg classes to actions, so they appear over the text
const decoratedActions = useMemo(() => {
const results = [];

View File

@@ -90,7 +90,6 @@ function ActualEventStreamViewer({ response }: Props) {
) : (
<Editor
readOnly
forceUpdateKey={activeEvent.id ?? activeEvent.data}
defaultValue={tryFormatJson(activeEvent.data)}
language={language}
/>

View File

@@ -160,7 +160,6 @@ export function TextViewer({
<Editor
readOnly
className={className}
forceUpdateKey={body}
defaultValue={body}
language={language}
actions={actions}