修复评审器跨组件修改项跳转丢失并展开完整文档视图

- DiffView 聚焦 effect 依赖补上 before/after:stage 文本到达、
  MergeView 重建后重新应用选区和滚动,跨组件点击不再停在顶部;
- 非可编辑面板加 drawSelection,聚焦范围在浏览器中可见;
- 移除 collapseUnchanged,评审始终可读完整未改动段落;
- 滚动容器移到 .cm-mergeView 外层,编辑器高度自适应内容;
- 新增 3 项 Vitest 覆盖折叠移除与聚焦时序,共 9 项通过;
- README 与 explanation 同步当前检查数量。
This commit is contained in:
2026-08-24 08:56:46 +08:00
parent ac798a2610
commit efc1313d87
6 changed files with 99 additions and 14 deletions
+7 -5
View File
@@ -1,7 +1,7 @@
import { markdown } from "@codemirror/lang-markdown";
import { MergeView } from "@codemirror/merge";
import { EditorState } from "@codemirror/state";
import { EditorView, lineNumbers } from "@codemirror/view";
import { EditorSelection, EditorState } from "@codemirror/state";
import { drawSelection, EditorView, lineNumbers } from "@codemirror/view";
import { useEffect, useRef } from "react";
interface DiffViewProps {
@@ -45,6 +45,7 @@ const readOnlyExtensions = [
markdown(),
EditorState.readOnly.of(true),
EditorView.editable.of(false),
drawSelection(),
EditorView.lineWrapping,
editorTheme,
];
@@ -64,7 +65,6 @@ export function DiffView({ before, after, beforeLabel, afterLabel, focusRange }:
orientation: "a-b",
gutter: true,
highlightChanges: true,
collapseUnchanged: { margin: 4, minSize: 8 },
});
merge.current = view;
return () => {
@@ -73,6 +73,8 @@ export function DiffView({ before, after, beforeLabel, afterLabel, focusRange }:
};
}, [before, after]);
// 切换组件时 stage 文本先到、旧视图上的提前滚动会被重建覆盖,所以聚焦
// 必须等 MergeView 换成目标文本之后再执行。
useEffect(() => {
const view = merge.current;
if (view === null || focusRange === null || focusRange === undefined) {
@@ -81,11 +83,11 @@ export function DiffView({ before, after, beforeLabel, afterLabel, focusRange }:
const anchor = Math.min(Math.max(focusRange.start, 0), view.a.state.doc.length);
const head = Math.min(Math.max(focusRange.end, anchor), view.a.state.doc.length);
view.a.dispatch({
selection: { anchor, head },
selection: EditorSelection.range(anchor, head),
effects: EditorView.scrollIntoView(anchor, { y: "center" }),
});
view.a.focus();
}, [focusRange]);
}, [focusRange, before, after]);
return (
<section className="diff-shell" aria-label={`${beforeLabel}${afterLabel}对比`}>