🐛 fix(editor): reset editor state when switching to empty page (#13229)

Fixes LOBE-6321
This commit is contained in:
Innei
2026-03-24 21:37:08 +08:00
committed by GitHub
parent 007d2dc554
commit ada555789d
6 changed files with 33 additions and 47 deletions

View File

@@ -4,6 +4,8 @@ import { type IEditor } from '@lobehub/editor';
import { memo, useCallback, useEffect, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { EMPTY_EDITOR_STATE } from '@/libs/editor/constants';
import { type EditorCanvasProps } from './EditorCanvas';
import InternalEditor from './InternalEditor';
@@ -29,6 +31,9 @@ const loadEditorContent = (
} else if (editorData.content?.trim()) {
editorInstance.setDocument('markdown', editorData.content, { keepId: true });
return true;
} else {
editorInstance.setDocument('json', JSON.stringify(EMPTY_EDITOR_STATE));
return true;
}
} catch (err) {
console.error('[loadEditorContent] Error loading content:', err);

View File

@@ -7,10 +7,10 @@ import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { createChatInputRichPlugins } from '@/features/ChatInput/InputEditor/plugins';
import { EMPTY_EDITOR_STATE } from '@/libs/editor/constants';
import { useAgentStore } from '@/store/agent';
import { agentSelectors } from '@/store/agent/selectors';
import { EMPTY_EDITOR_STATE } from '../constants';
import { useMentionOptions } from '../ProfileEditor/MentionList';
import { useProfileStore } from '../store';
import TypoBar from './TypoBar';

View File

@@ -1,36 +0,0 @@
/**
* Empty editor state for initializing the editor
* This is the minimal JSON structure required by the editor
* Must have at least one paragraph with an empty text node
*/
export const EMPTY_EDITOR_STATE = {
root: {
children: [
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: '',
type: 'text',
version: 1,
},
],
direction: null,
format: '',
indent: 0,
textFormat: 0,
textStyle: '',
type: 'paragraph',
version: 1,
},
],
direction: null,
format: '',
indent: 0,
type: 'root',
version: 1,
},
};

View File

@@ -1,6 +1,8 @@
import { act, renderHook } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';
import { EMPTY_EDITOR_STATE } from '@/libs/editor/constants';
import { useDocumentStore } from '../../store';
// Mock services
@@ -180,10 +182,23 @@ describe('DocumentStore - Editor Actions', () => {
expect(mockEditor.setDocument).toHaveBeenCalledWith('json', JSON.stringify(editorData));
});
it('should not call setDocument when content is empty to avoid editor error', () => {
it('should reset editor content when target document is empty', () => {
const { result } = renderHook(() => useDocumentStore());
const mockEditor = createMockEditor() as any;
act(() => {
result.current.initDocumentWithEditor({
content: '# Previous Content',
documentId: 'doc-previous',
editor: mockEditor,
sourceType: 'page',
});
});
act(() => {
result.current.onEditorInit(mockEditor);
});
act(() => {
result.current.initDocumentWithEditor({
documentId: 'doc-1',
@@ -196,9 +211,10 @@ describe('DocumentStore - Editor Actions', () => {
result.current.onEditorInit(mockEditor);
});
// setDocument should NOT be called for empty content
// This prevents "setEditorState: the editor state is empty" error
expect(mockEditor.setDocument).not.toHaveBeenCalled();
expect(mockEditor.setDocument).toHaveBeenLastCalledWith(
'json',
JSON.stringify(EMPTY_EDITOR_STATE),
);
});
});

View File

@@ -4,6 +4,7 @@ import type { IEditor } from '@lobehub/editor/es/types';
import type { EditorState as LobehubEditorState } from '@lobehub/editor/react';
import isEqual from 'fast-deep-equal';
import { EMPTY_EDITOR_STATE } from '@/libs/editor/constants';
import { documentService } from '@/services/document';
import type { StoreSetter } from '@/store/types';
import { setNamespace } from '@/utils/storeDebug';
@@ -129,14 +130,14 @@ export class EditorActionImpl {
}
}
// Load markdown content if available
// Skip setDocument for empty content - let editor use its default empty state
if (doc.content?.trim()) {
try {
try {
if (doc.content?.trim()) {
editor.setDocument('markdown', doc.content);
} catch (err) {
console.error('[DocumentStore] Failed to load markdown content:', err);
} else {
editor.setDocument('json', JSON.stringify(EMPTY_EDITOR_STATE));
}
} catch (err) {
console.error('[DocumentStore] Failed to load markdown content:', err);
}
this.#set({ editor });