fix(workspace): scroll/diff-race/recovery/editor/mobile polish

This commit is contained in:
Gabriel Brown
2026-07-11 17:59:25 -04:00
parent b00141130c
commit f89dfce3b8
6 changed files with 477 additions and 18 deletions
@@ -24,6 +24,7 @@ const EDITOR_FONT_FAMILY =
type MonacoEditorInstance = {
getModel?: () => unknown;
dispose?: () => void;
};
type VimMode = {
@@ -36,6 +37,7 @@ export const CodeEditor = ({
savedContent,
readOnly,
vimEnabled,
conflicted,
onSave,
onChange,
onVimEnabledChange,
@@ -45,6 +47,7 @@ export const CodeEditor = ({
savedContent: string;
readOnly: boolean;
vimEnabled: boolean;
conflicted?: boolean;
onSave: (content: string) => Promise<void>;
onChange: (content: string) => void;
onVimEnabledChange: (enabled: boolean) => void;
@@ -56,6 +59,18 @@ export const CodeEditor = ({
const { resolvedTheme } = useTheme();
const editorTheme = resolvedTheme === 'light' ? SPOON_LIGHT : SPOON_DARK;
// Dispose the Monaco instance and clear the ref on unmount so a remount
// (e.g. the Phase-1 key={jobId} swap) doesn't leave a stale editor/vim
// binding leaked behind the new mount.
useEffect(() => {
return () => {
vimRef.current?.dispose();
vimRef.current = null;
editorRef.current?.dispose?.();
editorRef.current = null;
};
}, []);
useEffect(() => {
const editor = editorRef.current;
if (!editor) return;
@@ -102,7 +117,11 @@ export const CodeEditor = ({
Editor
</p>
<p className='truncate font-mono text-xs'>{path}</p>
{dirty ? (
{conflicted ? (
<p className='text-amber-500 text-xs'>
This file changed on disk your unsaved edits may conflict.
</p>
) : dirty ? (
<p className='text-muted-foreground text-xs'>Unsaved changes</p>
) : null}
</div>