-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathflow.tsx
98 lines (88 loc) · 3.38 KB
/
flow.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import {
Background,
BackgroundVariant,
Controls,
type Node,
ReactFlow,
ReactFlowProvider,
useReactFlow,
} from '@xyflow/react'
import '@xyflow/react/dist/style.css'
import FrankNodeComponent, { type FrankNode } from '~/routes/builder/canvas/nodetypes/frank-node'
import FrankEdgeComponent from '~/routes/builder/canvas/frank-edge'
import ExitNodeComponent, { type ExitNode } from '~/routes/builder/canvas/nodetypes/exit-node'
import StartNodeComponent, { type StartNode } from '~/routes/builder/canvas/nodetypes/start-node'
import useFlowStore, { type FlowState } from '~/stores/flow-store'
import { useShallow } from 'zustand/react/shallow'
import { FlowConfig } from '~/routes/builder/canvas/flow.config'
import { getElementTypeFromName } from '~/routes/builder/node-translator-module'
export type FlowNode = FrankNode | StartNode | ExitNode | Node
const selector = (state: FlowState) => ({
nodes: state.nodes,
edges: state.edges,
onNodesChange: state.onNodesChange,
onEdgesChange: state.onEdgesChange,
onConnect: state.onConnect,
})
function FlowCanvas({ onDragEnd }: Readonly<{ onDragEnd: (b: boolean) => void }>) {
const nodeTypes = { frankNode: FrankNodeComponent, exitNode: ExitNodeComponent, startNode: StartNodeComponent }
const edgeTypes = { frankEdge: FrankEdgeComponent }
const reactFlow = useReactFlow()
const { nodes, edges, onNodesChange, onEdgesChange, onConnect } = useFlowStore(useShallow(selector))
const onDragOver = (event: React.DragEvent) => {
event.preventDefault()
event.dataTransfer.dropEffect = 'move'
}
const onDrop = (event: React.DragEvent) => {
event.preventDefault()
onDragEnd(true)
const data = event.dataTransfer.getData('application/reactflow')
if (!data) return
const parsedData = JSON.parse(data)
const { screenToFlowPosition } = reactFlow
const position = screenToFlowPosition({ x: event.clientX, y: event.clientY })
const newId = useFlowStore.getState().nodes.length
const elementType = getElementTypeFromName(parsedData.name)
const nodeType = elementType == 'exit' ? 'exitNode' : 'frankNode'
const newNode: FrankNode = {
id: newId.toString(),
position: {
x: position.x - (nodeType == 'exitNode' ? FlowConfig.EXIT_DEFAULT_WIDTH : FlowConfig.NODE_DEFAULT_WIDTH) / 2, // Centers node on top of cursor
y: position.y - (nodeType == 'exitNode' ? FlowConfig.EXIT_DEFAULT_HEIGHT : FlowConfig.NODE_DEFAULT_HEIGHT) / 2,
},
data: {
subtype: parsedData.name,
type: elementType,
name: ``,
sourceHandles: [{ type: 'success', index: 1 }],
children: [],
},
type: nodeType,
}
useFlowStore.getState().setNodes([...nodes, newNode])
}
return (
<div style={{ height: '100%' }} onDrop={onDrop} onDragOver={onDragOver}>
<ReactFlow
fitView
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
nodeTypes={nodeTypes}
edgeTypes={edgeTypes}
>
<Controls position="top-left"></Controls>
<Background variant={BackgroundVariant.Dots} size={2}></Background>
</ReactFlow>
</div>
)
}
export default function Flow({ onDragEnd }: Readonly<{ onDragEnd: (b: boolean) => void }>) {
return (
<ReactFlowProvider>
<FlowCanvas onDragEnd={onDragEnd} />
</ReactFlowProvider>
)
}