fix(diagram): keep a new mind-map topic in view after Tab

After Tab inserts a child, reflow no longer leaves the new topic and its editor outside the canvas. Center the node before editing starts.
This commit is contained in:
tianma-if committed 2026-09-10 19:07:29 +08:00
1 parent 30717d4207
commit edb22b1eb5
2 files changed
+36 -11

No files matched your search

@@ -58,7 +58,10 @@ describe("diagram editor keyboard workflow", () => {
expect(settleHelper).toContain("anchorAfter.left - anchorBefore.left");
expect(settleHelper).toContain("anchorAfter.top - anchorBefore.top");
expect(settleHelper).toContain("scroller.setScrollbarPosition(");
expect(settleHelper).toContain("requestAnimationFrame(restoreAnchor)");
expect(settleHelper).toContain("requestAnimationFrame(keepAnchor)");
expect(source).toContain("restoreAnchor: !isMindMap");
expect(source).toContain("if (isMindMap) revealDiagramNode(graph, node)");
expect(source).toContain("scroller.centerPoint(box.x + box.width / 2, box.y + box.height / 2)");
expect(source).toContain("SCROLLER_AUTORESIZE_SETTLE_MS");
expect(source).toContain("graph.localToClient");
expect(source).toContain("canvasSurfaceRef.current");
+32 -10
View File
@@ -734,12 +734,16 @@ const suspendScrollerAutoResize = (
graph: Graph,
timerRef: { current: number | null },
isCurrent: () => boolean,
options: { restoreAnchor?: boolean } = {},
) => {
const scroller = getDiagramScroller(graph);
if (!scroller) return () => undefined;
const anchorView = graph.getNodes()
.map((node) => graph.findViewByCell(node))
.find((view) => view?.container.isConnected);
const restoreAnchor = options.restoreAnchor !== false;
const anchorView = restoreAnchor
? graph.getNodes()
.map((node) => graph.findViewByCell(node))
.find((view) => view?.container.isConnected)
: undefined;
const anchorBefore = anchorView?.container.getBoundingClientRect();
let settled = false;
const settle = () => {
@@ -750,7 +754,8 @@ const suspendScrollerAutoResize = (
if (!isCurrent()) return;
scroller.enableAutoResize();
scroller.updateScroller();
const restoreAnchor = () => {
if (!restoreAnchor || !anchorView || !anchorBefore) return;
const keepAnchor = () => {
if (!isCurrent() || !anchorView || !anchorBefore) return;
const anchorAfter = anchorView.container.getBoundingClientRect();
const scroll = scroller.getScrollbarPosition();
@@ -759,8 +764,8 @@ const suspendScrollerAutoResize = (
scroll.top + anchorAfter.top - anchorBefore.top,
);
};
restoreAnchor();
requestAnimationFrame(restoreAnchor);
keepAnchor();
requestAnimationFrame(keepAnchor);
};
scroller.disableAutoResize();
if (timerRef.current !== null) window.clearTimeout(timerRef.current);
@@ -768,6 +773,14 @@ const suspendScrollerAutoResize = (
return settle;
};
const revealDiagramNode = (graph: Graph, node: Node) => {
ensureDiagramPaperContainsNodes(graph);
const box = node.getBBox();
const scroller = getDiagramScroller(graph);
if (scroller) scroller.centerPoint(box.x + box.width / 2, box.y + box.height / 2);
else graph.centerCell(node);
};
const nodeEditorState = (
graph: Graph,
node: Node,
@@ -2109,16 +2122,21 @@ export const DiagramEditorPane = ({
) => {
const graph = graphRef.current;
if (!graph || !document || readOnly) return;
const settleScroller = suspendScrollerAutoResize(graph, scrollerResumeTimerRef, () => graphRef.current === graph);
const isMindMap = document.kind === "mind-map";
const settleScroller = suspendScrollerAutoResize(
graph,
scrollerResumeTimerRef,
() => graphRef.current === graph,
{ restoreAnchor: !isMindMap },
);
const baseNodeId = options.baseNodeId ?? selectedNodeId;
const selected = baseNodeId
? graph.getCellById(baseNodeId) as Node | undefined
: document.kind === "mind-map"
: isMindMap
? graph.getNodes()[0]
: undefined;
const selectedPosition = selected?.isNode() ? selected.getPosition() : { x: 120, y: 120 };
const selectedSize = selected?.isNode() ? selected.getSize() : { width: 140, height: 52 };
const isMindMap = document.kind === "mind-map";
const isArchitecture = document.kind === "architecture";
const selectedData = selected?.isNode() ? selected.getData<NodeData>() : undefined;
const requestedSibling = isMindMap && options.relation === "sibling" && Boolean(selectedData?.parentId);
@@ -2228,6 +2246,7 @@ export const DiagramEditorPane = ({
}
graph.stopBatch("add");
settleScroller();
if (isMindMap) revealDiagramNode(graph, node);
graph.cleanSelection();
graph.select(node);
setSelectedNodeId(id);
@@ -2238,7 +2257,10 @@ export const DiagramEditorPane = ({
setDirty(true);
setHistoryState({ undo: graph.canUndo(), redo: graph.canRedo() });
if (options.beginEditing) {
requestAnimationFrame(() => beginNodeEdit(node));
requestAnimationFrame(() => {
if (isMindMap) revealDiagramNode(graph, node);
beginNodeEdit(node);
});
}
}, [beginNodeEdit, document, readOnly, selectedNodeId, t]);