feat(editor): 标签编辑器保活,切换立即呈现(docs/18)

最近用过的 6 个标签保持挂载、隐藏而非销毁,切回零解析零序列化、各窗格
保留滚动位置;超限窗格卸载走最终回写。引用改为按标签注册表 + 活动变化
effect 统一指向;外部重载 epoch 按标签粒度、抑制闸门对所有标签生效。
EditorPane 新增就绪状态:首次打开大文件显示「正在打开文档…」加载态。
打印守卫:只出活动窗格。vitest 87 通过 + 2 跳过(新增 pane-loading 1 例)。
This commit is contained in:
Muse
2026-11-14 13:06:17 +08:00
parent f378c60363
commit 4a527da655
5 changed files with 206 additions and 56 deletions

View File

@@ -0,0 +1,50 @@
// 编辑器窗格加载状态:编辑器创建完成前显示「正在打开文档…」,就绪后撤下并回传 API。
import { describe, it, expect, vi } from 'vitest'
import { createRoot } from 'react-dom/client'
import { act } from 'react-dom/test-utils'
let resolveCreate: (() => void) | null = null
const fakeEditor = {
create: () => new Promise<void>((resolve) => { resolveCreate = resolve }),
destroy: () => Promise.resolve(),
action: (fn: (ctx: unknown) => unknown) => fn({ get: () => { throw new Error('no view in test') } }),
}
vi.mock('../src/editor/editor', () => ({
createMarkdownEditor: () => fakeEditor,
getMarkdown: () => '',
}))
import EditorPane from '../src/components/EditorPane'
describe('EditorPane 加载状态', () => {
it('创建未完成时显示加载提示,完成后撤下并回传就绪 API', async () => {
const container = document.createElement('div')
document.body.appendChild(container)
const root = createRoot(container)
const readyApis: unknown[] = []
await act(async () => {
root.render(
<EditorPane
tabId="t1"
initialMarkdown="# 大文档"
onMarkdown={() => undefined}
onCursor={() => undefined}
onReady={(api) => readyApis.push(api)}
focusMode={false}
typewriter={false}
/>,
)
})
expect(container.textContent).toContain('正在打开文档')
expect(readyApis).toHaveLength(0)
await act(async () => { resolveCreate?.() })
expect(container.textContent).not.toContain('正在打开文档')
expect(readyApis).toHaveLength(1)
expect((readyApis[0] as { editor: unknown }).editor).toBe(fakeEditor)
await act(async () => { root.unmount() })
container.remove()
})
})