feat: add NetworkCanvas wrapper and DiagramHeader components

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-04-04 07:53:52 +00:00
parent d8d8de91d1
commit 600c3959af
2 changed files with 249 additions and 0 deletions

View File

@@ -0,0 +1,87 @@
import { useCallback } from 'react'
import {
ReactFlow,
Background,
Controls,
MiniMap,
BackgroundVariant,
type OnConnect,
type OnNodesChange,
type OnEdgesChange,
type Node,
type Edge,
} from '@xyflow/react'
import { nodeTypes } from './nodes/nodeTypes'
import { edgeTypes } from './edges/edgeTypes'
interface NetworkCanvasProps {
nodes: Node[]
edges: Edge[]
onNodesChange: OnNodesChange
onEdgesChange: OnEdgesChange
onConnect: OnConnect
onNodeSelect: (node: Node | null) => void
onEdgeSelect: (edge: Edge | null) => void
onDrop: (event: React.DragEvent) => void
onDragOver: (event: React.DragEvent) => void
}
export function NetworkCanvas({
nodes,
edges,
onNodesChange,
onEdgesChange,
onConnect,
onNodeSelect,
onEdgeSelect,
onDrop,
onDragOver,
}: NetworkCanvasProps) {
const handleSelectionChange = useCallback(({ nodes: selectedNodes, edges: selectedEdges }: { nodes: Node[]; edges: Edge[] }) => {
if (selectedNodes.length === 1) {
onNodeSelect(selectedNodes[0])
onEdgeSelect(null)
} else if (selectedEdges.length === 1) {
onEdgeSelect(selectedEdges[0])
onNodeSelect(null)
} else {
onNodeSelect(null)
onEdgeSelect(null)
}
}, [onNodeSelect, onEdgeSelect])
const handlePaneClick = useCallback(() => {
onNodeSelect(null)
onEdgeSelect(null)
}, [onNodeSelect, onEdgeSelect])
return (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
onSelectionChange={handleSelectionChange}
onPaneClick={handlePaneClick}
onDrop={onDrop}
onDragOver={onDragOver}
nodeTypes={nodeTypes}
edgeTypes={edgeTypes}
defaultEdgeOptions={{ type: 'connection' }}
deleteKeyCode={['Backspace', 'Delete']}
multiSelectionKeyCode="Shift"
fitView
className="bg-page"
>
<Background variant={BackgroundVariant.Dots} color="var(--color-border-default)" gap={20} size={1} />
<Controls className="!border-default !bg-card [&>button]:!border-default [&>button]:!bg-card [&>button]:!fill-text-primary" />
<MiniMap
nodeColor="var(--color-bg-elevated)"
maskColor="rgba(0,0,0,0.5)"
className="!border-default !bg-card"
position="bottom-right"
/>
</ReactFlow>
)
}