chore(examples): move examples to demo folder

This commit is contained in:
Christopher Möller
2022-07-19 15:12:37 +02:00
parent 97a9d0440f
commit 6733076ab4
86 changed files with 10840 additions and 4710 deletions
@@ -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
@@ -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;
@@ -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);
@@ -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
@@ -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 }}>
@@ -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} />
</> </>
); );
}; };
@@ -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';
@@ -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}
@@ -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 />
@@ -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,
+40
View File
@@ -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;
@@ -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>
@@ -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>
); );
}; };
@@ -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>
); );
}; };
@@ -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}
@@ -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>
@@ -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>
@@ -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;
@@ -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>
); );
@@ -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}
@@ -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) => {
@@ -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 (
@@ -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>
); );
}; };
@@ -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>
@@ -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}
@@ -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>
@@ -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;
@@ -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
@@ -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);
@@ -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));
@@ -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[] = [
{ {
@@ -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,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']);
@@ -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>
@@ -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>
@@ -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
@@ -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}
-1
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+7
View File
@@ -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"
}
-4
View File
@@ -1,4 +0,0 @@
{
"main": "dist/react-flow-themes-dark.cjs.js",
"module": "dist/react-flow-themes-dark.esm.js"
}
-4
View File
@@ -1,4 +0,0 @@
{
"main": "dist/react-flow-themes-light.cjs.js",
"module": "dist/react-flow-themes-light.esm.js"
}
-17
View File
@@ -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
View File
@@ -1 +0,0 @@
import './react-flow-dark.css';
-1
View File
@@ -1 +0,0 @@
import './react-flow-light.css';
-3
View File
@@ -1,3 +0,0 @@
.react-flow {
background-color: black;
}
-3
View File
@@ -1,3 +0,0 @@
.react-flow {
background-color: red;
}
+9583 -4180
View File
File diff suppressed because it is too large Load Diff