chore(examples): move examples to demo folder
This commit is contained in:
@@ -3,11 +3,11 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@react-flow/core": "11.0.0",
|
||||||
"dagre": "^0.8.5",
|
"dagre": "^0.8.5",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"react": "file:../node_modules/react",
|
"react": "^18.2.0",
|
||||||
"react-dom": "file:../node_modules/react-dom",
|
"react-dom": "^18.2.0",
|
||||||
"react-flow-renderer": "file:../",
|
|
||||||
"react-router-dom": "^6.3.0",
|
"react-router-dom": "^6.3.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"typescript": "^4.7.4"
|
"typescript": "^4.7.4"
|
||||||
@@ -36,8 +36,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/dagre": "^0.7.47",
|
"@types/dagre": "^0.7.47",
|
||||||
"@types/localforage": "0.0.34",
|
"@types/localforage": "0.0.34",
|
||||||
"@types/react": "file:../node_modules/@types/react",
|
"@types/react-dom": "^18.0.6",
|
||||||
"@types/react-dom": "file:../node_modules/@types/react-dom",
|
|
||||||
"@types/react-router-dom": "^5.3.3"
|
"@types/react-router-dom": "^5.3.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,17 +7,39 @@ import ReactFlow, {
|
|||||||
Node,
|
Node,
|
||||||
Edge,
|
Edge,
|
||||||
useReactFlow,
|
useReactFlow,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
const onNodeDrag = (_: MouseEvent, node: Node) => console.log('drag', node);
|
const onNodeDrag = (_: MouseEvent, node: Node) => console.log('drag', node);
|
||||||
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
const onNodeDragStop = (_: MouseEvent, node: Node) =>
|
||||||
|
console.log('drag stop', node);
|
||||||
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 }, className: 'light' },
|
{
|
||||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, className: 'light' },
|
id: '1',
|
||||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, className: 'light' },
|
type: 'input',
|
||||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 }, className: 'light' },
|
data: { label: 'Node 1' },
|
||||||
|
position: { x: 250, y: 5 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
data: { label: 'Node 2' },
|
||||||
|
position: { x: 100, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
data: { label: 'Node 3' },
|
||||||
|
position: { x: 400, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
data: { label: 'Node 4' },
|
||||||
|
position: { x: 400, y: 200 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const initialEdges: Edge[] = [
|
const initialEdges: Edge[] = [
|
||||||
@@ -63,7 +85,7 @@ const BasicFlow = () => {
|
|||||||
onNodeClick={onNodeClick}
|
onNodeClick={onNodeClick}
|
||||||
onNodeDragStop={onNodeDragStop}
|
onNodeDragStop={onNodeDragStop}
|
||||||
onNodeDrag={onNodeDrag}
|
onNodeDrag={onNodeDrag}
|
||||||
className="react-flow-basic-example"
|
className='react-flow-basic-example'
|
||||||
minZoom={0.2}
|
minZoom={0.2}
|
||||||
maxZoom={4}
|
maxZoom={4}
|
||||||
fitView
|
fitView
|
||||||
+26
-5
@@ -7,13 +7,34 @@ import ReactFlow, {
|
|||||||
ReactFlowProvider,
|
ReactFlowProvider,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
const defaultNodes: Node[] = [
|
const defaultNodes: Node[] = [
|
||||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 }, className: 'light' },
|
{
|
||||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, className: 'light' },
|
id: '1',
|
||||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, className: 'light' },
|
type: 'input',
|
||||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 }, className: 'light' },
|
data: { label: 'Node 1' },
|
||||||
|
position: { x: 250, y: 5 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
data: { label: 'Node 2' },
|
||||||
|
position: { x: 100, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
data: { label: 'Node 3' },
|
||||||
|
position: { x: 400, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
data: { label: 'Node 4' },
|
||||||
|
position: { x: 400, y: 200 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const defaultEdges: Edge[] = [
|
const defaultEdges: Edge[] = [
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import React, { FC } from 'react';
|
||||||
|
import { ConnectionLineComponentProps } from '@react-flow/core';
|
||||||
|
|
||||||
|
const ConnectionLine: FC<ConnectionLineComponentProps> = ({
|
||||||
|
sourceX,
|
||||||
|
sourceY,
|
||||||
|
targetX,
|
||||||
|
targetY,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<g>
|
||||||
|
<path
|
||||||
|
fill='none'
|
||||||
|
stroke='#222'
|
||||||
|
strokeWidth={1.5}
|
||||||
|
className='animated'
|
||||||
|
d={`M${sourceX},${sourceY} C ${sourceX} ${targetY} ${sourceX} ${targetY} ${targetX},${targetY}`}
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
cx={targetX}
|
||||||
|
cy={targetY}
|
||||||
|
fill='#fff'
|
||||||
|
r={3}
|
||||||
|
stroke='#222'
|
||||||
|
strokeWidth={1.5}
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ConnectionLine;
|
||||||
+13
-3
@@ -8,17 +8,27 @@ import ReactFlow, {
|
|||||||
Edge,
|
Edge,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import ConnectionLine from './ConnectionLine';
|
import ConnectionLine from './ConnectionLine';
|
||||||
|
|
||||||
const initialNodes: Node[] = [{ id: '1', type: 'default', data: { label: 'Node 1' }, position: { x: 250, y: 5 } }];
|
const initialNodes: Node[] = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
type: 'default',
|
||||||
|
data: { label: 'Node 1' },
|
||||||
|
position: { x: 250, y: 5 },
|
||||||
|
},
|
||||||
|
];
|
||||||
const initialEdges: Edge[] = [];
|
const initialEdges: Edge[] = [];
|
||||||
|
|
||||||
const ConnectionLineFlow = () => {
|
const ConnectionLineFlow = () => {
|
||||||
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
const onConnect = useCallback((params: Connection | Edge) => setEdges((eds) => addEdge(params, eds)), [setEdges]);
|
const onConnect = useCallback(
|
||||||
|
(params: Connection | Edge) => setEdges((eds) => addEdge(params, eds)),
|
||||||
|
[setEdges]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import React, { memo, FC, CSSProperties } from 'react';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Handle,
|
||||||
|
Position,
|
||||||
|
NodeProps,
|
||||||
|
Connection,
|
||||||
|
Edge,
|
||||||
|
} from '@react-flow/core';
|
||||||
|
|
||||||
|
const targetHandleStyle: CSSProperties = { background: '#555' };
|
||||||
|
const sourceHandleStyleA: CSSProperties = { ...targetHandleStyle, top: 10 };
|
||||||
|
const sourceHandleStyleB: CSSProperties = {
|
||||||
|
...targetHandleStyle,
|
||||||
|
bottom: 10,
|
||||||
|
top: 'auto',
|
||||||
|
};
|
||||||
|
|
||||||
|
const onConnect = (params: Connection | Edge) =>
|
||||||
|
console.log('handle onConnect', params);
|
||||||
|
|
||||||
|
const ColorSelectorNode: FC<NodeProps> = ({ data, isConnectable }) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Handle
|
||||||
|
type='target'
|
||||||
|
position={Position.Left}
|
||||||
|
style={targetHandleStyle}
|
||||||
|
onConnect={onConnect}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
Custom Color Picker Node: <strong>{data.color}</strong>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
className='nodrag'
|
||||||
|
type='color'
|
||||||
|
onChange={data.onChange}
|
||||||
|
defaultValue={data.color}
|
||||||
|
/>
|
||||||
|
<Handle
|
||||||
|
type='source'
|
||||||
|
position={Position.Right}
|
||||||
|
id='a'
|
||||||
|
style={sourceHandleStyleA}
|
||||||
|
isConnectable={isConnectable}
|
||||||
|
onMouseDown={(e) => {
|
||||||
|
console.log('You trigger mousedown event', e);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Handle
|
||||||
|
type='source'
|
||||||
|
position={Position.Right}
|
||||||
|
id='b'
|
||||||
|
style={sourceHandleStyleB}
|
||||||
|
isConnectable={isConnectable}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(ColorSelectorNode);
|
||||||
+29
-6
@@ -12,7 +12,7 @@ import ReactFlow, {
|
|||||||
Connection,
|
Connection,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import ColorSelectorNode from './ColorSelectorNode';
|
import ColorSelectorNode from './ColorSelectorNode';
|
||||||
|
|
||||||
@@ -20,7 +20,8 @@ const onInit = (reactFlowInstance: ReactFlowInstance) => {
|
|||||||
console.log('flow loaded:', reactFlowInstance);
|
console.log('flow loaded:', reactFlowInstance);
|
||||||
reactFlowInstance.fitView();
|
reactFlowInstance.fitView();
|
||||||
};
|
};
|
||||||
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
const onNodeDragStop = (_: MouseEvent, node: Node) =>
|
||||||
|
console.log('drag stop', node);
|
||||||
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
||||||
|
|
||||||
const initBgColor = '#1A192B';
|
const initBgColor = '#1A192B';
|
||||||
@@ -93,14 +94,36 @@ const CustomNodeFlow = () => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
setEdges([
|
setEdges([
|
||||||
{ id: 'e1-2', source: '1', target: '2', animated: true, style: { stroke: '#fff' } },
|
{
|
||||||
{ id: 'e2a-3', source: '2', sourceHandle: 'a', target: '3', animated: true, style: { stroke: '#fff' } },
|
id: 'e1-2',
|
||||||
{ id: 'e2b-4', source: '2', sourceHandle: 'b', target: '4', animated: true, style: { stroke: '#fff' } },
|
source: '1',
|
||||||
|
target: '2',
|
||||||
|
animated: true,
|
||||||
|
style: { stroke: '#fff' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'e2a-3',
|
||||||
|
source: '2',
|
||||||
|
sourceHandle: 'a',
|
||||||
|
target: '3',
|
||||||
|
animated: true,
|
||||||
|
style: { stroke: '#fff' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'e2b-4',
|
||||||
|
source: '2',
|
||||||
|
sourceHandle: 'b',
|
||||||
|
target: '4',
|
||||||
|
animated: true,
|
||||||
|
style: { stroke: '#fff' },
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onConnect = (connection: Connection) =>
|
const onConnect = (connection: Connection) =>
|
||||||
setEdges((eds) => addEdge({ ...connection, animated: true, style: { stroke: '#fff' } }, eds));
|
setEdges((eds) =>
|
||||||
|
addEdge({ ...connection, animated: true, style: { stroke: '#fff' } }, eds)
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
+32
-6
@@ -5,13 +5,34 @@ import ReactFlow, {
|
|||||||
Node,
|
Node,
|
||||||
Edge,
|
Edge,
|
||||||
ReactFlowProvider,
|
ReactFlowProvider,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
const defaultNodes: Node[] = [
|
const defaultNodes: Node[] = [
|
||||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 }, className: 'light' },
|
{
|
||||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, className: 'light' },
|
id: '1',
|
||||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, className: 'light' },
|
type: 'input',
|
||||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 }, className: 'light' },
|
data: { label: 'Node 1' },
|
||||||
|
position: { x: 250, y: 5 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
data: { label: 'Node 2' },
|
||||||
|
position: { x: 100, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
data: { label: 'Node 3' },
|
||||||
|
position: { x: 400, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
data: { label: 'Node 4' },
|
||||||
|
position: { x: 400, y: 200 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const defaultEdges: Edge[] = [
|
const defaultEdges: Edge[] = [
|
||||||
@@ -55,7 +76,12 @@ const DefaultNodes = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow defaultNodes={defaultNodes} defaultEdges={defaultEdges} defaultEdgeOptions={defaultEdgeOptions} fitView>
|
<ReactFlow
|
||||||
|
defaultNodes={defaultNodes}
|
||||||
|
defaultEdges={defaultEdges}
|
||||||
|
defaultEdgeOptions={defaultEdgeOptions}
|
||||||
|
fitView
|
||||||
|
>
|
||||||
<Background variant={BackgroundVariant.Lines} />
|
<Background variant={BackgroundVariant.Lines} />
|
||||||
|
|
||||||
<div style={{ position: 'absolute', right: 10, top: 10, zIndex: 4 }}>
|
<div style={{ position: 'absolute', right: 10, top: 10, zIndex: 4 }}>
|
||||||
+13
-5
@@ -1,8 +1,15 @@
|
|||||||
import { memo, FC } from 'react';
|
import { memo, FC } from 'react';
|
||||||
|
|
||||||
import { Handle, Position, NodeProps, Connection, Edge } from 'react-flow-renderer';
|
import {
|
||||||
|
Handle,
|
||||||
|
Position,
|
||||||
|
NodeProps,
|
||||||
|
Connection,
|
||||||
|
Edge,
|
||||||
|
} from '@react-flow/core';
|
||||||
|
|
||||||
const onConnect = (params: Connection | Edge) => console.log('handle onConnect', params);
|
const onConnect = (params: Connection | Edge) =>
|
||||||
|
console.log('handle onConnect', params);
|
||||||
|
|
||||||
const labelStyle = {
|
const labelStyle = {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -21,11 +28,12 @@ const dragHandleStyle = {
|
|||||||
const ColorSelectorNode: FC<NodeProps> = () => {
|
const ColorSelectorNode: FC<NodeProps> = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Handle type="target" position={Position.Left} onConnect={onConnect} />
|
<Handle type='target' position={Position.Left} onConnect={onConnect} />
|
||||||
<div style={labelStyle}>
|
<div style={labelStyle}>
|
||||||
Only draggable here → <span className="custom-drag-handle" style={dragHandleStyle} />
|
Only draggable here →{' '}
|
||||||
|
<span className='custom-drag-handle' style={dragHandleStyle} />
|
||||||
</div>
|
</div>
|
||||||
<Handle type="source" position={Position.Right} />
|
<Handle type='source' position={Position.Right} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
+6
-1
@@ -1,5 +1,10 @@
|
|||||||
import { MouseEvent } from 'react';
|
import { MouseEvent } from 'react';
|
||||||
import ReactFlow, { Node, Edge, useNodesState, useEdgesState } from 'react-flow-renderer';
|
import ReactFlow, {
|
||||||
|
Node,
|
||||||
|
Edge,
|
||||||
|
useNodesState,
|
||||||
|
useEdgesState,
|
||||||
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import DragHandleNode from './DragHandleNode';
|
import DragHandleNode from './DragHandleNode';
|
||||||
|
|
||||||
+19
-7
@@ -9,13 +9,20 @@ import ReactFlow, {
|
|||||||
Node,
|
Node,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import Sidebar from './Sidebar';
|
import Sidebar from './Sidebar';
|
||||||
|
|
||||||
import './dnd.css';
|
import './dnd.css';
|
||||||
|
|
||||||
const initialNodes: Node[] = [{ id: '1', type: 'input', data: { label: 'input node' }, position: { x: 250, y: 5 } }];
|
const initialNodes: Node[] = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
type: 'input',
|
||||||
|
data: { label: 'input node' },
|
||||||
|
position: { x: 250, y: 5 },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const onDragOver = (event: DragEvent) => {
|
const onDragOver = (event: DragEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -26,11 +33,13 @@ let id = 0;
|
|||||||
const getId = () => `dndnode_${id++}`;
|
const getId = () => `dndnode_${id++}`;
|
||||||
|
|
||||||
const DnDFlow = () => {
|
const DnDFlow = () => {
|
||||||
const [reactFlowInstance, setReactFlowInstance] = useState<ReactFlowInstance>();
|
const [reactFlowInstance, setReactFlowInstance] =
|
||||||
|
useState<ReactFlowInstance>();
|
||||||
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
||||||
|
|
||||||
const onConnect = (params: Connection | Edge) => setEdges((eds) => addEdge(params, eds));
|
const onConnect = (params: Connection | Edge) =>
|
||||||
|
setEdges((eds) => addEdge(params, eds));
|
||||||
const onInit = (rfi: ReactFlowInstance) => setReactFlowInstance(rfi);
|
const onInit = (rfi: ReactFlowInstance) => setReactFlowInstance(rfi);
|
||||||
|
|
||||||
const onDrop = (event: DragEvent) => {
|
const onDrop = (event: DragEvent) => {
|
||||||
@@ -38,7 +47,10 @@ const DnDFlow = () => {
|
|||||||
|
|
||||||
if (reactFlowInstance) {
|
if (reactFlowInstance) {
|
||||||
const type = event.dataTransfer.getData('application/reactflow');
|
const type = event.dataTransfer.getData('application/reactflow');
|
||||||
const position = reactFlowInstance.project({ x: event.clientX, y: event.clientY - 40 });
|
const position = reactFlowInstance.project({
|
||||||
|
x: event.clientX,
|
||||||
|
y: event.clientY - 40,
|
||||||
|
});
|
||||||
const newNode: Node = {
|
const newNode: Node = {
|
||||||
id: getId(),
|
id: getId(),
|
||||||
type,
|
type,
|
||||||
@@ -51,9 +63,9 @@ const DnDFlow = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="dndflow">
|
<div className='dndflow'>
|
||||||
<ReactFlowProvider>
|
<ReactFlowProvider>
|
||||||
<div className="reactflow-wrapper">
|
<div className='reactflow-wrapper'>
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
edges={edges}
|
edges={edges}
|
||||||
+5
-4
@@ -12,7 +12,7 @@ import ReactFlow, {
|
|||||||
Edge,
|
Edge,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
import { getElements } from './utils';
|
import { getElements } from './utils';
|
||||||
|
|
||||||
const onInit = (reactFlowInstance: ReactFlowInstance) => {
|
const onInit = (reactFlowInstance: ReactFlowInstance) => {
|
||||||
@@ -28,7 +28,8 @@ const deleteKeyCode = ['AltLeft+KeyD', 'Backspace'];
|
|||||||
const EdgeTypesFlow = () => {
|
const EdgeTypesFlow = () => {
|
||||||
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
const onConnect = (params: Connection | Edge) => setEdges((eds) => addEdge(params, eds));
|
const onConnect = (params: Connection | Edge) =>
|
||||||
|
setEdges((eds) => addEdge(params, eds));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
@@ -40,10 +41,10 @@ const EdgeTypesFlow = () => {
|
|||||||
onConnect={onConnect}
|
onConnect={onConnect}
|
||||||
minZoom={0.2}
|
minZoom={0.2}
|
||||||
zoomOnScroll={false}
|
zoomOnScroll={false}
|
||||||
selectionKeyCode="a+s"
|
selectionKeyCode='a+s'
|
||||||
multiSelectionKeyCode={multiSelectionKeyCode}
|
multiSelectionKeyCode={multiSelectionKeyCode}
|
||||||
deleteKeyCode={deleteKeyCode}
|
deleteKeyCode={deleteKeyCode}
|
||||||
zoomActivationKeyCode="z"
|
zoomActivationKeyCode='z'
|
||||||
>
|
>
|
||||||
<MiniMap />
|
<MiniMap />
|
||||||
<Controls />
|
<Controls />
|
||||||
+15
-4
@@ -1,4 +1,4 @@
|
|||||||
import { Edge, Node, Position } from 'react-flow-renderer';
|
import { Edge, Node, Position } from '@react-flow/core';
|
||||||
|
|
||||||
const nodeWidth = 80;
|
const nodeWidth = 80;
|
||||||
const nodeGapWidth = nodeWidth * 2;
|
const nodeGapWidth = nodeWidth * 2;
|
||||||
@@ -54,16 +54,27 @@ const getNodeId = (): string => (id++).toString();
|
|||||||
export function getElements(): { nodes: Node[]; edges: Edge[] } {
|
export function getElements(): { nodes: Node[]; edges: Edge[] } {
|
||||||
const initialElements = { nodes: [] as Node[], edges: [] as Edge[] };
|
const initialElements = { nodes: [] as Node[], edges: [] as Edge[] };
|
||||||
|
|
||||||
for (let sourceTargetIndex = 0; sourceTargetIndex < sourceTargetPositions.length; sourceTargetIndex++) {
|
for (
|
||||||
|
let sourceTargetIndex = 0;
|
||||||
|
sourceTargetIndex < sourceTargetPositions.length;
|
||||||
|
sourceTargetIndex++
|
||||||
|
) {
|
||||||
const currSourceTargetPos = sourceTargetPositions[sourceTargetIndex];
|
const currSourceTargetPos = sourceTargetPositions[sourceTargetIndex];
|
||||||
|
|
||||||
for (let edgeTypeIndex = 0; edgeTypeIndex < edgeTypes.length; edgeTypeIndex++) {
|
for (
|
||||||
|
let edgeTypeIndex = 0;
|
||||||
|
edgeTypeIndex < edgeTypes.length;
|
||||||
|
edgeTypeIndex++
|
||||||
|
) {
|
||||||
const currEdgeType = edgeTypes[edgeTypeIndex];
|
const currEdgeType = edgeTypes[edgeTypeIndex];
|
||||||
|
|
||||||
for (let offsetIndex = 0; offsetIndex < offsets.length; offsetIndex++) {
|
for (let offsetIndex = 0; offsetIndex < offsets.length; offsetIndex++) {
|
||||||
const currOffset = offsets[offsetIndex];
|
const currOffset = offsets[offsetIndex];
|
||||||
|
|
||||||
const style = { ...nodeStyle, background: nodeColors[sourceTargetIndex][edgeTypeIndex] };
|
const style = {
|
||||||
|
...nodeStyle,
|
||||||
|
background: nodeColors[sourceTargetIndex][edgeTypeIndex],
|
||||||
|
};
|
||||||
const sourcePosition = {
|
const sourcePosition = {
|
||||||
x: offsetIndex * nodeWidth * 4,
|
x: offsetIndex * nodeWidth * 4,
|
||||||
y: edgeTypeIndex * 300 + sourceTargetIndex * edgeTypes.length * 300,
|
y: edgeTypeIndex * 300 + sourceTargetIndex * edgeTypes.length * 300,
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
import { EdgeProps, getBezierPath } from '@react-flow/core';
|
||||||
|
|
||||||
|
const CustomEdge: FC<EdgeProps> = ({
|
||||||
|
id,
|
||||||
|
sourceX,
|
||||||
|
sourceY,
|
||||||
|
targetX,
|
||||||
|
targetY,
|
||||||
|
sourcePosition,
|
||||||
|
targetPosition,
|
||||||
|
data,
|
||||||
|
}) => {
|
||||||
|
const edgePath = getBezierPath({
|
||||||
|
sourceX,
|
||||||
|
sourceY,
|
||||||
|
sourcePosition,
|
||||||
|
targetX,
|
||||||
|
targetY,
|
||||||
|
targetPosition,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<path id={id} className='react-flow__edge-path' d={edgePath} />
|
||||||
|
<text>
|
||||||
|
<textPath
|
||||||
|
href={`#${id}`}
|
||||||
|
style={{ fontSize: '12px' }}
|
||||||
|
startOffset='50%'
|
||||||
|
textAnchor='middle'
|
||||||
|
>
|
||||||
|
{data.text}
|
||||||
|
</textPath>
|
||||||
|
</text>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CustomEdge;
|
||||||
+15
-3
@@ -1,5 +1,10 @@
|
|||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { EdgeProps, getBezierPath, EdgeText, getBezierEdgeCenter } from 'react-flow-renderer';
|
import {
|
||||||
|
EdgeProps,
|
||||||
|
getBezierPath,
|
||||||
|
EdgeText,
|
||||||
|
getBezierEdgeCenter,
|
||||||
|
} from '@react-flow/core';
|
||||||
|
|
||||||
const CustomEdge: FC<EdgeProps> = ({
|
const CustomEdge: FC<EdgeProps> = ({
|
||||||
id,
|
id,
|
||||||
@@ -11,7 +16,14 @@ const CustomEdge: FC<EdgeProps> = ({
|
|||||||
targetPosition,
|
targetPosition,
|
||||||
data,
|
data,
|
||||||
}) => {
|
}) => {
|
||||||
const edgePath = getBezierPath({ sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition });
|
const edgePath = getBezierPath({
|
||||||
|
sourceX,
|
||||||
|
sourceY,
|
||||||
|
sourcePosition,
|
||||||
|
targetX,
|
||||||
|
targetY,
|
||||||
|
targetPosition,
|
||||||
|
});
|
||||||
const [centerX, centerY] = getBezierEdgeCenter({
|
const [centerX, centerY] = getBezierEdgeCenter({
|
||||||
sourceX,
|
sourceX,
|
||||||
sourceY,
|
sourceY,
|
||||||
@@ -21,7 +33,7 @@ const CustomEdge: FC<EdgeProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<path id={id} className="react-flow__edge-path" d={edgePath} />
|
<path id={id} className='react-flow__edge-path' d={edgePath} />
|
||||||
<EdgeText
|
<EdgeText
|
||||||
x={centerX}
|
x={centerX}
|
||||||
y={centerY}
|
y={centerY}
|
||||||
@@ -12,21 +12,32 @@ import ReactFlow, {
|
|||||||
ReactFlowInstance,
|
ReactFlowInstance,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
import CustomEdge from './CustomEdge';
|
import CustomEdge from './CustomEdge';
|
||||||
import CustomEdge2 from './CustomEdge2';
|
import CustomEdge2 from './CustomEdge2';
|
||||||
|
|
||||||
const onInit = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.fitView();
|
const onInit = (reactFlowInstance: ReactFlowInstance) =>
|
||||||
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
reactFlowInstance.fitView();
|
||||||
|
const onNodeDragStop = (_: MouseEvent, node: Node) =>
|
||||||
|
console.log('drag stop', node);
|
||||||
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
||||||
const onEdgeClick = (_: MouseEvent, edge: Edge) => console.log('click', edge);
|
const onEdgeClick = (_: MouseEvent, edge: Edge) => console.log('click', edge);
|
||||||
const onEdgeDoubleClick = (_: MouseEvent, edge: Edge) => console.log('dblclick', edge);
|
const onEdgeDoubleClick = (_: MouseEvent, edge: Edge) =>
|
||||||
const onEdgeMouseEnter = (_: MouseEvent, edge: Edge) => console.log('enter', edge);
|
console.log('dblclick', edge);
|
||||||
const onEdgeMouseMove = (_: MouseEvent, edge: Edge) => console.log('move', edge);
|
const onEdgeMouseEnter = (_: MouseEvent, edge: Edge) =>
|
||||||
const onEdgeMouseLeave = (_: MouseEvent, edge: Edge) => console.log('leave', edge);
|
console.log('enter', edge);
|
||||||
|
const onEdgeMouseMove = (_: MouseEvent, edge: Edge) =>
|
||||||
|
console.log('move', edge);
|
||||||
|
const onEdgeMouseLeave = (_: MouseEvent, edge: Edge) =>
|
||||||
|
console.log('leave', edge);
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
{ id: '1', type: 'input', data: { label: 'Input 1' }, position: { x: 250, y: 0 } },
|
{
|
||||||
|
id: '1',
|
||||||
|
type: 'input',
|
||||||
|
data: { label: 'Input 1' },
|
||||||
|
position: { x: 250, y: 0 },
|
||||||
|
},
|
||||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 150, y: 100 } },
|
{ id: '2', data: { label: 'Node 2' }, position: { x: 150, y: 100 } },
|
||||||
{ id: '2a', data: { label: 'Node 2a' }, position: { x: 0, y: 180 } },
|
{ id: '2a', data: { label: 'Node 2a' }, position: { x: 0, y: 180 } },
|
||||||
{ id: '2b', data: { label: 'Node 2b' }, position: { x: -40, y: 300 } },
|
{ id: '2b', data: { label: 'Node 2b' }, position: { x: -40, y: 300 } },
|
||||||
@@ -34,15 +45,47 @@ const initialNodes: Node[] = [
|
|||||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 300 } },
|
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 300 } },
|
||||||
{ id: '3a', data: { label: 'Node 3a' }, position: { x: 150, y: 300 } },
|
{ id: '3a', data: { label: 'Node 3a' }, position: { x: 150, y: 300 } },
|
||||||
{ id: '5', data: { label: 'Node 5' }, position: { x: 250, y: 400 } },
|
{ id: '5', data: { label: 'Node 5' }, position: { x: 250, y: 400 } },
|
||||||
{ id: '6', type: 'output', data: { label: 'Output 6' }, position: { x: 50, y: 550 } },
|
{
|
||||||
{ id: '7', type: 'output', data: { label: 'Output 7' }, position: { x: 250, y: 550 } },
|
id: '6',
|
||||||
{ id: '8', type: 'output', data: { label: 'Output 8' }, position: { x: 525, y: 600 } },
|
type: 'output',
|
||||||
{ id: '9', type: 'output', data: { label: 'Output 9' }, position: { x: 675, y: 500 } },
|
data: { label: 'Output 6' },
|
||||||
|
position: { x: 50, y: 550 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '7',
|
||||||
|
type: 'output',
|
||||||
|
data: { label: 'Output 7' },
|
||||||
|
position: { x: 250, y: 550 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '8',
|
||||||
|
type: 'output',
|
||||||
|
data: { label: 'Output 8' },
|
||||||
|
position: { x: 525, y: 600 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '9',
|
||||||
|
type: 'output',
|
||||||
|
data: { label: 'Output 9' },
|
||||||
|
position: { x: 675, y: 500 },
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const initialEdges: Edge[] = [
|
const initialEdges: Edge[] = [
|
||||||
{ id: 'e1-2', source: '1', target: '2', label: 'bezier edge (default)', className: 'normal-edge' },
|
{
|
||||||
{ id: 'e2-2a', source: '2', target: '2a', type: 'smoothstep', label: 'smoothstep edge' },
|
id: 'e1-2',
|
||||||
|
source: '1',
|
||||||
|
target: '2',
|
||||||
|
label: 'bezier edge (default)',
|
||||||
|
className: 'normal-edge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'e2-2a',
|
||||||
|
source: '2',
|
||||||
|
target: '2a',
|
||||||
|
type: 'smoothstep',
|
||||||
|
label: 'smoothstep edge',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'e2a-2b',
|
id: 'e2a-2b',
|
||||||
source: '2a',
|
source: '2a',
|
||||||
@@ -51,9 +94,29 @@ const initialEdges: Edge[] = [
|
|||||||
label: 'simple bezier edge',
|
label: 'simple bezier edge',
|
||||||
},
|
},
|
||||||
{ id: 'e2-3', source: '2', target: '3', type: 'step', label: 'step edge' },
|
{ id: 'e2-3', source: '2', target: '3', type: 'step', label: 'step edge' },
|
||||||
{ id: 'e3-4', source: '3', target: '4', type: 'straight', label: 'straight edge' },
|
{
|
||||||
{ id: 'e3-3a', source: '3', target: '3a', type: 'straight', label: 'label only edge', style: { stroke: 'none' } },
|
id: 'e3-4',
|
||||||
{ id: 'e3-5', source: '4', target: '5', animated: true, label: 'animated styled edge', style: { stroke: 'red' } },
|
source: '3',
|
||||||
|
target: '4',
|
||||||
|
type: 'straight',
|
||||||
|
label: 'straight edge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'e3-3a',
|
||||||
|
source: '3',
|
||||||
|
target: '3a',
|
||||||
|
type: 'straight',
|
||||||
|
label: 'label only edge',
|
||||||
|
style: { stroke: 'none' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'e3-5',
|
||||||
|
source: '4',
|
||||||
|
target: '5',
|
||||||
|
animated: true,
|
||||||
|
label: 'animated styled edge',
|
||||||
|
style: { stroke: 'red' },
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'e5-7',
|
id: 'e5-7',
|
||||||
source: '5',
|
source: '5',
|
||||||
@@ -121,7 +184,8 @@ const edgeTypes: EdgeTypes = {
|
|||||||
const EdgesFlow = () => {
|
const EdgesFlow = () => {
|
||||||
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
const onConnect = (params: Connection | Edge) => setEdges((eds) => addEdge(params, eds));
|
const onConnect = (params: Connection | Edge) =>
|
||||||
|
setEdges((eds) => addEdge(params, eds));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
@@ -11,25 +11,36 @@ import ReactFlow, {
|
|||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
ReactFlowInstance,
|
ReactFlowInstance,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
const onInit = (reactFlowInstance: ReactFlowInstance) => console.log('flow loaded:', reactFlowInstance);
|
const onInit = (reactFlowInstance: ReactFlowInstance) =>
|
||||||
|
console.log('flow loaded:', reactFlowInstance);
|
||||||
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
||||||
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
const onNodeDragStop = (_: MouseEvent, node: Node) =>
|
||||||
|
console.log('drag stop', node);
|
||||||
|
|
||||||
const buttonStyle: CSSProperties = { position: 'absolute', left: 10, top: 10, zIndex: 4 };
|
const buttonStyle: CSSProperties = {
|
||||||
|
position: 'absolute',
|
||||||
|
left: 10,
|
||||||
|
top: 10,
|
||||||
|
zIndex: 4,
|
||||||
|
};
|
||||||
|
|
||||||
const EmptyFlow = () => {
|
const EmptyFlow = () => {
|
||||||
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
||||||
|
|
||||||
const onConnect = (params: Connection | Edge) => setEdges((els) => addEdge(params, els));
|
const onConnect = (params: Connection | Edge) =>
|
||||||
|
setEdges((els) => addEdge(params, els));
|
||||||
const addRandomNode = () => {
|
const addRandomNode = () => {
|
||||||
const nodeId = (nodes.length + 1).toString();
|
const nodeId = (nodes.length + 1).toString();
|
||||||
const newNode: Node = {
|
const newNode: Node = {
|
||||||
id: nodeId,
|
id: nodeId,
|
||||||
data: { label: `Node: ${nodeId}` },
|
data: { label: `Node: ${nodeId}` },
|
||||||
position: { x: Math.random() * window.innerWidth, y: Math.random() * window.innerHeight },
|
position: {
|
||||||
|
x: Math.random() * window.innerWidth,
|
||||||
|
y: Math.random() * window.innerHeight,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
setNodes((nds) => nds.concat(newNode));
|
setNodes((nds) => nds.concat(newNode));
|
||||||
};
|
};
|
||||||
@@ -49,7 +60,7 @@ const EmptyFlow = () => {
|
|||||||
<Controls />
|
<Controls />
|
||||||
<Background variant={BackgroundVariant.Lines} />
|
<Background variant={BackgroundVariant.Lines} />
|
||||||
|
|
||||||
<button type="button" onClick={addRandomNode} style={buttonStyle}>
|
<button type='button' onClick={addRandomNode} style={buttonStyle}>
|
||||||
add node
|
add node
|
||||||
</button>
|
</button>
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
+20
-3
@@ -1,5 +1,9 @@
|
|||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { getBezierPath, ConnectionLineComponentProps, Node } from 'react-flow-renderer';
|
import {
|
||||||
|
getBezierPath,
|
||||||
|
ConnectionLineComponentProps,
|
||||||
|
Node,
|
||||||
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import { getEdgeParams } from './utils';
|
import { getEdgeParams } from './utils';
|
||||||
|
|
||||||
@@ -33,8 +37,21 @@ const FloatingConnectionLine: FC<ConnectionLineComponentProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<g>
|
<g>
|
||||||
<path fill="none" stroke="#222" strokeWidth={1.5} className="animated" d={d} />
|
<path
|
||||||
<circle cx={targetX} cy={targetY} fill="#fff" r={3} stroke="#222" strokeWidth={1.5} />
|
fill='none'
|
||||||
|
stroke='#222'
|
||||||
|
strokeWidth={1.5}
|
||||||
|
className='animated'
|
||||||
|
d={d}
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
cx={targetX}
|
||||||
|
cy={targetY}
|
||||||
|
fill='#fff'
|
||||||
|
r={3}
|
||||||
|
stroke='#222'
|
||||||
|
strokeWidth={1.5}
|
||||||
|
/>
|
||||||
</g>
|
</g>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
+25
-6
@@ -1,5 +1,10 @@
|
|||||||
import { FC, useMemo, CSSProperties } from 'react';
|
import { FC, useMemo, CSSProperties } from 'react';
|
||||||
import { EdgeProps, useStore, getBezierPath, ReactFlowState } from 'react-flow-renderer';
|
import {
|
||||||
|
EdgeProps,
|
||||||
|
useStore,
|
||||||
|
getBezierPath,
|
||||||
|
ReactFlowState,
|
||||||
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import { getEdgeParams } from './utils';
|
import { getEdgeParams } from './utils';
|
||||||
|
|
||||||
@@ -8,14 +13,23 @@ const nodeSelector = (s: ReactFlowState) => s.nodeInternals;
|
|||||||
const FloatingEdge: FC<EdgeProps> = ({ id, source, target, style }) => {
|
const FloatingEdge: FC<EdgeProps> = ({ id, source, target, style }) => {
|
||||||
const nodeInternals = useStore(nodeSelector);
|
const nodeInternals = useStore(nodeSelector);
|
||||||
|
|
||||||
const sourceNode = useMemo(() => nodeInternals.get(source), [source, nodeInternals]);
|
const sourceNode = useMemo(
|
||||||
const targetNode = useMemo(() => nodeInternals.get(target), [target, nodeInternals]);
|
() => nodeInternals.get(source),
|
||||||
|
[source, nodeInternals]
|
||||||
|
);
|
||||||
|
const targetNode = useMemo(
|
||||||
|
() => nodeInternals.get(target),
|
||||||
|
[target, nodeInternals]
|
||||||
|
);
|
||||||
|
|
||||||
if (!sourceNode || !targetNode) {
|
if (!sourceNode || !targetNode) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { sx, sy, tx, ty, sourcePos, targetPos } = getEdgeParams(sourceNode, targetNode);
|
const { sx, sy, tx, ty, sourcePos, targetPos } = getEdgeParams(
|
||||||
|
sourceNode,
|
||||||
|
targetNode
|
||||||
|
);
|
||||||
|
|
||||||
const d = getBezierPath({
|
const d = getBezierPath({
|
||||||
sourceX: sx,
|
sourceX: sx,
|
||||||
@@ -27,8 +41,13 @@ const FloatingEdge: FC<EdgeProps> = ({ id, source, target, style }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g className="react-flow__connection">
|
<g className='react-flow__connection'>
|
||||||
<path id={id} className="react-flow__edge-path" d={d} style={style as CSSProperties} />
|
<path
|
||||||
|
id={id}
|
||||||
|
className='react-flow__edge-path'
|
||||||
|
d={d}
|
||||||
|
style={style as CSSProperties}
|
||||||
|
/>
|
||||||
</g>
|
</g>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
+4
-3
@@ -8,7 +8,7 @@ import ReactFlow, {
|
|||||||
Connection,
|
Connection,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import './style.css';
|
import './style.css';
|
||||||
|
|
||||||
@@ -16,7 +16,8 @@ import FloatingEdge from './FloatingEdge';
|
|||||||
import FloatingConnectionLine from './FloatingConnectionLine';
|
import FloatingConnectionLine from './FloatingConnectionLine';
|
||||||
import { createElements } from './utils';
|
import { createElements } from './utils';
|
||||||
|
|
||||||
const onInit = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.fitView();
|
const onInit = (reactFlowInstance: ReactFlowInstance) =>
|
||||||
|
reactFlowInstance.fitView();
|
||||||
|
|
||||||
const { nodes: initialNodes, edges: initialEdges } = createElements();
|
const { nodes: initialNodes, edges: initialEdges } = createElements();
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ const FloatingEdges = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="floatingedges">
|
<div className='floatingedges'>
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
edges={edges}
|
edges={edges}
|
||||||
+5
-2
@@ -1,8 +1,11 @@
|
|||||||
import { Position, XYPosition, Node, Edge } from 'react-flow-renderer';
|
import { Position, XYPosition, Node, Edge } from '@react-flow/core';
|
||||||
|
|
||||||
// this helper function returns the intersection point
|
// this helper function returns the intersection point
|
||||||
// of the line between the center of the intersectionNode and the target node
|
// of the line between the center of the intersectionNode and the target node
|
||||||
function getNodeIntersection(intersectionNode: Node, targetNode: Node): XYPosition {
|
function getNodeIntersection(
|
||||||
|
intersectionNode: Node,
|
||||||
|
targetNode: Node
|
||||||
|
): XYPosition {
|
||||||
// https://math.stackexchange.com/questions/1724792/an-algorithm-for-finding-the-intersection-point-between-a-center-of-vision-and-a
|
// https://math.stackexchange.com/questions/1724792/an-algorithm-for-finding-the-intersection-point-between-a-center-of-vision-and-a
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -10,13 +10,34 @@ import ReactFlow, {
|
|||||||
Node,
|
Node,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
{ id: '1', type: 'input', hidden: true, data: { label: 'Node 1' }, position: { x: 250, y: 5 } },
|
{
|
||||||
{ id: '2', hidden: true, data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
|
id: '1',
|
||||||
{ id: '3', hidden: true, data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
|
type: 'input',
|
||||||
{ id: '4', hidden: true, data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
|
hidden: true,
|
||||||
|
data: { label: 'Node 1' },
|
||||||
|
position: { x: 250, y: 5 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
hidden: true,
|
||||||
|
data: { label: 'Node 2' },
|
||||||
|
position: { x: 100, y: 100 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
hidden: true,
|
||||||
|
data: { label: 'Node 3' },
|
||||||
|
position: { x: 400, y: 100 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
hidden: true,
|
||||||
|
data: { label: 'Node 4' },
|
||||||
|
position: { x: 400, y: 200 },
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const initialEdges: Edge[] = [
|
const initialEdges: Edge[] = [
|
||||||
@@ -64,14 +85,14 @@ const HiddenFlow = () => {
|
|||||||
|
|
||||||
<div style={{ position: 'absolute', left: 10, top: 10, zIndex: 4 }}>
|
<div style={{ position: 'absolute', left: 10, top: 10, zIndex: 4 }}>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="ishidden">
|
<label htmlFor='ishidden'>
|
||||||
isHidden
|
isHidden
|
||||||
<input
|
<input
|
||||||
id="ishidden"
|
id='ishidden'
|
||||||
type="checkbox"
|
type='checkbox'
|
||||||
checked={isHidden}
|
checked={isHidden}
|
||||||
onChange={(event) => setIsHidden(event.target.checked)}
|
onChange={(event) => setIsHidden(event.target.checked)}
|
||||||
className="react-flow__ishidden"
|
className='react-flow__ishidden'
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
+81
-63
@@ -10,10 +10,15 @@ import ReactFlow, {
|
|||||||
Viewport,
|
Viewport,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } },
|
{
|
||||||
|
id: '1',
|
||||||
|
type: 'input',
|
||||||
|
data: { label: 'Node 1' },
|
||||||
|
position: { x: 250, y: 5 },
|
||||||
|
},
|
||||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
|
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
|
||||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
|
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
|
||||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
|
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
|
||||||
@@ -24,19 +29,27 @@ const initialEdges: Edge[] = [
|
|||||||
{ id: 'e1-3', source: '1', target: '3' },
|
{ id: 'e1-3', source: '1', target: '3' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const onNodeDragStart = (_: ReactMouseEvent, node: Node) => console.log('drag start', node);
|
const onNodeDragStart = (_: ReactMouseEvent, node: Node) =>
|
||||||
const onNodeDragStop = (_: ReactMouseEvent, node: Node) => console.log('drag stop', node);
|
console.log('drag start', node);
|
||||||
const onNodeClick = (_: ReactMouseEvent, node: Node) => console.log('click', node);
|
const onNodeDragStop = (_: ReactMouseEvent, node: Node) =>
|
||||||
const onEdgeClick = (_: ReactMouseEvent, edge: Edge) => console.log('click', edge);
|
console.log('drag stop', node);
|
||||||
const onPaneClick = (event: ReactMouseEvent) => console.log('onPaneClick', event);
|
const onNodeClick = (_: ReactMouseEvent, node: Node) =>
|
||||||
|
console.log('click', node);
|
||||||
|
const onEdgeClick = (_: ReactMouseEvent, edge: Edge) =>
|
||||||
|
console.log('click', edge);
|
||||||
|
const onPaneClick = (event: ReactMouseEvent) =>
|
||||||
|
console.log('onPaneClick', event);
|
||||||
const onPaneScroll = (event?: WheelEvent) => console.log('onPaneScroll', event);
|
const onPaneScroll = (event?: WheelEvent) => console.log('onPaneScroll', event);
|
||||||
const onPaneContextMenu = (event: ReactMouseEvent) => console.log('onPaneContextMenu', event);
|
const onPaneContextMenu = (event: ReactMouseEvent) =>
|
||||||
const onMoveEnd = (_: TouchEvent | MouseEvent, viewport: Viewport) => console.log('onMoveEnd', viewport);
|
console.log('onPaneContextMenu', event);
|
||||||
|
const onMoveEnd = (_: TouchEvent | MouseEvent, viewport: Viewport) =>
|
||||||
|
console.log('onMoveEnd', viewport);
|
||||||
|
|
||||||
const InteractionFlow = () => {
|
const InteractionFlow = () => {
|
||||||
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
const onConnect = (params: Connection | Edge) => setEdges((els) => addEdge(params, els));
|
const onConnect = (params: Connection | Edge) =>
|
||||||
|
setEdges((els) => addEdge(params, els));
|
||||||
|
|
||||||
const [isSelectable, setIsSelectable] = useState<boolean>(false);
|
const [isSelectable, setIsSelectable] = useState<boolean>(false);
|
||||||
const [isDraggable, setIsDraggable] = useState<boolean>(false);
|
const [isDraggable, setIsDraggable] = useState<boolean>(false);
|
||||||
@@ -44,12 +57,15 @@ const InteractionFlow = () => {
|
|||||||
const [zoomOnScroll, setZoomOnScroll] = useState<boolean>(false);
|
const [zoomOnScroll, setZoomOnScroll] = useState<boolean>(false);
|
||||||
const [zoomOnPinch, setZoomOnPinch] = useState<boolean>(false);
|
const [zoomOnPinch, setZoomOnPinch] = useState<boolean>(false);
|
||||||
const [panOnScroll, setPanOnScroll] = useState<boolean>(false);
|
const [panOnScroll, setPanOnScroll] = useState<boolean>(false);
|
||||||
const [panOnScrollMode, setPanOnScrollMode] = useState<PanOnScrollMode>(PanOnScrollMode.Free);
|
const [panOnScrollMode, setPanOnScrollMode] = useState<PanOnScrollMode>(
|
||||||
|
PanOnScrollMode.Free
|
||||||
|
);
|
||||||
const [zoomOnDoubleClick, setZoomOnDoubleClick] = useState<boolean>(false);
|
const [zoomOnDoubleClick, setZoomOnDoubleClick] = useState<boolean>(false);
|
||||||
const [panOnDrag, setPanOnDrag] = useState<boolean>(true);
|
const [panOnDrag, setPanOnDrag] = useState<boolean>(true);
|
||||||
const [captureZoomClick, setCaptureZoomClick] = useState<boolean>(false);
|
const [captureZoomClick, setCaptureZoomClick] = useState<boolean>(false);
|
||||||
const [captureZoomScroll, setCaptureZoomScroll] = useState<boolean>(false);
|
const [captureZoomScroll, setCaptureZoomScroll] = useState<boolean>(false);
|
||||||
const [captureElementClick, setCaptureElementClick] = useState<boolean>(false);
|
const [captureElementClick, setCaptureElementClick] =
|
||||||
|
useState<boolean>(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
@@ -81,149 +97,151 @@ const InteractionFlow = () => {
|
|||||||
|
|
||||||
<div style={{ position: 'absolute', left: 10, top: 10, zIndex: 4 }}>
|
<div style={{ position: 'absolute', left: 10, top: 10, zIndex: 4 }}>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="draggable">
|
<label htmlFor='draggable'>
|
||||||
nodesDraggable
|
nodesDraggable
|
||||||
<input
|
<input
|
||||||
id="draggable"
|
id='draggable'
|
||||||
type="checkbox"
|
type='checkbox'
|
||||||
checked={isDraggable}
|
checked={isDraggable}
|
||||||
onChange={(event) => setIsDraggable(event.target.checked)}
|
onChange={(event) => setIsDraggable(event.target.checked)}
|
||||||
className="react-flow__draggable"
|
className='react-flow__draggable'
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="connectable">
|
<label htmlFor='connectable'>
|
||||||
nodesConnectable
|
nodesConnectable
|
||||||
<input
|
<input
|
||||||
id="connectable"
|
id='connectable'
|
||||||
type="checkbox"
|
type='checkbox'
|
||||||
checked={isConnectable}
|
checked={isConnectable}
|
||||||
onChange={(event) => setIsConnectable(event.target.checked)}
|
onChange={(event) => setIsConnectable(event.target.checked)}
|
||||||
className="react-flow__connectable"
|
className='react-flow__connectable'
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="selectable">
|
<label htmlFor='selectable'>
|
||||||
elementsSelectable
|
elementsSelectable
|
||||||
<input
|
<input
|
||||||
id="selectable"
|
id='selectable'
|
||||||
type="checkbox"
|
type='checkbox'
|
||||||
checked={isSelectable}
|
checked={isSelectable}
|
||||||
onChange={(event) => setIsSelectable(event.target.checked)}
|
onChange={(event) => setIsSelectable(event.target.checked)}
|
||||||
className="react-flow__selectable"
|
className='react-flow__selectable'
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="zoomonscroll">
|
<label htmlFor='zoomonscroll'>
|
||||||
zoomOnScroll
|
zoomOnScroll
|
||||||
<input
|
<input
|
||||||
id="zoomonscroll"
|
id='zoomonscroll'
|
||||||
type="checkbox"
|
type='checkbox'
|
||||||
checked={zoomOnScroll}
|
checked={zoomOnScroll}
|
||||||
onChange={(event) => setZoomOnScroll(event.target.checked)}
|
onChange={(event) => setZoomOnScroll(event.target.checked)}
|
||||||
className="react-flow__zoomonscroll"
|
className='react-flow__zoomonscroll'
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="zoomonpinch">
|
<label htmlFor='zoomonpinch'>
|
||||||
zoomOnPinch
|
zoomOnPinch
|
||||||
<input
|
<input
|
||||||
id="zoomonpinch"
|
id='zoomonpinch'
|
||||||
type="checkbox"
|
type='checkbox'
|
||||||
checked={zoomOnPinch}
|
checked={zoomOnPinch}
|
||||||
onChange={(event) => setZoomOnPinch(event.target.checked)}
|
onChange={(event) => setZoomOnPinch(event.target.checked)}
|
||||||
className="react-flow__zoomonpinch"
|
className='react-flow__zoomonpinch'
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="panonscroll">
|
<label htmlFor='panonscroll'>
|
||||||
panOnScroll
|
panOnScroll
|
||||||
<input
|
<input
|
||||||
id="panonscroll"
|
id='panonscroll'
|
||||||
type="checkbox"
|
type='checkbox'
|
||||||
checked={panOnScroll}
|
checked={panOnScroll}
|
||||||
onChange={(event) => setPanOnScroll(event.target.checked)}
|
onChange={(event) => setPanOnScroll(event.target.checked)}
|
||||||
className="react-flow__panonscroll"
|
className='react-flow__panonscroll'
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="panonscrollmode">
|
<label htmlFor='panonscrollmode'>
|
||||||
panOnScrollMode
|
panOnScrollMode
|
||||||
<select
|
<select
|
||||||
id="panonscrollmode"
|
id='panonscrollmode'
|
||||||
value={panOnScrollMode}
|
value={panOnScrollMode}
|
||||||
onChange={(event) => setPanOnScrollMode(event.target.value as PanOnScrollMode)}
|
onChange={(event) =>
|
||||||
className="react-flow__panonscrollmode"
|
setPanOnScrollMode(event.target.value as PanOnScrollMode)
|
||||||
|
}
|
||||||
|
className='react-flow__panonscrollmode'
|
||||||
>
|
>
|
||||||
<option value="free">free</option>
|
<option value='free'>free</option>
|
||||||
<option value="horizontal">horizontal</option>
|
<option value='horizontal'>horizontal</option>
|
||||||
<option value="vertical">vertical</option>
|
<option value='vertical'>vertical</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="zoomondbl">
|
<label htmlFor='zoomondbl'>
|
||||||
zoomOnDoubleClick
|
zoomOnDoubleClick
|
||||||
<input
|
<input
|
||||||
id="zoomondbl"
|
id='zoomondbl'
|
||||||
type="checkbox"
|
type='checkbox'
|
||||||
checked={zoomOnDoubleClick}
|
checked={zoomOnDoubleClick}
|
||||||
onChange={(event) => setZoomOnDoubleClick(event.target.checked)}
|
onChange={(event) => setZoomOnDoubleClick(event.target.checked)}
|
||||||
className="react-flow__zoomondbl"
|
className='react-flow__zoomondbl'
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="panondrag">
|
<label htmlFor='panondrag'>
|
||||||
panOnDrag
|
panOnDrag
|
||||||
<input
|
<input
|
||||||
id="panondrag"
|
id='panondrag'
|
||||||
type="checkbox"
|
type='checkbox'
|
||||||
checked={panOnDrag}
|
checked={panOnDrag}
|
||||||
onChange={(event) => setPanOnDrag(event.target.checked)}
|
onChange={(event) => setPanOnDrag(event.target.checked)}
|
||||||
className="react-flow__panondrag"
|
className='react-flow__panondrag'
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="capturezoompaneclick">
|
<label htmlFor='capturezoompaneclick'>
|
||||||
capture onPaneClick
|
capture onPaneClick
|
||||||
<input
|
<input
|
||||||
id="capturezoompaneclick"
|
id='capturezoompaneclick'
|
||||||
type="checkbox"
|
type='checkbox'
|
||||||
checked={captureZoomClick}
|
checked={captureZoomClick}
|
||||||
onChange={(event) => setCaptureZoomClick(event.target.checked)}
|
onChange={(event) => setCaptureZoomClick(event.target.checked)}
|
||||||
className="react-flow__capturezoompaneclick"
|
className='react-flow__capturezoompaneclick'
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="capturezoompanescroll">
|
<label htmlFor='capturezoompanescroll'>
|
||||||
capture onPaneScroll
|
capture onPaneScroll
|
||||||
<input
|
<input
|
||||||
id="capturezoompanescroll"
|
id='capturezoompanescroll'
|
||||||
type="checkbox"
|
type='checkbox'
|
||||||
checked={captureZoomScroll}
|
checked={captureZoomScroll}
|
||||||
onChange={(event) => setCaptureZoomScroll(event.target.checked)}
|
onChange={(event) => setCaptureZoomScroll(event.target.checked)}
|
||||||
className="react-flow__capturezoompanescroll"
|
className='react-flow__capturezoompanescroll'
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="captureelementclick">
|
<label htmlFor='captureelementclick'>
|
||||||
capture onElementClick
|
capture onElementClick
|
||||||
<input
|
<input
|
||||||
id="captureelementclick"
|
id='captureelementclick'
|
||||||
type="checkbox"
|
type='checkbox'
|
||||||
checked={captureElementClick}
|
checked={captureElementClick}
|
||||||
onChange={(event) => setCaptureElementClick(event.target.checked)}
|
onChange={(event) => setCaptureElementClick(event.target.checked)}
|
||||||
className="react-flow__captureelementclick"
|
className='react-flow__captureelementclick'
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
+11
-5
@@ -10,7 +10,7 @@ import ReactFlow, {
|
|||||||
useEdgesState,
|
useEdgesState,
|
||||||
MarkerType,
|
MarkerType,
|
||||||
EdgeMarker,
|
EdgeMarker,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
import dagre from 'dagre';
|
import dagre from 'dagre';
|
||||||
|
|
||||||
import initialItems from './initial-elements';
|
import initialItems from './initial-elements';
|
||||||
@@ -56,7 +56,10 @@ const LayoutFlow = () => {
|
|||||||
node.sourcePosition = isHorizontal ? Position.Right : Position.Bottom;
|
node.sourcePosition = isHorizontal ? Position.Right : Position.Bottom;
|
||||||
// we need to pass a slightly different position in order to notify react flow about the change
|
// we need to pass a slightly different position in order to notify react flow about the change
|
||||||
// @TODO how can we change the position handling so that we dont need this hack?
|
// @TODO how can we change the position handling so that we dont need this hack?
|
||||||
node.position = { x: nodeWithPosition.x + Math.random() / 1000, y: nodeWithPosition.y };
|
node.position = {
|
||||||
|
x: nodeWithPosition.x + Math.random() / 1000,
|
||||||
|
y: nodeWithPosition.y,
|
||||||
|
};
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
});
|
});
|
||||||
@@ -73,14 +76,17 @@ const LayoutFlow = () => {
|
|||||||
eds.map((e) => ({
|
eds.map((e) => ({
|
||||||
...e,
|
...e,
|
||||||
markerEnd: {
|
markerEnd: {
|
||||||
type: (e.markerEnd as EdgeMarker)?.type === MarkerType.Arrow ? MarkerType.ArrowClosed : MarkerType.Arrow,
|
type:
|
||||||
|
(e.markerEnd as EdgeMarker)?.type === MarkerType.Arrow
|
||||||
|
? MarkerType.ArrowClosed
|
||||||
|
: MarkerType.Arrow,
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="layoutflow">
|
<div className='layoutflow'>
|
||||||
<ReactFlowProvider>
|
<ReactFlowProvider>
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
@@ -93,7 +99,7 @@ const LayoutFlow = () => {
|
|||||||
>
|
>
|
||||||
<Controls />
|
<Controls />
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
<div className="controls">
|
<div className='controls'>
|
||||||
<button onClick={() => onLayout('TB')} style={{ marginRight: 10 }}>
|
<button onClick={() => onLayout('TB')} style={{ marginRight: 10 }}>
|
||||||
vertical layout
|
vertical layout
|
||||||
</button>
|
</button>
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
import { Node, Edge, XYPosition, MarkerType } from '@react-flow/core';
|
||||||
|
|
||||||
|
const position: XYPosition = { x: 0, y: 0 };
|
||||||
|
|
||||||
|
const nodes: Node[] = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
type: 'input',
|
||||||
|
data: { label: 'input' },
|
||||||
|
position,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
data: { label: 'node 2' },
|
||||||
|
position,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2a',
|
||||||
|
data: { label: 'node 2a' },
|
||||||
|
position,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2b',
|
||||||
|
data: { label: 'node 2b' },
|
||||||
|
position,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2c',
|
||||||
|
data: { label: 'node 2c' },
|
||||||
|
position,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2d',
|
||||||
|
data: { label: 'node 2d' },
|
||||||
|
position,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
data: { label: 'node 3' },
|
||||||
|
position,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
data: { label: 'node 4' },
|
||||||
|
position,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '5',
|
||||||
|
data: { label: 'node 5' },
|
||||||
|
position,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '6',
|
||||||
|
type: 'output',
|
||||||
|
data: { label: 'output' },
|
||||||
|
position,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '7',
|
||||||
|
type: 'output',
|
||||||
|
data: { label: 'output' },
|
||||||
|
position: { x: 400, y: 450 },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const edges: Edge[] = [
|
||||||
|
{
|
||||||
|
id: 'e12',
|
||||||
|
source: '1',
|
||||||
|
target: '2',
|
||||||
|
type: 'smoothstep',
|
||||||
|
markerEnd: { type: MarkerType.Arrow },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'e13',
|
||||||
|
source: '1',
|
||||||
|
target: '3',
|
||||||
|
type: 'smoothstep',
|
||||||
|
markerEnd: { type: MarkerType.Arrow },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'e22a',
|
||||||
|
source: '2',
|
||||||
|
target: '2a',
|
||||||
|
type: 'smoothstep',
|
||||||
|
markerEnd: { type: MarkerType.Arrow },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'e22b',
|
||||||
|
source: '2',
|
||||||
|
target: '2b',
|
||||||
|
type: 'smoothstep',
|
||||||
|
markerEnd: { type: MarkerType.Arrow },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'e22c',
|
||||||
|
source: '2',
|
||||||
|
target: '2c',
|
||||||
|
type: 'smoothstep',
|
||||||
|
markerEnd: { type: MarkerType.Arrow },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'e2c2d',
|
||||||
|
source: '2c',
|
||||||
|
target: '2d',
|
||||||
|
type: 'smoothstep',
|
||||||
|
markerEnd: { type: MarkerType.Arrow },
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: 'e45',
|
||||||
|
source: '4',
|
||||||
|
target: '5',
|
||||||
|
type: 'smoothstep',
|
||||||
|
markerEnd: { type: MarkerType.Arrow },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'e56',
|
||||||
|
source: '5',
|
||||||
|
target: '6',
|
||||||
|
type: 'smoothstep',
|
||||||
|
markerEnd: { type: MarkerType.Arrow },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'e57',
|
||||||
|
source: '5',
|
||||||
|
target: '7',
|
||||||
|
type: 'smoothstep',
|
||||||
|
markerEnd: { type: MarkerType.Arrow },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const nodesAndEdges = { nodes, edges };
|
||||||
|
|
||||||
|
export default nodesAndEdges;
|
||||||
+38
-10
@@ -10,19 +10,46 @@ import ReactFlow, {
|
|||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
MarkerType,
|
MarkerType,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import './multiflows.css';
|
import './multiflows.css';
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 }, className: 'light' },
|
{
|
||||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, className: 'light' },
|
id: '1',
|
||||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, className: 'light' },
|
type: 'input',
|
||||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 }, className: 'light' },
|
data: { label: 'Node 1' },
|
||||||
|
position: { x: 250, y: 5 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
data: { label: 'Node 2' },
|
||||||
|
position: { x: 100, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
data: { label: 'Node 3' },
|
||||||
|
position: { x: 400, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
data: { label: 'Node 4' },
|
||||||
|
position: { x: 400, y: 200 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const initialEdges: Edge[] = [
|
const initialEdges: Edge[] = [
|
||||||
{ id: 'e1-2', source: '1', target: '2', animated: true, markerEnd: { type: MarkerType.Arrow } },
|
{
|
||||||
|
id: 'e1-2',
|
||||||
|
source: '1',
|
||||||
|
target: '2',
|
||||||
|
animated: true,
|
||||||
|
markerEnd: { type: MarkerType.Arrow },
|
||||||
|
},
|
||||||
{ id: 'e1-3', source: '1', target: '3' },
|
{ id: 'e1-3', source: '1', target: '3' },
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -30,7 +57,8 @@ const Flow: FC<{ id: string }> = ({ id }) => {
|
|||||||
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
|
|
||||||
const onConnect = (params: Edge | Connection) => setEdges((eds) => addEdge(params, eds));
|
const onConnect = (params: Edge | Connection) =>
|
||||||
|
setEdges((eds) => addEdge(params, eds));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlowProvider>
|
<ReactFlowProvider>
|
||||||
@@ -49,9 +77,9 @@ const Flow: FC<{ id: string }> = ({ id }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const MultiFlows: FC = () => (
|
const MultiFlows: FC = () => (
|
||||||
<div className="react-flow__example-multiflows">
|
<div className='react-flow__example-multiflows'>
|
||||||
<Flow id="flow-a" />
|
<Flow id='flow-a' />
|
||||||
<Flow id="flow-b" />
|
<Flow id='flow-b' />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
+26
-7
@@ -11,14 +11,21 @@ import ReactFlow, {
|
|||||||
Edge,
|
Edge,
|
||||||
ReactFlowInstance,
|
ReactFlowInstance,
|
||||||
Connection,
|
Connection,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
const onNodeDragStop = (_: MouseEvent, node: Node) =>
|
||||||
|
console.log('drag stop', node);
|
||||||
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
||||||
const onEdgeClick = (_: MouseEvent, edge: Edge) => console.log('click', edge);
|
const onEdgeClick = (_: MouseEvent, edge: Edge) => console.log('click', edge);
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 }, className: 'light' },
|
{
|
||||||
|
id: '1',
|
||||||
|
type: 'input',
|
||||||
|
data: { label: 'Node 1' },
|
||||||
|
position: { x: 250, y: 5 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: '2',
|
id: '2',
|
||||||
data: { label: 'Node 2' },
|
data: { label: 'Node 2' },
|
||||||
@@ -32,7 +39,12 @@ const initialNodes: Node[] = [
|
|||||||
position: { x: 10, y: 50 },
|
position: { x: 10, y: 50 },
|
||||||
parentNode: '2',
|
parentNode: '2',
|
||||||
},
|
},
|
||||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 320, y: 100 }, className: 'light' },
|
{
|
||||||
|
id: '3',
|
||||||
|
data: { label: 'Node 3' },
|
||||||
|
position: { x: 320, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: '4',
|
id: '4',
|
||||||
data: { label: 'Node 4' },
|
data: { label: 'Node 4' },
|
||||||
@@ -53,7 +65,11 @@ const initialNodes: Node[] = [
|
|||||||
data: { label: 'Node 4b' },
|
data: { label: 'Node 4b' },
|
||||||
position: { x: 15, y: 120 },
|
position: { x: 15, y: 120 },
|
||||||
className: 'light',
|
className: 'light',
|
||||||
style: { backgroundColor: 'rgba(255, 0, 255, 0.7)', height: 150, width: 270 },
|
style: {
|
||||||
|
backgroundColor: 'rgba(255, 0, 255, 0.7)',
|
||||||
|
height: 150,
|
||||||
|
width: 270,
|
||||||
|
},
|
||||||
parentNode: '4',
|
parentNode: '4',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -91,7 +107,10 @@ const NestedFlow = () => {
|
|||||||
const onConnect = useCallback((connection: Connection) => {
|
const onConnect = useCallback((connection: Connection) => {
|
||||||
setEdges((eds) => addEdge(connection, eds));
|
setEdges((eds) => addEdge(connection, eds));
|
||||||
}, []);
|
}, []);
|
||||||
const onInit = useCallback((reactFlowInstance: ReactFlowInstance) => setRfInstance(reactFlowInstance), []);
|
const onInit = useCallback(
|
||||||
|
(reactFlowInstance: ReactFlowInstance) => setRfInstance(reactFlowInstance),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
const updatePos = () => {
|
const updatePos = () => {
|
||||||
setNodes((nds) => {
|
setNodes((nds) => {
|
||||||
@@ -138,7 +157,7 @@ const NestedFlow = () => {
|
|||||||
onEdgeClick={onEdgeClick}
|
onEdgeClick={onEdgeClick}
|
||||||
onConnect={onConnect}
|
onConnect={onConnect}
|
||||||
onNodeDragStop={onNodeDragStop}
|
onNodeDragStop={onNodeDragStop}
|
||||||
className="react-flow-basic-example"
|
className='react-flow-basic-example'
|
||||||
defaultZoom={1.5}
|
defaultZoom={1.5}
|
||||||
minZoom={0.2}
|
minZoom={0.2}
|
||||||
maxZoom={4}
|
maxZoom={4}
|
||||||
+12
-4
@@ -8,7 +8,7 @@ import ReactFlow, {
|
|||||||
Edge,
|
Edge,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
{
|
{
|
||||||
@@ -28,14 +28,22 @@ const initialNodes: Node[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const initialEdges: Edge[] = [{ id: 'e1-2', source: '1', type: 'smoothstep', target: '2', animated: true }];
|
const initialEdges: Edge[] = [
|
||||||
|
{ id: 'e1-2', source: '1', type: 'smoothstep', target: '2', animated: true },
|
||||||
|
];
|
||||||
|
|
||||||
const buttonStyle: CSSProperties = { position: 'absolute', right: 10, top: 30, zIndex: 4 };
|
const buttonStyle: CSSProperties = {
|
||||||
|
position: 'absolute',
|
||||||
|
right: 10,
|
||||||
|
top: 30,
|
||||||
|
zIndex: 4,
|
||||||
|
};
|
||||||
|
|
||||||
const NodeTypeChangeFlow = () => {
|
const NodeTypeChangeFlow = () => {
|
||||||
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
const onConnect = (params: Connection | Edge) => setEdges((eds) => addEdge(params, eds));
|
const onConnect = (params: Connection | Edge) =>
|
||||||
|
setEdges((eds) => addEdge(params, eds));
|
||||||
const changeType = () => {
|
const changeType = () => {
|
||||||
setNodes((nds) =>
|
setNodes((nds) =>
|
||||||
nds.map((node) => {
|
nds.map((node) => {
|
||||||
+13
-4
@@ -10,7 +10,7 @@ import ReactFlow, {
|
|||||||
NodeTypes,
|
NodeTypes,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
{
|
{
|
||||||
@@ -30,9 +30,17 @@ const initialNodes: Node[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const buttonStyle: CSSProperties = { position: 'absolute', right: 10, top: 30, zIndex: 4 };
|
const buttonStyle: CSSProperties = {
|
||||||
|
position: 'absolute',
|
||||||
|
right: 10,
|
||||||
|
top: 30,
|
||||||
|
zIndex: 4,
|
||||||
|
};
|
||||||
|
|
||||||
const nodeStyles: CSSProperties = { padding: '10px 15px', border: '1px solid #ddd' };
|
const nodeStyles: CSSProperties = {
|
||||||
|
padding: '10px 15px',
|
||||||
|
border: '1px solid #ddd',
|
||||||
|
};
|
||||||
|
|
||||||
const NodeA: FC<NodeProps> = () => {
|
const NodeA: FC<NodeProps> = () => {
|
||||||
return <div style={nodeStyles}>A</div>;
|
return <div style={nodeStyles}>A</div>;
|
||||||
@@ -59,7 +67,8 @@ const NodeTypeChangeFlow = () => {
|
|||||||
const [nodeTypesId, setNodeTypesId] = useState<string>('a');
|
const [nodeTypesId, setNodeTypesId] = useState<string>('a');
|
||||||
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
||||||
const onConnect = (params: Connection | Edge) => setEdges((eds) => addEdge(params, eds));
|
const onConnect = (params: Connection | Edge) =>
|
||||||
|
setEdges((eds) => addEdge(params, eds));
|
||||||
const changeType = () => setNodeTypesId((nt) => (nt === 'a' ? 'b' : 'a'));
|
const changeType = () => setNodeTypesId((nt) => (nt === 'a' ? 'b' : 'a'));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
+86
-30
@@ -1,4 +1,8 @@
|
|||||||
import { MouseEvent as ReactMouseEvent, CSSProperties, useCallback } from 'react';
|
import {
|
||||||
|
MouseEvent as ReactMouseEvent,
|
||||||
|
CSSProperties,
|
||||||
|
useCallback,
|
||||||
|
} from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
MiniMap,
|
MiniMap,
|
||||||
@@ -13,36 +17,55 @@ import ReactFlow, {
|
|||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
OnSelectionChangeParams,
|
OnSelectionChangeParams,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
const onNodeDragStart = (_: ReactMouseEvent, node: Node, nodes: Node[]) => console.log('drag start', node, nodes);
|
const onNodeDragStart = (_: ReactMouseEvent, node: Node, nodes: Node[]) =>
|
||||||
const onNodeDrag = (_: ReactMouseEvent, node: Node, nodes: Node[]) => console.log('drag', node, nodes);
|
console.log('drag start', node, nodes);
|
||||||
const onNodeDragStop = (_: ReactMouseEvent, node: Node, nodes: Node[]) => console.log('drag stop', node, nodes);
|
const onNodeDrag = (_: ReactMouseEvent, node: Node, nodes: Node[]) =>
|
||||||
const onNodeDoubleClick = (_: ReactMouseEvent, node: Node) => console.log('node double click', node);
|
console.log('drag', node, nodes);
|
||||||
const onPaneClick = (event: ReactMouseEvent) => console.log('pane click', event);
|
const onNodeDragStop = (_: ReactMouseEvent, node: Node, nodes: Node[]) =>
|
||||||
const onPaneScroll = (event?: ReactMouseEvent) => console.log('pane scroll', event);
|
console.log('drag stop', node, nodes);
|
||||||
const onPaneContextMenu = (event: ReactMouseEvent) => console.log('pane context menu', event);
|
const onNodeDoubleClick = (_: ReactMouseEvent, node: Node) =>
|
||||||
const onSelectionDrag = (_: ReactMouseEvent, nodes: Node[]) => console.log('selection drag', nodes);
|
console.log('node double click', node);
|
||||||
const onSelectionDragStart = (_: ReactMouseEvent, nodes: Node[]) => console.log('selection drag start', nodes);
|
const onPaneClick = (event: ReactMouseEvent) =>
|
||||||
const onSelectionDragStop = (_: ReactMouseEvent, nodes: Node[]) => console.log('selection drag stop', nodes);
|
console.log('pane click', event);
|
||||||
|
const onPaneScroll = (event?: ReactMouseEvent) =>
|
||||||
|
console.log('pane scroll', event);
|
||||||
|
const onPaneContextMenu = (event: ReactMouseEvent) =>
|
||||||
|
console.log('pane context menu', event);
|
||||||
|
const onSelectionDrag = (_: ReactMouseEvent, nodes: Node[]) =>
|
||||||
|
console.log('selection drag', nodes);
|
||||||
|
const onSelectionDragStart = (_: ReactMouseEvent, nodes: Node[]) =>
|
||||||
|
console.log('selection drag start', nodes);
|
||||||
|
const onSelectionDragStop = (_: ReactMouseEvent, nodes: Node[]) =>
|
||||||
|
console.log('selection drag stop', nodes);
|
||||||
const onSelectionContextMenu = (event: ReactMouseEvent, nodes: Node[]) => {
|
const onSelectionContextMenu = (event: ReactMouseEvent, nodes: Node[]) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
console.log('selection context menu', nodes);
|
console.log('selection context menu', nodes);
|
||||||
};
|
};
|
||||||
const onNodeClick = (_: ReactMouseEvent, node: Node) => console.log('node click:', node);
|
const onNodeClick = (_: ReactMouseEvent, node: Node) =>
|
||||||
|
console.log('node click:', node);
|
||||||
|
|
||||||
const onSelectionChange = ({ nodes, edges }: OnSelectionChangeParams) => console.log('selection change', nodes, edges);
|
const onSelectionChange = ({ nodes, edges }: OnSelectionChangeParams) =>
|
||||||
|
console.log('selection change', nodes, edges);
|
||||||
const onInit = (reactFlowInstance: ReactFlowInstance) => {
|
const onInit = (reactFlowInstance: ReactFlowInstance) => {
|
||||||
console.log('pane ready:', reactFlowInstance);
|
console.log('pane ready:', reactFlowInstance);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMoveStart = (_: MouseEvent | TouchEvent, viewport: Viewport) => console.log('zoom/move start', viewport);
|
const onMoveStart = (_: MouseEvent | TouchEvent, viewport: Viewport) =>
|
||||||
const onMoveEnd = (_: MouseEvent | TouchEvent, viewport: Viewport) => console.log('zoom/move end', viewport);
|
console.log('zoom/move start', viewport);
|
||||||
const onEdgeContextMenu = (_: ReactMouseEvent, edge: Edge) => console.log('edge context menu', edge);
|
const onMoveEnd = (_: MouseEvent | TouchEvent, viewport: Viewport) =>
|
||||||
const onEdgeMouseEnter = (_: ReactMouseEvent, edge: Edge) => console.log('edge mouse enter', edge);
|
console.log('zoom/move end', viewport);
|
||||||
const onEdgeMouseMove = (_: ReactMouseEvent, edge: Edge) => console.log('edge mouse move', edge);
|
const onEdgeContextMenu = (_: ReactMouseEvent, edge: Edge) =>
|
||||||
const onEdgeMouseLeave = (_: ReactMouseEvent, edge: Edge) => console.log('edge mouse leave', edge);
|
console.log('edge context menu', edge);
|
||||||
const onEdgeDoubleClick = (_: ReactMouseEvent, edge: Edge) => console.log('edge double click', edge);
|
const onEdgeMouseEnter = (_: ReactMouseEvent, edge: Edge) =>
|
||||||
|
console.log('edge mouse enter', edge);
|
||||||
|
const onEdgeMouseMove = (_: ReactMouseEvent, edge: Edge) =>
|
||||||
|
console.log('edge mouse move', edge);
|
||||||
|
const onEdgeMouseLeave = (_: ReactMouseEvent, edge: Edge) =>
|
||||||
|
console.log('edge mouse leave', edge);
|
||||||
|
const onEdgeDoubleClick = (_: ReactMouseEvent, edge: Edge) =>
|
||||||
|
console.log('edge double click', edge);
|
||||||
const onNodesDelete = (nodes: Node[]) => console.log('nodes delete', nodes);
|
const onNodesDelete = (nodes: Node[]) => console.log('nodes delete', nodes);
|
||||||
const onEdgesDelete = (edges: Edge[]) => console.log('edges delete', edges);
|
const onEdgesDelete = (edges: Edge[]) => console.log('edges delete', edges);
|
||||||
|
|
||||||
@@ -80,7 +103,12 @@ const initialNodes: Node[] = [
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
position: { x: 400, y: 100 },
|
position: { x: 400, y: 100 },
|
||||||
style: { background: '#D6D5E6', color: '#333', border: '1px solid #222138', width: 180 },
|
style: {
|
||||||
|
background: '#D6D5E6',
|
||||||
|
color: '#333',
|
||||||
|
border: '1px solid #222138',
|
||||||
|
width: 180,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '4',
|
id: '4',
|
||||||
@@ -89,7 +117,11 @@ const initialNodes: Node[] = [
|
|||||||
label: (
|
label: (
|
||||||
<>
|
<>
|
||||||
You can find the docs on{' '}
|
You can find the docs on{' '}
|
||||||
<a href="https://github.com/wbkd/react-flow" target="_blank" rel="noopener noreferrer">
|
<a
|
||||||
|
href='https://github.com/wbkd/react-flow'
|
||||||
|
target='_blank'
|
||||||
|
rel='noopener noreferrer'
|
||||||
|
>
|
||||||
Github
|
Github
|
||||||
</a>
|
</a>
|
||||||
</>
|
</>
|
||||||
@@ -119,15 +151,32 @@ const initialNodes: Node[] = [
|
|||||||
},
|
},
|
||||||
position: { x: 100, y: 480 },
|
position: { x: 100, y: 480 },
|
||||||
},
|
},
|
||||||
{ id: '7', type: 'output', data: { label: 'Another output node' }, position: { x: 400, y: 450 } },
|
{
|
||||||
|
id: '7',
|
||||||
|
type: 'output',
|
||||||
|
data: { label: 'Another output node' },
|
||||||
|
position: { x: 400, y: 450 },
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const initialEdges: Edge[] = [
|
const initialEdges: Edge[] = [
|
||||||
{ id: 'e1-2', source: '1', target: '2', label: 'this is an edge label' },
|
{ id: 'e1-2', source: '1', target: '2', label: 'this is an edge label' },
|
||||||
{ id: 'e1-3', source: '1', target: '3' },
|
{ id: 'e1-3', source: '1', target: '3' },
|
||||||
{ id: 'e3-4', source: '3', target: '4', animated: true, label: 'animated edge' },
|
{
|
||||||
|
id: 'e3-4',
|
||||||
|
source: '3',
|
||||||
|
target: '4',
|
||||||
|
animated: true,
|
||||||
|
label: 'animated edge',
|
||||||
|
},
|
||||||
{ id: 'e4-5', source: '4', target: '5', label: 'edge with arrow head' },
|
{ id: 'e4-5', source: '4', target: '5', label: 'edge with arrow head' },
|
||||||
{ id: 'e5-6', source: '5', target: '6', type: 'smoothstep', label: 'smooth step edge' },
|
{
|
||||||
|
id: 'e5-6',
|
||||||
|
source: '5',
|
||||||
|
target: '6',
|
||||||
|
type: 'smoothstep',
|
||||||
|
label: 'smooth step edge',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'e5-7',
|
id: 'e5-7',
|
||||||
source: '5',
|
source: '5',
|
||||||
@@ -161,7 +210,10 @@ const nodeColor = (n: Node): string => {
|
|||||||
const OverviewFlow = () => {
|
const OverviewFlow = () => {
|
||||||
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
const onConnect = useCallback((params: Connection | Edge) => setEdges((eds) => addEdge(params, eds)), [setEdges]);
|
const onConnect = useCallback(
|
||||||
|
(params: Connection | Edge) => setEdges((eds) => addEdge(params, eds)),
|
||||||
|
[setEdges]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
@@ -196,14 +248,18 @@ const OverviewFlow = () => {
|
|||||||
onEdgeDoubleClick={onEdgeDoubleClick}
|
onEdgeDoubleClick={onEdgeDoubleClick}
|
||||||
fitView
|
fitView
|
||||||
fitViewOptions={{ padding: 0.2 }}
|
fitViewOptions={{ padding: 0.2 }}
|
||||||
attributionPosition="top-right"
|
attributionPosition='top-right'
|
||||||
maxZoom={Infinity}
|
maxZoom={Infinity}
|
||||||
onNodesDelete={onNodesDelete}
|
onNodesDelete={onNodesDelete}
|
||||||
onEdgesDelete={onEdgesDelete}
|
onEdgesDelete={onEdgesDelete}
|
||||||
>
|
>
|
||||||
<MiniMap nodeStrokeColor={nodeStrokeColor} nodeColor={nodeColor} nodeBorderRadius={2} />
|
<MiniMap
|
||||||
|
nodeStrokeColor={nodeStrokeColor}
|
||||||
|
nodeColor={nodeColor}
|
||||||
|
nodeBorderRadius={2}
|
||||||
|
/>
|
||||||
<Controls />
|
<Controls />
|
||||||
<Background color="#aaa" gap={25} />
|
<Background color='#aaa' gap={25} />
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
+12
-9
@@ -1,4 +1,4 @@
|
|||||||
import { useStore, useStoreApi } from 'react-flow-renderer';
|
import { useStore, useStoreApi } from '@react-flow/core';
|
||||||
|
|
||||||
const Sidebar = () => {
|
const Sidebar = () => {
|
||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
@@ -12,21 +12,24 @@ const Sidebar = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<aside>
|
<aside>
|
||||||
<div className="description">
|
<div className='description'>
|
||||||
This is an example of how you can access the internal state outside of the ReactFlow component.
|
This is an example of how you can access the internal state outside of
|
||||||
|
the ReactFlow component.
|
||||||
</div>
|
</div>
|
||||||
<div className="title">Zoom & pan transform</div>
|
<div className='title'>Zoom & pan transform</div>
|
||||||
<div className="transform">
|
<div className='transform'>
|
||||||
[{transform[0].toFixed(2)}, {transform[1].toFixed(2)}, {transform[2].toFixed(2)}]
|
[{transform[0].toFixed(2)}, {transform[1].toFixed(2)},{' '}
|
||||||
|
{transform[2].toFixed(2)}]
|
||||||
</div>
|
</div>
|
||||||
<div className="title">Nodes</div>
|
<div className='title'>Nodes</div>
|
||||||
{Array.from(nodeInternals).map(([, node]) => (
|
{Array.from(nodeInternals).map(([, node]) => (
|
||||||
<div key={node.id}>
|
<div key={node.id}>
|
||||||
Node {node.id} - x: {node.position.x.toFixed(2)}, y: {node.position.y.toFixed(2)}
|
Node {node.id} - x: {node.position.x.toFixed(2)}, y:{' '}
|
||||||
|
{node.position.y.toFixed(2)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<div className="selectall">
|
<div className='selectall'>
|
||||||
<button onClick={selectAll}>select all nodes</button>
|
<button onClick={selectAll}>select all nodes</button>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
+13
-6
@@ -10,17 +10,23 @@ import ReactFlow, {
|
|||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
ReactFlowInstance,
|
ReactFlowInstance,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import Sidebar from './Sidebar';
|
import Sidebar from './Sidebar';
|
||||||
|
|
||||||
import './provider.css';
|
import './provider.css';
|
||||||
|
|
||||||
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
||||||
const onInit = (reactFlowInstance: ReactFlowInstance) => console.log('pane ready:', reactFlowInstance);
|
const onInit = (reactFlowInstance: ReactFlowInstance) =>
|
||||||
|
console.log('pane ready:', reactFlowInstance);
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } },
|
{
|
||||||
|
id: '1',
|
||||||
|
type: 'input',
|
||||||
|
data: { label: 'Node 1' },
|
||||||
|
position: { x: 250, y: 5 },
|
||||||
|
},
|
||||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
|
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
|
||||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
|
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
|
||||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
|
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
|
||||||
@@ -34,13 +40,14 @@ const initialEdges: Edge[] = [
|
|||||||
const ProviderFlow = () => {
|
const ProviderFlow = () => {
|
||||||
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
const onConnect = (params: Edge | Connection) => setEdges((els) => addEdge(params, els));
|
const onConnect = (params: Edge | Connection) =>
|
||||||
|
setEdges((els) => addEdge(params, els));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="providerflow">
|
<div className='providerflow'>
|
||||||
<ReactFlowProvider>
|
<ReactFlowProvider>
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<div className="reactflow-wrapper">
|
<div className='reactflow-wrapper'>
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
edges={edges}
|
edges={edges}
|
||||||
+14
-4
@@ -1,5 +1,10 @@
|
|||||||
import React, { memo, useCallback, Dispatch, FC } from 'react';
|
import React, { memo, useCallback, Dispatch, FC } from 'react';
|
||||||
import { useReactFlow, Edge, Node, ReactFlowJsonObject } from 'react-flow-renderer';
|
import {
|
||||||
|
useReactFlow,
|
||||||
|
Edge,
|
||||||
|
Node,
|
||||||
|
ReactFlowJsonObject,
|
||||||
|
} from '@react-flow/core';
|
||||||
import localforage from 'localforage';
|
import localforage from 'localforage';
|
||||||
|
|
||||||
localforage.config({
|
localforage.config({
|
||||||
@@ -26,7 +31,9 @@ const Controls: FC<ControlsProps> = ({ setNodes, setEdges }) => {
|
|||||||
|
|
||||||
const onRestore = useCallback(() => {
|
const onRestore = useCallback(() => {
|
||||||
const restoreFlow = async () => {
|
const restoreFlow = async () => {
|
||||||
const flow: ReactFlowJsonObject | null = await localforage.getItem(flowKey);
|
const flow: ReactFlowJsonObject | null = await localforage.getItem(
|
||||||
|
flowKey
|
||||||
|
);
|
||||||
|
|
||||||
if (flow) {
|
if (flow) {
|
||||||
const { x, y, zoom } = flow.viewport;
|
const { x, y, zoom } = flow.viewport;
|
||||||
@@ -44,13 +51,16 @@ const Controls: FC<ControlsProps> = ({ setNodes, setEdges }) => {
|
|||||||
const newNode = {
|
const newNode = {
|
||||||
id: `random_node-${getNodeId()}`,
|
id: `random_node-${getNodeId()}`,
|
||||||
data: { label: 'Added node' },
|
data: { label: 'Added node' },
|
||||||
position: { x: Math.random() * window.innerWidth - 100, y: Math.random() * window.innerHeight },
|
position: {
|
||||||
|
x: Math.random() * window.innerWidth - 100,
|
||||||
|
y: Math.random() * window.innerHeight,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
setNodes((nds) => nds.concat(newNode));
|
setNodes((nds) => nds.concat(newNode));
|
||||||
}, [setNodes]);
|
}, [setNodes]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="save__controls">
|
<div className='save__controls'>
|
||||||
<button onClick={onSave}>save</button>
|
<button onClick={onSave}>save</button>
|
||||||
<button onClick={onRestore}>restore</button>
|
<button onClick={onRestore}>restore</button>
|
||||||
<button onClick={onAdd}>add node</button>
|
<button onClick={onAdd}>add node</button>
|
||||||
+5
-2
@@ -7,7 +7,7 @@ import ReactFlow, {
|
|||||||
Edge,
|
Edge,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import Controls from './Controls';
|
import Controls from './Controls';
|
||||||
|
|
||||||
@@ -23,7 +23,10 @@ const initialEdges: Edge[] = [{ id: 'e1-2', source: '1', target: '2' }];
|
|||||||
const SaveRestore = () => {
|
const SaveRestore = () => {
|
||||||
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
const onConnect = useCallback((params: Connection | Edge) => setEdges((eds) => addEdge(params, eds)), [setEdges]);
|
const onConnect = useCallback(
|
||||||
|
(params: Connection | Edge) => setEdges((eds) => addEdge(params, eds)),
|
||||||
|
[setEdges]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlowProvider>
|
<ReactFlowProvider>
|
||||||
@@ -12,11 +12,16 @@ import ReactFlow, {
|
|||||||
addEdge,
|
addEdge,
|
||||||
applyEdgeChanges,
|
applyEdgeChanges,
|
||||||
EdgeChange,
|
EdgeChange,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import { getNodesAndEdges } from './utils';
|
import { getNodesAndEdges } from './utils';
|
||||||
|
|
||||||
const buttonWrapperStyles: CSSProperties = { position: 'absolute', right: 10, top: 10, zIndex: 4 };
|
const buttonWrapperStyles: CSSProperties = {
|
||||||
|
position: 'absolute',
|
||||||
|
right: 10,
|
||||||
|
top: 10,
|
||||||
|
zIndex: 4,
|
||||||
|
};
|
||||||
|
|
||||||
const onInit = (reactFlowInstance: ReactFlowInstance) => {
|
const onInit = (reactFlowInstance: ReactFlowInstance) => {
|
||||||
reactFlowInstance.fitView();
|
reactFlowInstance.fitView();
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
import { Node, Edge } from 'react-flow-renderer';
|
import { Node, Edge } from '@react-flow/core';
|
||||||
|
|
||||||
type ElementsCollection = {
|
type ElementsCollection = {
|
||||||
nodes: Node[];
|
nodes: Node[];
|
||||||
edges: Edge[];
|
edges: Edge[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getNodesAndEdges(xElements: number = 10, yElements: number = 10): ElementsCollection {
|
export function getNodesAndEdges(
|
||||||
|
xElements: number = 10,
|
||||||
|
yElements: number = 10
|
||||||
|
): ElementsCollection {
|
||||||
const initialNodes = [];
|
const initialNodes = [];
|
||||||
const initialEdges: Edge[] = [];
|
const initialEdges: Edge[] = [];
|
||||||
let nodeId = 1;
|
let nodeId = 1;
|
||||||
@@ -24,7 +27,11 @@ export function getNodesAndEdges(xElements: number = 10, yElements: number = 10)
|
|||||||
initialNodes.push(node);
|
initialNodes.push(node);
|
||||||
|
|
||||||
if (recentNodeId && nodeId <= xElements * yElements) {
|
if (recentNodeId && nodeId <= xElements * yElements) {
|
||||||
initialEdges.push({ id: `${x}-${y}`, source: recentNodeId.toString(), target: nodeId.toString() });
|
initialEdges.push({
|
||||||
|
id: `${x}-${y}`,
|
||||||
|
source: recentNodeId.toString(),
|
||||||
|
target: nodeId.toString(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
recentNodeId = nodeId;
|
recentNodeId = nodeId;
|
||||||
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
import { memo, FC, CSSProperties } from 'react';
|
import { memo, FC, CSSProperties } from 'react';
|
||||||
|
|
||||||
import { Handle, NodeProps, Position } from 'react-flow-renderer';
|
import { Handle, NodeProps, Position } from '@react-flow/core';
|
||||||
|
|
||||||
const infoStyle: CSSProperties = { fontSize: 11 };
|
const infoStyle: CSSProperties = { fontSize: 11 };
|
||||||
const idStyle: CSSProperties = {
|
const idStyle: CSSProperties = {
|
||||||
@@ -14,12 +14,12 @@ const idStyle: CSSProperties = {
|
|||||||
const DebugNode: FC<NodeProps> = ({ zIndex, xPos, yPos, id }) => {
|
const DebugNode: FC<NodeProps> = ({ zIndex, xPos, yPos, id }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Handle type="target" position={Position.Top} />
|
<Handle type='target' position={Position.Top} />
|
||||||
<div style={idStyle}>{id}</div>
|
<div style={idStyle}>{id}</div>
|
||||||
<div style={infoStyle}>
|
<div style={infoStyle}>
|
||||||
x:{Math.round(xPos || 0)} y:{Math.round(yPos || 0)} z:{zIndex}
|
x:{Math.round(xPos || 0)} y:{Math.round(yPos || 0)} z:{zIndex}
|
||||||
</div>
|
</div>
|
||||||
<Handle type="source" position={Position.Bottom} />
|
<Handle type='source' position={Position.Bottom} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -12,11 +12,13 @@ import ReactFlow, {
|
|||||||
MarkerType,
|
MarkerType,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
import DebugNode from './DebugNode';
|
import DebugNode from './DebugNode';
|
||||||
|
|
||||||
const onNodeDrag = (_: MouseEvent, node: Node, nodes: Node[]) => console.log('drag', node, nodes);
|
const onNodeDrag = (_: MouseEvent, node: Node, nodes: Node[]) =>
|
||||||
const onNodeDragStop = (_: MouseEvent, node: Node, nodes: Node[]) => console.log('drag stop', node, nodes);
|
console.log('drag', node, nodes);
|
||||||
|
const onNodeDragStop = (_: MouseEvent, node: Node, nodes: Node[]) =>
|
||||||
|
console.log('drag stop', node, nodes);
|
||||||
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
||||||
const onEdgeClick = (_: MouseEvent, edge: Edge) => console.log('click', edge);
|
const onEdgeClick = (_: MouseEvent, edge: Edge) => console.log('click', edge);
|
||||||
|
|
||||||
@@ -33,7 +35,11 @@ const initialNodes: Node[] = [
|
|||||||
data: { label: 'Node 4' },
|
data: { label: 'Node 4' },
|
||||||
position: { x: 100, y: 200 },
|
position: { x: 100, y: 200 },
|
||||||
className: 'light',
|
className: 'light',
|
||||||
style: { backgroundColor: 'rgba(255,50, 50, 0.5)', width: 500, height: 300 },
|
style: {
|
||||||
|
backgroundColor: 'rgba(255,50, 50, 0.5)',
|
||||||
|
width: 500,
|
||||||
|
height: 300,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '4a',
|
id: '4a',
|
||||||
@@ -51,7 +57,11 @@ const initialNodes: Node[] = [
|
|||||||
data: { label: 'Node 4b' },
|
data: { label: 'Node 4b' },
|
||||||
position: { x: 100, y: 60 },
|
position: { x: 100, y: 60 },
|
||||||
className: 'light',
|
className: 'light',
|
||||||
style: { backgroundColor: 'rgba(50, 50, 255, 0.5)', height: 200, width: 300 },
|
style: {
|
||||||
|
backgroundColor: 'rgba(50, 50, 255, 0.5)',
|
||||||
|
height: 200,
|
||||||
|
width: 300,
|
||||||
|
},
|
||||||
parentNode: '4',
|
parentNode: '4',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -93,8 +103,18 @@ const initialNodes: Node[] = [
|
|||||||
parentNode: '5',
|
parentNode: '5',
|
||||||
expandParent: true,
|
expandParent: true,
|
||||||
},
|
},
|
||||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, className: 'light' },
|
{
|
||||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, className: 'light' },
|
id: '2',
|
||||||
|
data: { label: 'Node 2' },
|
||||||
|
position: { x: 100, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
data: { label: 'Node 3' },
|
||||||
|
position: { x: 400, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const initialEdges: Edge[] = [
|
const initialEdges: Edge[] = [
|
||||||
@@ -102,7 +122,13 @@ const initialEdges: Edge[] = [
|
|||||||
id: 'e1-2',
|
id: 'e1-2',
|
||||||
source: '1',
|
source: '1',
|
||||||
target: '2',
|
target: '2',
|
||||||
markerEnd: { type: MarkerType.Arrow, strokeWidth: 2, width: 15, height: 15, color: '#f00' },
|
markerEnd: {
|
||||||
|
type: MarkerType.Arrow,
|
||||||
|
strokeWidth: 2,
|
||||||
|
width: 15,
|
||||||
|
height: 15,
|
||||||
|
color: '#f00',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{ id: 'e1-3', source: '1', target: '3' },
|
{ id: 'e1-3', source: '1', target: '3' },
|
||||||
{ id: 'e3-4', source: '3', target: '4', zIndex: 100 },
|
{ id: 'e3-4', source: '3', target: '4', zIndex: 100 },
|
||||||
@@ -121,8 +147,14 @@ const Subflow = () => {
|
|||||||
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
|
|
||||||
const onConnect = useCallback((connection: Connection) => setEdges((eds) => addEdge(connection, eds)), [setEdges]);
|
const onConnect = useCallback(
|
||||||
const onInit = useCallback((reactFlowInstance: ReactFlowInstance) => setRfInstance(reactFlowInstance), []);
|
(connection: Connection) => setEdges((eds) => addEdge(connection, eds)),
|
||||||
|
[setEdges]
|
||||||
|
);
|
||||||
|
const onInit = useCallback(
|
||||||
|
(reactFlowInstance: ReactFlowInstance) => setRfInstance(reactFlowInstance),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
const updatePos = () => {
|
const updatePos = () => {
|
||||||
setNodes((nds) => {
|
setNodes((nds) => {
|
||||||
@@ -172,7 +204,7 @@ const Subflow = () => {
|
|||||||
onConnect={onConnect}
|
onConnect={onConnect}
|
||||||
onNodeDrag={onNodeDrag}
|
onNodeDrag={onNodeDrag}
|
||||||
onNodeDragStop={onNodeDragStop}
|
onNodeDragStop={onNodeDragStop}
|
||||||
className="react-flow-basic-example"
|
className='react-flow-basic-example'
|
||||||
defaultZoom={1.5}
|
defaultZoom={1.5}
|
||||||
minZoom={0.2}
|
minZoom={0.2}
|
||||||
maxZoom={4}
|
maxZoom={4}
|
||||||
@@ -1,14 +1,43 @@
|
|||||||
import { MouseEvent } from 'react';
|
import { MouseEvent } from 'react';
|
||||||
import ReactFlow, { addEdge, Node, Connection, Edge, useNodesState, useEdgesState } from 'react-flow-renderer';
|
import ReactFlow, {
|
||||||
|
addEdge,
|
||||||
|
Node,
|
||||||
|
Connection,
|
||||||
|
Edge,
|
||||||
|
useNodesState,
|
||||||
|
useEdgesState,
|
||||||
|
} from '@react-flow/core';
|
||||||
|
|
||||||
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
const onNodeDragStop = (_: MouseEvent, node: Node) =>
|
||||||
|
console.log('drag stop', node);
|
||||||
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
||||||
|
|
||||||
const nodesA: Node[] = [
|
const nodesA: Node[] = [
|
||||||
{ id: '1a', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 }, className: 'light' },
|
{
|
||||||
{ id: '2a', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, className: 'light' },
|
id: '1a',
|
||||||
{ id: '3a', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, className: 'light' },
|
type: 'input',
|
||||||
{ id: '4a', data: { label: 'Node 4' }, position: { x: 400, y: 200 }, className: 'light' },
|
data: { label: 'Node 1' },
|
||||||
|
position: { x: 250, y: 5 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2a',
|
||||||
|
data: { label: 'Node 2' },
|
||||||
|
position: { x: 100, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3a',
|
||||||
|
data: { label: 'Node 3' },
|
||||||
|
position: { x: 400, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4a',
|
||||||
|
data: { label: 'Node 4' },
|
||||||
|
position: { x: 400, y: 200 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const edgesA: Edge[] = [
|
const edgesA: Edge[] = [
|
||||||
@@ -17,11 +46,37 @@ const edgesA: Edge[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const nodesB: Node[] = [
|
const nodesB: Node[] = [
|
||||||
{ id: 'inputb', type: 'input', data: { label: 'Input' }, position: { x: 300, y: 5 }, className: 'light' },
|
{
|
||||||
{ id: '1b', data: { label: 'Node 1' }, position: { x: 0, y: 100 }, className: 'light' },
|
id: 'inputb',
|
||||||
{ id: '2b', data: { label: 'Node 2' }, position: { x: 200, y: 100 }, className: 'light' },
|
type: 'input',
|
||||||
{ id: '3b', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, className: 'light' },
|
data: { label: 'Input' },
|
||||||
{ id: '4b', data: { label: 'Node 4' }, position: { x: 600, y: 100 }, className: 'light' },
|
position: { x: 300, y: 5 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '1b',
|
||||||
|
data: { label: 'Node 1' },
|
||||||
|
position: { x: 0, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2b',
|
||||||
|
data: { label: 'Node 2' },
|
||||||
|
position: { x: 200, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3b',
|
||||||
|
data: { label: 'Node 3' },
|
||||||
|
position: { x: 400, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4b',
|
||||||
|
data: { label: 'Node 4' },
|
||||||
|
position: { x: 600, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const edgesB: Edge[] = [
|
const edgesB: Edge[] = [
|
||||||
@@ -35,7 +90,8 @@ const BasicFlow = () => {
|
|||||||
const [nodes, setNodes, onNodesChange] = useNodesState(nodesA);
|
const [nodes, setNodes, onNodesChange] = useNodesState(nodesA);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(edgesA);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(edgesA);
|
||||||
|
|
||||||
const onConnect = (params: Connection | Edge) => setEdges((eds) => addEdge(params, eds));
|
const onConnect = (params: Connection | Edge) =>
|
||||||
|
setEdges((eds) => addEdge(params, eds));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
+14
-5
@@ -7,7 +7,7 @@ import ReactFlow, {
|
|||||||
Position,
|
Position,
|
||||||
Connection,
|
Connection,
|
||||||
addEdge,
|
addEdge,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import './touch-device.css';
|
import './touch-device.css';
|
||||||
|
|
||||||
@@ -33,11 +33,20 @@ const initialEdges: Edge[] = [];
|
|||||||
const TouchDeviceFlow = () => {
|
const TouchDeviceFlow = () => {
|
||||||
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
const onConnect = useCallback((connection: Connection) => setEdges((eds) => addEdge(connection, eds)), [setEdges]);
|
const onConnect = useCallback(
|
||||||
|
(connection: Connection) => setEdges((eds) => addEdge(connection, eds)),
|
||||||
|
[setEdges]
|
||||||
|
);
|
||||||
const onConnectStart = useCallback(() => console.log('connect start'), []);
|
const onConnectStart = useCallback(() => console.log('connect start'), []);
|
||||||
const onConnectStop = useCallback(() => console.log('connect end'), []);
|
const onConnectStop = useCallback(() => console.log('connect end'), []);
|
||||||
const onClickConnectStart = useCallback(() => console.log('click connect start'), []);
|
const onClickConnectStart = useCallback(
|
||||||
const onClickConnectStop = useCallback(() => console.log('click connect end'), []);
|
() => console.log('click connect start'),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
const onClickConnectStop = useCallback(
|
||||||
|
() => console.log('click connect end'),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
@@ -50,7 +59,7 @@ const TouchDeviceFlow = () => {
|
|||||||
onConnectStop={onConnectStop}
|
onConnectStop={onConnectStop}
|
||||||
onClickConnectStart={onClickConnectStart}
|
onClickConnectStart={onClickConnectStart}
|
||||||
onClickConnectStop={onClickConnectStop}
|
onClickConnectStop={onClickConnectStop}
|
||||||
className="touchdevice-flow"
|
className='touchdevice-flow'
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import React, { memo, FC, CSSProperties } from 'react';
|
||||||
|
|
||||||
|
import { Handle, Position, NodeProps } from '@react-flow/core';
|
||||||
|
|
||||||
|
const nodeStyles: CSSProperties = {
|
||||||
|
padding: '10px 15px',
|
||||||
|
border: '1px solid #ddd',
|
||||||
|
};
|
||||||
|
|
||||||
|
const CustomNode: FC<NodeProps> = ({ id }) => {
|
||||||
|
return (
|
||||||
|
<div style={nodeStyles}>
|
||||||
|
<div>node {id}</div>
|
||||||
|
<Handle type='source' id='left' position={Position.Left} />
|
||||||
|
<Handle type='source' id='right' position={Position.Right} />
|
||||||
|
<Handle type='source' id='top' position={Position.Top} />
|
||||||
|
<Handle type='source' id='bottom' position={Position.Bottom} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(CustomNode);
|
||||||
+3
-2
@@ -13,7 +13,7 @@ import ReactFlow, {
|
|||||||
updateEdge,
|
updateEdge,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
import CustomNode from './CustomNode';
|
import CustomNode from './CustomNode';
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
@@ -183,7 +183,8 @@ const UpdateNodeInternalsFlow = () => {
|
|||||||
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
|
|
||||||
const onConnect = (params: Edge | Connection) => setEdges((els) => addEdge(params, els));
|
const onConnect = (params: Edge | Connection) =>
|
||||||
|
setEdges((els) => addEdge(params, els));
|
||||||
const { project } = useReactFlow();
|
const { project } = useReactFlow();
|
||||||
const onEdgeUpdate = (oldEdge: Edge, newConnection: Connection) =>
|
const onEdgeUpdate = (oldEdge: Edge, newConnection: Connection) =>
|
||||||
setEdges((els) => updateEdge(oldEdge, newConnection, els));
|
setEdges((els) => updateEdge(oldEdge, newConnection, els));
|
||||||
+1
-1
@@ -12,7 +12,7 @@ import ReactFlow, {
|
|||||||
NodeChange,
|
NodeChange,
|
||||||
EdgeChange,
|
EdgeChange,
|
||||||
HandleType,
|
HandleType,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
{
|
{
|
||||||
+18
-6
@@ -1,5 +1,10 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import ReactFlow, { Node, Edge, useNodesState, useEdgesState } from 'react-flow-renderer';
|
import ReactFlow, {
|
||||||
|
Node,
|
||||||
|
Edge,
|
||||||
|
useNodesState,
|
||||||
|
useEdgesState,
|
||||||
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import './updatenode.css';
|
import './updatenode.css';
|
||||||
|
|
||||||
@@ -70,16 +75,23 @@ const UpdateNode = () => {
|
|||||||
onNodesChange={onNodesChange}
|
onNodesChange={onNodesChange}
|
||||||
onEdgesChange={onEdgesChange}
|
onEdgesChange={onEdgesChange}
|
||||||
>
|
>
|
||||||
<div className="updatenode__controls">
|
<div className='updatenode__controls'>
|
||||||
<label>label:</label>
|
<label>label:</label>
|
||||||
<input value={nodeName} onChange={(evt) => setNodeName(evt.target.value)} />
|
<input
|
||||||
|
value={nodeName}
|
||||||
|
onChange={(evt) => setNodeName(evt.target.value)}
|
||||||
|
/>
|
||||||
|
|
||||||
<label className="updatenode__bglabel">background:</label>
|
<label className='updatenode__bglabel'>background:</label>
|
||||||
<input value={nodeBg} onChange={(evt) => setNodeBg(evt.target.value)} />
|
<input value={nodeBg} onChange={(evt) => setNodeBg(evt.target.value)} />
|
||||||
|
|
||||||
<div className="updatenode__checkboxwrapper">
|
<div className='updatenode__checkboxwrapper'>
|
||||||
<label>hidden:</label>
|
<label>hidden:</label>
|
||||||
<input type="checkbox" checked={nodeHidden} onChange={(evt) => setNodeHidden(evt.target.checked)} />
|
<input
|
||||||
|
type='checkbox'
|
||||||
|
checked={nodeHidden}
|
||||||
|
onChange={(evt) => setNodeHidden(evt.target.checked)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import { useKeyPress } from 'react-flow-renderer';
|
import { useKeyPress } from '@react-flow/core';
|
||||||
|
|
||||||
const UseKeyPressComponent = () => {
|
const UseKeyPressComponent = () => {
|
||||||
const metaPressed = useKeyPress(['Meta']);
|
const metaPressed = useKeyPress(['Meta']);
|
||||||
+39
-9
@@ -11,13 +11,34 @@ import ReactFlow, {
|
|||||||
Edge,
|
Edge,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 }, className: 'light' },
|
{
|
||||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, className: 'light' },
|
id: '1',
|
||||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, className: 'light' },
|
type: 'input',
|
||||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 }, className: 'light' },
|
data: { label: 'Node 1' },
|
||||||
|
position: { x: 250, y: 5 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
data: { label: 'Node 2' },
|
||||||
|
position: { x: 100, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
data: { label: 'Node 3' },
|
||||||
|
position: { x: 400, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
data: { label: 'Node 4' },
|
||||||
|
position: { x: 400, y: 200 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const initialEdges: Edge[] = [
|
const initialEdges: Edge[] = [
|
||||||
@@ -32,7 +53,8 @@ const getId = () => `${id++}`;
|
|||||||
const UseZoomPanHelperFlow = () => {
|
const UseZoomPanHelperFlow = () => {
|
||||||
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
const onConnect = (params: Connection | Edge) => setEdges((eds) => addEdge(params, eds));
|
const onConnect = (params: Connection | Edge) =>
|
||||||
|
setEdges((eds) => addEdge(params, eds));
|
||||||
const {
|
const {
|
||||||
project,
|
project,
|
||||||
setCenter,
|
setCenter,
|
||||||
@@ -48,7 +70,10 @@ const UseZoomPanHelperFlow = () => {
|
|||||||
|
|
||||||
const onPaneClick = useCallback(
|
const onPaneClick = useCallback(
|
||||||
(evt: MouseEvent) => {
|
(evt: MouseEvent) => {
|
||||||
const projectedPosition = project({ x: evt.clientX, y: evt.clientY - 40 });
|
const projectedPosition = project({
|
||||||
|
x: evt.clientX,
|
||||||
|
y: evt.clientY - 40,
|
||||||
|
});
|
||||||
|
|
||||||
setNodes((nds) =>
|
setNodes((nds) =>
|
||||||
nds.concat({
|
nds.concat({
|
||||||
@@ -92,7 +117,10 @@ const UseZoomPanHelperFlow = () => {
|
|||||||
addEdges({ id: 'e3-4', source: '3', target: '4' });
|
addEdges({ id: 'e3-4', source: '3', target: '4' });
|
||||||
}, [addEdges]);
|
}, [addEdges]);
|
||||||
|
|
||||||
const onResetNodes = useCallback(() => setNodesHook(initialNodes), [setNodesHook]);
|
const onResetNodes = useCallback(
|
||||||
|
() => setNodesHook(initialNodes),
|
||||||
|
[setNodesHook]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
@@ -110,7 +138,9 @@ const UseZoomPanHelperFlow = () => {
|
|||||||
<div style={{ position: 'absolute', left: 0, top: 0, zIndex: 100 }}>
|
<div style={{ position: 'absolute', left: 0, top: 0, zIndex: 100 }}>
|
||||||
<button onClick={() => zoomIn({ duration: 1200 })}>zoomIn</button>
|
<button onClick={() => zoomIn({ duration: 1200 })}>zoomIn</button>
|
||||||
<button onClick={() => zoomOut({ duration: 0 })}>zoomOut</button>
|
<button onClick={() => zoomOut({ duration: 0 })}>zoomOut</button>
|
||||||
<button onClick={() => fitView({ duration: 1200, padding: 0.3 })}>fitView</button>
|
<button onClick={() => fitView({ duration: 1200, padding: 0.3 })}>
|
||||||
|
fitView
|
||||||
|
</button>
|
||||||
<button onClick={onAddNode}>add node</button>
|
<button onClick={onAddNode}>add node</button>
|
||||||
<button onClick={onResetNodes}>reset nodes</button>
|
<button onClick={onResetNodes}>reset nodes</button>
|
||||||
<button onClick={logNodes}>useNodes</button>
|
<button onClick={logNodes}>useNodes</button>
|
||||||
+3
-3
@@ -1,5 +1,5 @@
|
|||||||
import React, { memo, FC, useMemo, CSSProperties } from 'react';
|
import React, { memo, FC, useMemo, CSSProperties } from 'react';
|
||||||
import { Handle, Position, NodeProps } from 'react-flow-renderer';
|
import { Handle, Position, NodeProps } from '@react-flow/core';
|
||||||
|
|
||||||
const nodeStyles: CSSProperties = { padding: 10, border: '1px solid #ddd' };
|
const nodeStyles: CSSProperties = { padding: 10, border: '1px solid #ddd' };
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ const CustomNode: FC<NodeProps> = ({ data }) => {
|
|||||||
return (
|
return (
|
||||||
<Handle
|
<Handle
|
||||||
key={handleId}
|
key={handleId}
|
||||||
type="source"
|
type='source'
|
||||||
position={Position.Right}
|
position={Position.Right}
|
||||||
id={handleId}
|
id={handleId}
|
||||||
style={{ top: 10 * i + data.handlePosition * 10 }}
|
style={{ top: 10 * i + data.handlePosition * 10 }}
|
||||||
@@ -23,7 +23,7 @@ const CustomNode: FC<NodeProps> = ({ data }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={nodeStyles}>
|
<div style={nodeStyles}>
|
||||||
<Handle type="target" position={Position.Left} />
|
<Handle type='target' position={Position.Left} />
|
||||||
<div>output handle count: {data.handleCount}</div>
|
<div>output handle count: {data.handleCount}</div>
|
||||||
{handles}
|
{handles}
|
||||||
</div>
|
</div>
|
||||||
+32
-7
@@ -12,7 +12,7 @@ import ReactFlow, {
|
|||||||
Position,
|
Position,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
import CustomNode from './CustomNode';
|
import CustomNode from './CustomNode';
|
||||||
|
|
||||||
const initialHandleCount = 1;
|
const initialHandleCount = 1;
|
||||||
@@ -21,12 +21,21 @@ const initialNodes: Node[] = [
|
|||||||
{
|
{
|
||||||
id: '1',
|
id: '1',
|
||||||
type: 'custom',
|
type: 'custom',
|
||||||
data: { label: 'Node 1', handleCount: initialHandleCount, handlePosition: 0 },
|
data: {
|
||||||
|
label: 'Node 1',
|
||||||
|
handleCount: initialHandleCount,
|
||||||
|
handlePosition: 0,
|
||||||
|
},
|
||||||
position: { x: 250, y: 5 },
|
position: { x: 250, y: 5 },
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const buttonWrapperStyles: CSSProperties = { position: 'absolute', right: 10, top: 10, zIndex: 10 };
|
const buttonWrapperStyles: CSSProperties = {
|
||||||
|
position: 'absolute',
|
||||||
|
right: 10,
|
||||||
|
top: 10,
|
||||||
|
zIndex: 10,
|
||||||
|
};
|
||||||
|
|
||||||
const nodeTypes: NodeTypes = {
|
const nodeTypes: NodeTypes = {
|
||||||
custom: CustomNode,
|
custom: CustomNode,
|
||||||
@@ -38,7 +47,8 @@ const getId = (): string => `${id++}`;
|
|||||||
const UpdateNodeInternalsFlow = () => {
|
const UpdateNodeInternalsFlow = () => {
|
||||||
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
||||||
const onConnect = (params: Edge | Connection) => setEdges((els) => addEdge(params, els));
|
const onConnect = (params: Edge | Connection) =>
|
||||||
|
setEdges((els) => addEdge(params, els));
|
||||||
|
|
||||||
const updateNodeInternals = useUpdateNodeInternals();
|
const updateNodeInternals = useUpdateNodeInternals();
|
||||||
const { project } = useReactFlow();
|
const { project } = useReactFlow();
|
||||||
@@ -60,7 +70,13 @@ const UpdateNodeInternalsFlow = () => {
|
|||||||
const toggleHandleCount = useCallback(() => {
|
const toggleHandleCount = useCallback(() => {
|
||||||
setNodes((nds) =>
|
setNodes((nds) =>
|
||||||
nds.map((node) => {
|
nds.map((node) => {
|
||||||
return { ...node, data: { ...node.data, handleCount: node.data?.handleCount === 1 ? 2 : 1 } };
|
return {
|
||||||
|
...node,
|
||||||
|
data: {
|
||||||
|
...node.data,
|
||||||
|
handleCount: node.data?.handleCount === 1 ? 2 : 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}, [setNodes]);
|
}, [setNodes]);
|
||||||
@@ -68,12 +84,21 @@ const UpdateNodeInternalsFlow = () => {
|
|||||||
const toggleHandlePosition = useCallback(() => {
|
const toggleHandlePosition = useCallback(() => {
|
||||||
setNodes((nds) =>
|
setNodes((nds) =>
|
||||||
nds.map((node) => {
|
nds.map((node) => {
|
||||||
return { ...node, data: { ...node.data, handlePosition: node.data?.handlePosition === 0 ? 1 : 0 } };
|
return {
|
||||||
|
...node,
|
||||||
|
data: {
|
||||||
|
...node.data,
|
||||||
|
handlePosition: node.data?.handlePosition === 0 ? 1 : 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}, [setNodes]);
|
}, [setNodes]);
|
||||||
|
|
||||||
const updateNode = useCallback(() => updateNodeInternals('1'), [updateNodeInternals]);
|
const updateNode = useCallback(
|
||||||
|
() => updateNodeInternals('1'),
|
||||||
|
[updateNodeInternals]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
+17
-5
@@ -11,7 +11,7 @@ import ReactFlow, {
|
|||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
OnConnectStartParams,
|
OnConnectStartParams,
|
||||||
} from 'react-flow-renderer';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import './validation.css';
|
import './validation.css';
|
||||||
|
|
||||||
@@ -27,15 +27,27 @@ const isValidConnection = (connection: Connection) => connection.target === 'B';
|
|||||||
const CustomInput: FC<NodeProps> = () => (
|
const CustomInput: FC<NodeProps> = () => (
|
||||||
<>
|
<>
|
||||||
<div>Only connectable with B</div>
|
<div>Only connectable with B</div>
|
||||||
<Handle type="source" position={Position.Right} isValidConnection={isValidConnection} />
|
<Handle
|
||||||
|
type='source'
|
||||||
|
position={Position.Right}
|
||||||
|
isValidConnection={isValidConnection}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
const CustomNode: FC<NodeProps> = ({ id }) => (
|
const CustomNode: FC<NodeProps> = ({ id }) => (
|
||||||
<>
|
<>
|
||||||
<Handle type="target" position={Position.Left} isValidConnection={isValidConnection} />
|
<Handle
|
||||||
|
type='target'
|
||||||
|
position={Position.Left}
|
||||||
|
isValidConnection={isValidConnection}
|
||||||
|
/>
|
||||||
<div>{id}</div>
|
<div>{id}</div>
|
||||||
<Handle type="source" position={Position.Right} isValidConnection={isValidConnection} />
|
<Handle
|
||||||
|
type='source'
|
||||||
|
position={Position.Right}
|
||||||
|
isValidConnection={isValidConnection}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -81,7 +93,7 @@ const ValidationFlow = () => {
|
|||||||
onEdgesChange={onEdgesChange}
|
onEdgesChange={onEdgesChange}
|
||||||
onConnect={onConnect}
|
onConnect={onConnect}
|
||||||
selectNodesOnDrag={false}
|
selectNodesOnDrag={false}
|
||||||
className="validationflow"
|
className='validationflow'
|
||||||
nodeTypes={nodeTypes}
|
nodeTypes={nodeTypes}
|
||||||
onConnectStart={onConnectStart}
|
onConnectStart={onConnectStart}
|
||||||
onConnectEnd={onConnectEnd}
|
onConnectEnd={onConnectEnd}
|
||||||
@@ -11,7 +11,6 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@preconstruct/next": "^4.0.0",
|
"@preconstruct/next": "^4.0.0",
|
||||||
"@react-flow/core": "11.0.0",
|
"@react-flow/core": "11.0.0",
|
||||||
"@react-flow/themes": "11.0.0",
|
|
||||||
"next": "12.2.2",
|
"next": "12.2.2",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0"
|
"react-dom": "18.2.0"
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import ReactFlow from '@react-flow/core';
|
import ReactFlow from '@react-flow/core';
|
||||||
import '@react-flow/themes/dark';
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-flow",
|
"name": "react-flow",
|
||||||
"version": "1.0.0",
|
"version": "11.0.0",
|
||||||
"description": "A highly customizable React library for building node-based editors and interactive flow charts",
|
"description": "A highly customizable React library for building node-based editors and interactive flow charts",
|
||||||
"repository": "git@github.com:wbkd/react-flow.git",
|
"repository": "git@github.com:wbkd/react-flow.git",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
import React, { FC } from 'react';
|
|
||||||
import { ConnectionLineComponentProps } from 'react-flow-renderer';
|
|
||||||
|
|
||||||
const ConnectionLine: FC<ConnectionLineComponentProps> = ({ sourceX, sourceY, targetX, targetY, toX, toY }) => {
|
|
||||||
return (
|
|
||||||
<g>
|
|
||||||
<path
|
|
||||||
fill="none"
|
|
||||||
stroke="#222"
|
|
||||||
strokeWidth={1.5}
|
|
||||||
className="animated"
|
|
||||||
d={`M${sourceX},${sourceY} C ${sourceX} ${targetY} ${sourceX} ${targetY} ${targetX},${targetY}`}
|
|
||||||
/>
|
|
||||||
<circle cx={toX} cy={toY} fill="#fff" r={3} stroke="#222" strokeWidth={1.5} />
|
|
||||||
</g>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ConnectionLine;
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
import React, { memo, FC, CSSProperties } from 'react';
|
|
||||||
|
|
||||||
import { Handle, Position, NodeProps, Connection, Edge } from 'react-flow-renderer';
|
|
||||||
|
|
||||||
const targetHandleStyle: CSSProperties = { background: '#555' };
|
|
||||||
const sourceHandleStyleA: CSSProperties = { ...targetHandleStyle, top: 10 };
|
|
||||||
const sourceHandleStyleB: CSSProperties = { ...targetHandleStyle, bottom: 10, top: 'auto' };
|
|
||||||
|
|
||||||
const onConnect = (params: Connection | Edge) => console.log('handle onConnect', params);
|
|
||||||
|
|
||||||
const ColorSelectorNode: FC<NodeProps> = ({ data, isConnectable }) => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Handle type="target" position={Position.Left} style={targetHandleStyle} onConnect={onConnect} />
|
|
||||||
<div>
|
|
||||||
Custom Color Picker Node: <strong>{data.color}</strong>
|
|
||||||
</div>
|
|
||||||
<input className="nodrag" type="color" onChange={data.onChange} defaultValue={data.color} />
|
|
||||||
<Handle
|
|
||||||
type="source"
|
|
||||||
position={Position.Right}
|
|
||||||
id="a"
|
|
||||||
style={sourceHandleStyleA}
|
|
||||||
isConnectable={isConnectable}
|
|
||||||
onMouseDown={(e) => {
|
|
||||||
console.log('You trigger mousedown event', e);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Handle type="source" position={Position.Right} id="b" style={sourceHandleStyleB} isConnectable={isConnectable} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(ColorSelectorNode);
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import { FC } from 'react';
|
|
||||||
import { EdgeProps, getBezierPath } from 'react-flow-renderer';
|
|
||||||
|
|
||||||
const CustomEdge: FC<EdgeProps> = ({
|
|
||||||
id,
|
|
||||||
sourceX,
|
|
||||||
sourceY,
|
|
||||||
targetX,
|
|
||||||
targetY,
|
|
||||||
sourcePosition,
|
|
||||||
targetPosition,
|
|
||||||
data,
|
|
||||||
}) => {
|
|
||||||
const edgePath = getBezierPath({ sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition });
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<path id={id} className="react-flow__edge-path" d={edgePath} />
|
|
||||||
<text>
|
|
||||||
<textPath href={`#${id}`} style={{ fontSize: '12px' }} startOffset="50%" textAnchor="middle">
|
|
||||||
{data.text}
|
|
||||||
</textPath>
|
|
||||||
</text>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CustomEdge;
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
import { Node, Edge, XYPosition, MarkerType } from 'react-flow-renderer';
|
|
||||||
|
|
||||||
const position: XYPosition = { x: 0, y: 0 };
|
|
||||||
|
|
||||||
const nodes: Node[] = [
|
|
||||||
{
|
|
||||||
id: '1',
|
|
||||||
type: 'input',
|
|
||||||
data: { label: 'input' },
|
|
||||||
position,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '2',
|
|
||||||
data: { label: 'node 2' },
|
|
||||||
position,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '2a',
|
|
||||||
data: { label: 'node 2a' },
|
|
||||||
position,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '2b',
|
|
||||||
data: { label: 'node 2b' },
|
|
||||||
position,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '2c',
|
|
||||||
data: { label: 'node 2c' },
|
|
||||||
position,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '2d',
|
|
||||||
data: { label: 'node 2d' },
|
|
||||||
position,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '3',
|
|
||||||
data: { label: 'node 3' },
|
|
||||||
position,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '4',
|
|
||||||
data: { label: 'node 4' },
|
|
||||||
position,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '5',
|
|
||||||
data: { label: 'node 5' },
|
|
||||||
position,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '6',
|
|
||||||
type: 'output',
|
|
||||||
data: { label: 'output' },
|
|
||||||
position,
|
|
||||||
},
|
|
||||||
{ id: '7', type: 'output', data: { label: 'output' }, position: { x: 400, y: 450 } },
|
|
||||||
];
|
|
||||||
|
|
||||||
const edges: Edge[] = [
|
|
||||||
{ id: 'e12', source: '1', target: '2', type: 'smoothstep', markerEnd: { type: MarkerType.Arrow } },
|
|
||||||
{ id: 'e13', source: '1', target: '3', type: 'smoothstep', markerEnd: { type: MarkerType.Arrow } },
|
|
||||||
{ id: 'e22a', source: '2', target: '2a', type: 'smoothstep', markerEnd: { type: MarkerType.Arrow } },
|
|
||||||
{ id: 'e22b', source: '2', target: '2b', type: 'smoothstep', markerEnd: { type: MarkerType.Arrow } },
|
|
||||||
{ id: 'e22c', source: '2', target: '2c', type: 'smoothstep', markerEnd: { type: MarkerType.Arrow } },
|
|
||||||
{ id: 'e2c2d', source: '2c', target: '2d', type: 'smoothstep', markerEnd: { type: MarkerType.Arrow } },
|
|
||||||
|
|
||||||
{ id: 'e45', source: '4', target: '5', type: 'smoothstep', markerEnd: { type: MarkerType.Arrow } },
|
|
||||||
{ id: 'e56', source: '5', target: '6', type: 'smoothstep', markerEnd: { type: MarkerType.Arrow } },
|
|
||||||
{ id: 'e57', source: '5', target: '7', type: 'smoothstep', markerEnd: { type: MarkerType.Arrow } },
|
|
||||||
];
|
|
||||||
|
|
||||||
const nodesAndEdges = { nodes, edges };
|
|
||||||
|
|
||||||
export default nodesAndEdges;
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import React, { memo, FC, CSSProperties } from 'react';
|
|
||||||
|
|
||||||
import { Handle, Position, NodeProps } from 'react-flow-renderer';
|
|
||||||
|
|
||||||
const nodeStyles: CSSProperties = { padding: '10px 15px', border: '1px solid #ddd' };
|
|
||||||
|
|
||||||
const CustomNode: FC<NodeProps> = ({ id }) => {
|
|
||||||
return (
|
|
||||||
<div style={nodeStyles}>
|
|
||||||
<div>node {id}</div>
|
|
||||||
<Handle type="source" id="left" position={Position.Left} />
|
|
||||||
<Handle type="source" id="right" position={Position.Right} />
|
|
||||||
<Handle type="source" id="top" position={Position.Top} />
|
|
||||||
<Handle type="source" id="bottom" position={Position.Bottom} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(CustomNode);
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "@react-flow/minimap",
|
||||||
|
"version": "11.0.0",
|
||||||
|
"description": "A minimap component for usage with React Flow",
|
||||||
|
"main": "index.js",
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"main": "dist/react-flow-themes-dark.cjs.js",
|
|
||||||
"module": "dist/react-flow-themes-dark.esm.js"
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"main": "dist/react-flow-themes-light.cjs.js",
|
|
||||||
"module": "dist/react-flow-themes-light.esm.js"
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@react-flow/themes",
|
|
||||||
"version": "11.0.0",
|
|
||||||
"description": "Themes for React Flow",
|
|
||||||
"license": "MIT",
|
|
||||||
"scripts": {
|
|
||||||
"build": "yarn build:darktheme && yarn build:lighttheme",
|
|
||||||
"build:darktheme": "mkdir -p ./dark/dist && cp ./src/react-flow-dark.css ./dark/dist/react-flow-dark.css",
|
|
||||||
"build:lighttheme": "mkdir -p ./light/dist && cp ./src/react-flow-light.css ./dark/dist/react-flow-light.css"
|
|
||||||
},
|
|
||||||
"preconstruct": {
|
|
||||||
"entrypoints": [
|
|
||||||
"dark.js",
|
|
||||||
"light.js"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
import './react-flow-dark.css';
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
import './react-flow-light.css';
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
.react-flow {
|
|
||||||
background-color: black;
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
.react-flow {
|
|
||||||
background-color: red;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user