Select the edge you click in the flow editor
React Flow's selection changes had nowhere to go: the canvas passed edges but no onEdgesChange, so no edge ever carried .selected and both the selected-edge stroke and its rest colour were unreachable. The edges are derived from the bindings, so the selected ids are held on their own and marked on after the layout has had the array — a rebuild cannot drop the selection, and selecting cannot make the graph lay itself out again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SKL7sUgNWhukDEz95vSMQv
This commit is contained in:
@@ -2,6 +2,7 @@ import {
|
||||
Background,
|
||||
BackgroundVariant,
|
||||
type Connection,
|
||||
type EdgeChange,
|
||||
type Node as FlowCanvasNode,
|
||||
type NodeChange,
|
||||
ReactFlow,
|
||||
@@ -219,6 +220,11 @@ function FlowEditorInner({
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null)
|
||||
const [paletteOpen, setPaletteOpen] = useState(false)
|
||||
const [inspected, setInspected] = useState<InspectedEdge | null>(null)
|
||||
// The edges are derived, so xyflow's own selection would be thrown away on
|
||||
// every rebuild: the ids live here instead and are marked on at render.
|
||||
const [selectedEdges, setSelectedEdges] = useState<ReadonlySet<string>>(
|
||||
() => new Set(),
|
||||
)
|
||||
const [rebind, setRebind] = useState<Rebind | null>(null)
|
||||
const [renamed, setRenamed] = useState<MessageRename | null>(null)
|
||||
const [flowPanelOpen, setFlowPanelOpen] = useState(false)
|
||||
@@ -423,6 +429,20 @@ function FlowEditorInner({
|
||||
[onNodesChange],
|
||||
)
|
||||
|
||||
/** Selection is all an edge change can carry here: nothing else is stored. */
|
||||
const onEdgesChange = useCallback((changes: EdgeChange[]) => {
|
||||
const selections = changes.filter((change) => change.type === "select")
|
||||
if (!selections.length) return
|
||||
setSelectedEdges((current) => {
|
||||
const next = new Set(current)
|
||||
for (const change of selections) {
|
||||
if (change.selected) next.add(change.id)
|
||||
else next.delete(change.id)
|
||||
}
|
||||
return next
|
||||
})
|
||||
}, [])
|
||||
|
||||
// Dashboards and other flows wired into this one. They are drawn but never
|
||||
// stored: they join at render, after everything that reads or writes
|
||||
// canvasNodes, so an autosave, an undo or a delete cannot reach them.
|
||||
@@ -485,6 +505,14 @@ function FlowEditorInner({
|
||||
[external, positions],
|
||||
)
|
||||
|
||||
// Marked after the layout has had the derived array, so selecting an edge
|
||||
// never sends the graph through the layout again.
|
||||
const shownEdges = useMemo(
|
||||
() =>
|
||||
edges.map((edge) => ({ ...edge, selected: selectedEdges.has(edge.id) })),
|
||||
[edges, selectedEdges],
|
||||
)
|
||||
|
||||
const shownNodes = useMemo(
|
||||
() => [
|
||||
...renderedNodes.map((node) => ({
|
||||
@@ -911,8 +939,9 @@ function FlowEditorInner({
|
||||
>
|
||||
<ReactFlow
|
||||
nodes={shownNodes}
|
||||
edges={edges}
|
||||
edges={shownEdges}
|
||||
onNodesChange={trackMeasured}
|
||||
onEdgesChange={onEdgesChange}
|
||||
onNodesDelete={(deleted) =>
|
||||
deleteNodes(deleted.filter(isDocumentNode).map((node) => node.id))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user