fix: explicit handle IDs — forward edges use top/bottom, feedback uses sides

Prevent React Flow from auto-routing forward edges to side handles.
All handles now have explicit IDs and all edges specify sourceHandle/targetHandle.
This commit is contained in:
2026-05-14 15:54:21 +08:00
parent 5e783e7a24
commit 019d8c1ee9
3 changed files with 6 additions and 5 deletions
@@ -45,7 +45,7 @@ export function RoleNode(props: NodeProps) {
}} }}
title={data.description} title={data.description}
> >
<Handle type="target" position={Position.Top} style={handleStyle} isConnectable={false} /> <Handle type="target" position={Position.Top} id="top-in" style={handleStyle} isConnectable={false} />
<Handle type="target" position={Position.Left} id="left-in" style={handleStyle} isConnectable={false} /> <Handle type="target" position={Position.Left} id="left-in" style={handleStyle} isConnectable={false} />
<Handle type="target" position={Position.Right} id="right-in" style={handleStyle} isConnectable={false} /> <Handle type="target" position={Position.Right} id="right-in" style={handleStyle} isConnectable={false} />
<Handle type="source" position={Position.Left} id="left-out" style={handleStyle} isConnectable={false} /> <Handle type="source" position={Position.Left} id="left-out" style={handleStyle} isConnectable={false} />
@@ -67,7 +67,7 @@ export function RoleNode(props: NodeProps) {
{data.description} {data.description}
</div> </div>
)} )}
<Handle type="source" position={Position.Bottom} style={handleStyle} isConnectable={false} /> <Handle type="source" position={Position.Bottom} id="bottom-out" style={handleStyle} isConnectable={false} />
</div> </div>
); );
} }
@@ -45,11 +45,12 @@ export function TerminalNode(props: NodeProps) {
<Handle <Handle
type="source" type="source"
position={Position.Bottom} position={Position.Bottom}
id="bottom-out"
style={handleStyle} style={handleStyle}
isConnectable={false} isConnectable={false}
/> />
) : ( ) : (
<Handle type="target" position={Position.Top} style={handleStyle} isConnectable={false} /> <Handle type="target" position={Position.Top} id="top-in" style={handleStyle} isConnectable={false} />
)} )}
{isStart ? "▶" : "■"} {isStart ? "▶" : "■"}
</div> </div>
@@ -216,8 +216,8 @@ function computeLayout(input: LayoutInput): LayoutResult {
id: edgeKey(e), id: edgeKey(e),
source: e.from, source: e.from,
target: e.to, target: e.to,
sourceHandle: isFeedback ? (feedbackSide === "left" ? "left-out" : "right-out") : undefined, sourceHandle: isFeedback ? (feedbackSide === "left" ? "left-out" : "right-out") : "bottom-out",
targetHandle: isFeedback ? (feedbackSide === "left" ? "left-in" : "right-in") : undefined, targetHandle: isFeedback ? (feedbackSide === "left" ? "left-in" : "right-in") : "top-in",
type: "condition", type: "condition",
data: { data: {
condition: e.condition, condition: e.condition,