refactor(examples): use cra + ts

This commit is contained in:
moklick
2021-02-23 18:39:17 +01:00
parent 2f5ce17a89
commit 20309d4e38
46 changed files with 17435 additions and 462 deletions
@@ -1,11 +1,23 @@
import React, { useState } from 'react';
import React, { useState, MouseEvent } from 'react';
import ReactFlow, { removeElements, addEdge, isNode, Background } from 'react-flow-renderer';
import ReactFlow, {
removeElements,
addEdge,
isNode,
Background,
Elements,
BackgroundVariant,
FlowElement,
Node,
Edge,
Connection,
OnLoadParams,
} from 'react-flow-renderer';
const onNodeDragStop = (event, node) => console.log('drag stop', node);
const onElementClick = (event, element) => console.log('click', element);
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element);
const initialElements = [
const initialElements: Elements = [
{ 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: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, className: 'light' },
@@ -15,11 +27,11 @@ const initialElements = [
];
const BasicFlow = () => {
const [rfInstance, setRfInstance] = useState(null);
const [elements, setElements] = useState(initialElements);
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params) => setElements((els) => addEdge(params, els));
const onLoad = (reactFlowInstance) => setRfInstance(reactFlowInstance);
const [rfInstance, setRfInstance] = useState<OnLoadParams | null>(null);
const [elements, setElements] = useState<Elements>(initialElements);
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params: Edge | Connection) => setElements((els) => addEdge(params, els));
const onLoad = (reactFlowInstance: OnLoadParams) => setRfInstance(reactFlowInstance);
const updatePos = () => {
setElements((elms) => {
@@ -36,8 +48,8 @@ const BasicFlow = () => {
});
};
const logToObject = () => console.log(rfInstance.toObject());
const resetTransform = () => rfInstance.setTransform({ x: 0, y: 0, zoom: 1 });
const logToObject = () => console.log(rfInstance?.toObject());
const resetTransform = () => rfInstance?.setTransform({ x: 0, y: 0, zoom: 1 });
const toggleClassnames = () => {
setElements((elms) => {
@@ -64,7 +76,7 @@ const BasicFlow = () => {
minZoom={0.2}
maxZoom={4}
>
<Background variant="lines" />
<Background variant={BackgroundVariant.Lines} />
<div style={{ position: 'absolute', right: 10, top: 10, zIndex: 4 }}>
<button onClick={resetTransform} style={{ marginRight: 5 }}>
@@ -1,15 +1,7 @@
import React from 'react';
import React, { FC } from 'react';
import { ConnectionLineComponentProps } from 'react-flow-renderer';
export default ({
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
connectionLineType,
connectionLineStyle,
}) => {
const ConnectionLine: FC<ConnectionLineComponentProps> = ({ sourceX, sourceY, targetX, targetY }) => {
return (
<g>
<path
@@ -23,3 +15,5 @@ export default ({
</g>
);
};
export default ConnectionLine;
-25
View File
@@ -1,25 +0,0 @@
import React, { useState } from 'react';
import ReactFlow, { removeElements, addEdge, Background } from 'react-flow-renderer';
import ConnectionLine from './ConnectionLine';
const initialElements = [{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } }];
const ConnectionLineFlow = () => {
const [elements, setElements] = useState(initialElements);
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params) => setElements((els) => addEdge(params, els));
return (
<ReactFlow
elements={elements}
connectionLineComponent={ConnectionLine}
onElementsRemove={onElementsRemove}
onConnect={onConnect}
>
<Background variant="lines" />
</ReactFlow>
);
};
export default ConnectionLineFlow;
@@ -0,0 +1,33 @@
import React, { useState } from 'react';
import ReactFlow, {
removeElements,
addEdge,
Background,
BackgroundVariant,
Elements,
Connection,
Edge,
} from 'react-flow-renderer';
import ConnectionLine from './ConnectionLine';
const initialElements: Elements = [{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } }];
const ConnectionLineFlow = () => {
const [elements, setElements] = useState<Elements>(initialElements);
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
return (
<ReactFlow
elements={elements}
connectionLineComponent={ConnectionLine}
onElementsRemove={onElementsRemove}
onConnect={onConnect}
>
<Background variant={BackgroundVariant.Lines} />
</ReactFlow>
);
};
export default ConnectionLineFlow;
@@ -1,22 +0,0 @@
import React, { memo } from 'react';
import { Handle } from 'react-flow-renderer';
export default memo(({ data }) => {
return (
<>
<Handle
type="target"
position="left"
style={{ background: '#555' }}
onConnect={(params) => console.log('handle onConnect', params)}
/>
<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="right" id="a" style={{ top: 10, background: '#555' }} />
<Handle type="source" position="right" id="b" style={{ bottom: 10, top: 'auto', background: '#555' }} />
</>
);
});
@@ -0,0 +1,25 @@
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 }) => {
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} />
<Handle type="source" position={Position.Right} id="b" style={sourceHandleStyleB} />
</>
);
};
export default memo(ColorSelectorNode);
@@ -1,27 +1,42 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, MouseEvent } from 'react';
import { ChangeEvent } from 'react';
import ReactFlow, { isEdge, removeElements, addEdge, MiniMap, Controls } from 'react-flow-renderer';
import ReactFlow, {
isEdge,
removeElements,
addEdge,
MiniMap,
Controls,
Node,
FlowElement,
OnLoadParams,
Elements,
Position,
SnapGrid,
Connection,
Edge,
} from 'react-flow-renderer';
import ColorSelectorNode from './ColorSelectorNode';
const onLoad = (reactFlowInstance) => console.log('flow loaded:', reactFlowInstance);
const onNodeDragStop = (event, node) => console.log('drag stop', node);
const onElementClick = (event, element) => console.log('click', element);
const onLoad = (reactFlowInstance: OnLoadParams) => console.log('flow loaded:', reactFlowInstance);
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element);
const initBgColor = '#1A192B';
const connectionLineStyle = { stroke: '#fff' };
const snapGrid = [16, 16];
const snapGrid: SnapGrid = [16, 16];
const nodeTypes = {
selectorNode: ColorSelectorNode,
};
const CustomNodeFlow = () => {
const [elements, setElements] = useState([]);
const [bgColor, setBgColor] = useState(initBgColor);
const [elements, setElements] = useState<Elements>([]);
const [bgColor, setBgColor] = useState<string>(initBgColor);
useEffect(() => {
const onChange = (event) => {
const onChange = (event: ChangeEvent<HTMLInputElement>) => {
setElements((els) =>
els.map((e) => {
if (isEdge(e) || e.id !== '2') {
@@ -44,7 +59,13 @@ const CustomNodeFlow = () => {
};
setElements([
{ id: '1', type: 'input', data: { label: 'An input node' }, position: { x: 0, y: 50 }, sourcePosition: 'right' },
{
id: '1',
type: 'input',
data: { label: 'An input node' },
position: { x: 0, y: 50 },
sourcePosition: Position.Right,
},
{
id: '2',
type: 'selectorNode',
@@ -52,8 +73,20 @@ const CustomNodeFlow = () => {
style: { border: '1px solid #777', padding: 10 },
position: { x: 250, y: 50 },
},
{ id: '3', type: 'output', data: { label: 'Output A' }, position: { x: 550, y: 25 }, targetPosition: 'left' },
{ id: '4', type: 'output', data: { label: 'Output B' }, position: { x: 550, y: 100 }, targetPosition: 'left' },
{
id: '3',
type: 'output',
data: { label: 'Output A' },
position: { x: 550, y: 25 },
targetPosition: Position.Left,
},
{
id: '4',
type: 'output',
data: { label: 'Output B' },
position: { x: 550, y: 100 },
targetPosition: Position.Left,
},
{ 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' } },
@@ -61,8 +94,8 @@ const CustomNodeFlow = () => {
]);
}, []);
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params) =>
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params: Connection | Edge) =>
setElements((els) => addEdge({ ...params, animated: true, style: { stroke: '#fff' } }, els));
return (
@@ -81,13 +114,16 @@ const CustomNodeFlow = () => {
defaultZoom={1.5}
>
<MiniMap
nodeStrokeColor={(n) => {
nodeStrokeColor={(n: Node): string => {
if (n.type === 'input') return '#0041d0';
if (n.type === 'selectorNode') return bgColor;
if (n.type === 'output') return '#ff0072';
return '#eee';
}}
nodeColor={(n) => {
nodeColor={(n: Node): string => {
if (n.type === 'selectorNode') return bgColor;
return '#fff';
}}
/>
-23
View File
@@ -1,23 +0,0 @@
import React from 'react';
export default () => {
const onDragStart = (event, nodeType) => {
event.dataTransfer.setData('application/reactflow', nodeType);
event.dataTransfer.effectAllowed = 'move';
};
return (
<aside>
<div className="description">You can drag these nodes to the pane on the right.</div>
<div className="dndnode input" onDragStart={(event) => onDragStart(event, 'input')} draggable>
Input Node
</div>
<div className="dndnode" onDragStart={(event) => onDragStart(event, 'default')} draggable>
Default Node
</div>
<div className="dndnode output" onDragStart={(event) => onDragStart(event, 'output')} draggable>
Output Node
</div>
</aside>
);
};
+25
View File
@@ -0,0 +1,25 @@
import React, { DragEvent } from 'react';
const onDragStart = (event: DragEvent, nodeType: string) => {
event.dataTransfer.setData('application/reactflow', nodeType);
event.dataTransfer.effectAllowed = 'move';
};
const Sidebar = () => {
return (
<aside>
<div className="description">You can drag these nodes to the pane on the right.</div>
<div className="dndnode input" onDragStart={(event: DragEvent) => onDragStart(event, 'input')} draggable>
Input Node
</div>
<div className="dndnode" onDragStart={(event: DragEvent) => onDragStart(event, 'default')} draggable>
Default Node
</div>
<div className="dndnode output" onDragStart={(event: DragEvent) => onDragStart(event, 'output')} draggable>
Output Node
</div>
</aside>
);
};
export default Sidebar;
-62
View File
@@ -1,62 +0,0 @@
import React, { useState } from 'react';
import ReactFlow, { ReactFlowProvider, addEdge, removeElements, Controls } from 'react-flow-renderer';
import Sidebar from './Sidebar';
import './dnd.css';
const initialElements = [{ id: '1', type: 'input', data: { label: 'input node' }, position: { x: 250, y: 5 } }];
let id = 0;
const getId = () => `dndnode_${id++}`;
const DnDFlow = () => {
const [reactFlowInstance, setReactFlowInstance] = useState(null);
const [elements, setElements] = useState(initialElements);
const onConnect = (params) => setElements((els) => addEdge(params, els));
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
const onLoad = (_reactFlowInstance) => setReactFlowInstance(_reactFlowInstance);
const onDragOver = (event) => {
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
};
const onDrop = (event) => {
event.preventDefault();
const type = event.dataTransfer.getData('application/reactflow');
const position = reactFlowInstance.project({ x: event.clientX, y: event.clientY - 40 });
const newNode = {
id: getId(),
type,
position,
data: { label: `${type} node` },
};
setElements((es) => es.concat(newNode));
};
return (
<div className="dndflow">
<ReactFlowProvider>
<div className="reactflow-wrapper">
<ReactFlow
elements={elements}
onConnect={onConnect}
onElementsRemove={onElementsRemove}
onLoad={onLoad}
onDrop={onDrop}
onDragOver={onDragOver}
>
<Controls />
</ReactFlow>
</div>
<Sidebar />
</ReactFlowProvider>
</div>
);
};
export default DnDFlow;
+75
View File
@@ -0,0 +1,75 @@
import React, { useState, DragEvent } from 'react';
import ReactFlow, {
ReactFlowProvider,
addEdge,
removeElements,
Controls,
OnLoadParams,
Elements,
Connection,
Edge,
ElementId,
Node,
} from 'react-flow-renderer';
import Sidebar from './Sidebar';
import './dnd.css';
const initialElements = [{ id: '1', type: 'input', data: { label: 'input node' }, position: { x: 250, y: 5 } }];
const onDragOver = (event: DragEvent) => {
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
};
let id = 0;
const getId = (): ElementId => `dndnode_${id++}`;
const DnDFlow = () => {
const [reactFlowInstance, setReactFlowInstance] = useState<OnLoadParams>();
const [elements, setElements] = useState<Elements>(initialElements);
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
const onLoad = (_reactFlowInstance: OnLoadParams) => setReactFlowInstance(_reactFlowInstance);
const onDrop = (event: DragEvent) => {
event.preventDefault();
if (reactFlowInstance) {
const type = event.dataTransfer.getData('application/reactflow');
const position = reactFlowInstance.project({ x: event.clientX, y: event.clientY - 40 });
const newNode: Node = {
id: getId(),
type,
position,
data: { label: `${type} node` },
};
setElements((es) => es.concat(newNode));
}
};
return (
<div className="dndflow">
<ReactFlowProvider>
<div className="reactflow-wrapper">
<ReactFlow
elements={elements}
onConnect={onConnect}
onElementsRemove={onElementsRemove}
onLoad={onLoad}
onDrop={onDrop}
onDragOver={onDragOver}
>
<Controls />
</ReactFlow>
</div>
<Sidebar />
</ReactFlowProvider>
</div>
);
};
export default DnDFlow;
@@ -3,10 +3,20 @@
*/
import React, { useState } from 'react';
import ReactFlow, { removeElements, addEdge, MiniMap, Controls, Background } from 'react-flow-renderer';
import ReactFlow, {
removeElements,
addEdge,
MiniMap,
Controls,
Background,
OnLoadParams,
Connection,
Edge,
Elements,
} from 'react-flow-renderer';
import { getElements } from './utils';
const onLoad = (reactFlowInstance) => {
const onLoad = (reactFlowInstance: OnLoadParams) => {
reactFlowInstance.fitView();
console.log(reactFlowInstance.getElements());
};
@@ -14,9 +24,9 @@ const onLoad = (reactFlowInstance) => {
const initialElements = getElements();
const EdgeTypesFlow = () => {
const [elements, setElements] = useState(initialElements);
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params) => setElements((els) => addEdge(params, els));
const [elements, setElements] = useState<Elements>(initialElements);
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
return (
<ReactFlow
@@ -1,10 +1,12 @@
import { ElementId, Elements, Position } from 'react-flow-renderer';
const nodeWidth = 80;
const nodeGapWidth = nodeWidth * 2;
const nodeStyle = { width: nodeWidth, fontSize: 11, color: 'white' };
const sourceTargetPositions = [
{ source: 'bottom', target: 'top' },
{ source: 'right', target: 'left' },
{ source: Position.Bottom, target: Position.Top },
{ source: Position.Right, target: Position.Left },
];
const nodeColors = [
['#1e9e99', '#4cb3ac', '#6ec9c0', '#8ddfd4'],
@@ -47,9 +49,9 @@ const offsets = [
];
let id = 0;
const getNodeId = () => (id++).toString();
const getNodeId = (): ElementId => (id++).toString();
export function getElements() {
export function getElements(): Elements {
const initialElements = [];
for (let sourceTargetIndex = 0; sourceTargetIndex < sourceTargetPositions.length; sourceTargetIndex++) {
@@ -1,7 +1,7 @@
import React from 'react';
import { getBezierPath, getMarkerEnd } from 'react-flow-renderer';
import React, { FC } from 'react';
import { EdgeProps, getBezierPath, getMarkerEnd } from 'react-flow-renderer';
export default function CustomEdge({
const CustomEdge: FC<EdgeProps> = ({
id,
sourceX,
sourceY,
@@ -13,7 +13,7 @@ export default function CustomEdge({
data,
arrowHeadType,
markerEndId,
}) {
}) => {
const edgePath = getBezierPath({ sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition });
const markerEnd = getMarkerEnd(arrowHeadType, markerEndId);
@@ -27,4 +27,6 @@ export default function CustomEdge({
</text>
</>
);
}
};
export default CustomEdge;
@@ -1,14 +1,28 @@
import React, { useState } from 'react';
import React, { useState, MouseEvent } from 'react';
import ReactFlow, { removeElements, addEdge, MiniMap, Controls, Background } from 'react-flow-renderer';
import ReactFlow, {
removeElements,
addEdge,
MiniMap,
Controls,
Background,
OnLoadParams,
FlowElement,
EdgeTypesType,
Elements,
Connection,
Edge,
ArrowHeadType,
Node,
} from 'react-flow-renderer';
import CustomEdge from './CustomEdge';
const onLoad = (reactFlowInstance) => reactFlowInstance.fitView();
const onNodeDragStop = (event, node) => console.log('drag stop', node);
const onElementClick = (event, element) => console.log('click', element);
const onLoad = (reactFlowInstance: OnLoadParams) => reactFlowInstance.fitView();
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element);
const initialElements = [
const initialElements: Elements = [
{ 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: '2a', data: { label: 'Node 2a' }, position: { x: 0, y: 180 } },
@@ -31,7 +45,7 @@ const initialElements = [
target: '6',
label: 'styled label',
labelStyle: { fill: 'red', fontWeight: 700 },
arrowHeadType: 'arrow',
arrowHeadType: ArrowHeadType.Arrow,
},
{
id: 'e5-7',
@@ -41,20 +55,27 @@ const initialElements = [
labelBgPadding: [8, 4],
labelBgBorderRadius: 4,
labelBgStyle: { fill: '#FFCC00', color: '#fff', fillOpacity: 0.7 },
arrowHeadType: 'arrowclosed',
arrowHeadType: ArrowHeadType.ArrowClosed,
},
{
id: 'e5-8',
source: '5',
target: '8',
type: 'custom',
data: { text: 'custom edge' },
arrowHeadType: ArrowHeadType.ArrowClosed,
},
{ id: 'e5-8', source: '5', target: '8', type: 'custom', data: { text: 'custom edge' }, arrowHeadType: 'arrowclosed' },
];
const edgeTypes = {
const edgeTypes: EdgeTypesType = {
custom: CustomEdge,
};
const EdgesFlow = () => {
const [elements, setElements] = useState(initialElements);
const [elements, setElements] = useState<Elements>(initialElements);
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params) => setElements((els) => addEdge(params, els));
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
return (
<ReactFlow
-44
View File
@@ -1,44 +0,0 @@
import React, { useState } from 'react';
import ReactFlow, { removeElements, addEdge, MiniMap, Controls, Background } from 'react-flow-renderer';
const onLoad = (reactFlowInstance) => console.log('flow loaded:', reactFlowInstance);
const onElementClick = (event, element) => console.log('click', element);
const onNodeDragStop = (event, node) => console.log('drag stop', node);
const EmptyFlow = () => {
const [elements, setElements] = useState([]);
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params) => setElements((els) => addEdge(params, els));
const addRandomNode = () => {
const nodeId = (elements.length + 1).toString();
const newNode = {
id: nodeId,
data: { label: `Node: ${nodeId}` },
position: { x: Math.random() * window.innerWidth, y: Math.random() * window.innerHeight },
};
setElements((els) => els.concat(newNode));
};
return (
<ReactFlow
elements={elements}
onLoad={onLoad}
onElementClick={onElementClick}
onElementsRemove={onElementsRemove}
onConnect={(p) => onConnect(p)}
onNodeDragStop={onNodeDragStop}
onlyRenderVisibleElements={false}
>
<MiniMap />
<Controls />
<Background variant="lines" />
<button type="button" onClick={addRandomNode} style={{ position: 'absolute', left: 10, top: 10, zIndex: 4 }}>
add node
</button>
</ReactFlow>
);
};
export default EmptyFlow;
+60
View File
@@ -0,0 +1,60 @@
import React, { useState, MouseEvent, CSSProperties } from 'react';
import ReactFlow, {
removeElements,
addEdge,
MiniMap,
Controls,
Background,
OnLoadParams,
Elements,
ElementId,
Node,
FlowElement,
BackgroundVariant,
Connection,
Edge,
} from 'react-flow-renderer';
const onLoad = (reactFlowInstance: OnLoadParams) => console.log('flow loaded:', reactFlowInstance);
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element);
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
const buttonStyle: CSSProperties = { position: 'absolute', left: 10, top: 10, zIndex: 4 };
const EmptyFlow = () => {
const [elements, setElements] = useState<Elements>([]);
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
const addRandomNode = () => {
const nodeId: ElementId = (elements.length + 1).toString();
const newNode: Node = {
id: nodeId,
data: { label: `Node: ${nodeId}` },
position: { x: Math.random() * window.innerWidth, y: Math.random() * window.innerHeight },
};
setElements((els) => els.concat(newNode));
};
return (
<ReactFlow
elements={elements}
onLoad={onLoad}
onElementClick={onElementClick}
onElementsRemove={onElementsRemove}
onConnect={(p) => onConnect(p)}
onNodeDragStop={onNodeDragStop}
onlyRenderVisibleElements={false}
>
<MiniMap />
<Controls />
<Background variant={BackgroundVariant.Lines} />
<button type="button" onClick={addRandomNode} style={buttonStyle}>
add node
</button>
</ReactFlow>
);
};
export default EmptyFlow;
@@ -1,9 +1,9 @@
import React, { useState } from 'react';
import ReactFlow, { addEdge, MiniMap, Controls } from 'react-flow-renderer';
import { useEffect } from 'react';
import ReactFlow, { addEdge, MiniMap, Controls, Connection, Edge, Elements } from 'react-flow-renderer';
const initialElements = [
const initialElements: Elements = [
{ 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: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
@@ -14,9 +14,9 @@ const initialElements = [
];
const HiddenFlow = () => {
const [elements, setElements] = useState(initialElements);
const [isHidden, setIsHidden] = useState(false);
const onConnect = (params) => setElements((els) => addEdge(params, els));
const [elements, setElements] = useState<Elements>(initialElements);
const [isHidden, setIsHidden] = useState<boolean>(false);
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
useEffect(() => {
setElements((els) =>
@@ -1,8 +1,18 @@
import React, { useState } from 'react';
import React, { useState, MouseEvent, WheelEvent } from 'react';
import ReactFlow, {
addEdge,
MiniMap,
Controls,
Elements,
Node,
FlowElement,
Connection,
Edge,
PanOnScrollMode,
FlowTransform,
} from 'react-flow-renderer';
import ReactFlow, { addEdge, MiniMap, Controls } from 'react-flow-renderer';
const initialElements = [
const initialElements: Elements = [
{ 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: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
@@ -11,30 +21,30 @@ const initialElements = [
{ id: 'e1-3', source: '1', target: '3' },
];
const onNodeDragStart = (event, node) => console.log('drag start', node);
const onNodeDragStop = (event, node) => console.log('drag stop', node);
const onElementClick = (event, element) => console.log('click', element);
const onPaneClick = (event) => console.log('onPaneClick', event);
const onPaneScroll = (event) => console.log('onPaneScroll', event);
const onPaneContextMenu = (event) => console.log('onPaneContextMenu', event);
const onMoveEnd = (event) => console.log('onMoveEnd', event);
const onNodeDragStart = (_: MouseEvent, node: Node) => console.log('drag start', node);
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element);
const onPaneClick = (event: MouseEvent) => console.log('onPaneClick', event);
const onPaneScroll = (event?: WheelEvent) => console.log('onPaneScroll', event);
const onPaneContextMenu = (event: MouseEvent) => console.log('onPaneContextMenu', event);
const onMoveEnd = (flowTranasform?: FlowTransform) => console.log('onMoveEnd', flowTranasform);
const InteractionFlow = () => {
const [elements, setElements] = useState(initialElements);
const onConnect = (params) => setElements((els) => addEdge(params, els));
const [elements, setElements] = useState<Elements>(initialElements);
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
const [isSelectable, setIsSelectable] = useState(false);
const [isDraggable, setIsDraggable] = useState(false);
const [isConnectable, setIsConnectable] = useState(false);
const [zoomOnScroll, setZoomOnScroll] = useState(false);
const [zoomOnPinch, setZoomOnPinch] = useState(false);
const [panOnScroll, setPanOnScroll] = useState(false);
const [panOnScrollMode, setPanOnScrollMode] = useState('free');
const [zoomOnDoubleClick, setZoomOnDoubleClick] = useState(false);
const [paneMoveable, setPaneMoveable] = useState(true);
const [captureZoomClick, setCaptureZoomClick] = useState(false);
const [captureZoomScroll, setCaptureZoomScroll] = useState(false);
const [captureElementClick, setCaptureElementClick] = useState(false);
const [isSelectable, setIsSelectable] = useState<boolean>(false);
const [isDraggable, setIsDraggable] = useState<boolean>(false);
const [isConnectable, setIsConnectable] = useState<boolean>(false);
const [zoomOnScroll, setZoomOnScroll] = useState<boolean>(false);
const [zoomOnPinch, setZoomOnPinch] = useState<boolean>(false);
const [panOnScroll, setPanOnScroll] = useState<boolean>(false);
const [panOnScrollMode, setPanOnScrollMode] = useState<PanOnScrollMode>(PanOnScrollMode.Free);
const [zoomOnDoubleClick, setZoomOnDoubleClick] = useState<boolean>(false);
const [paneMoveable, setPaneMoveable] = useState<boolean>(true);
const [captureZoomClick, setCaptureZoomClick] = useState<boolean>(false);
const [captureZoomScroll, setCaptureZoomScroll] = useState<boolean>(false);
const [captureElementClick, setCaptureElementClick] = useState<boolean>(false);
return (
<ReactFlow
@@ -139,7 +149,7 @@ const InteractionFlow = () => {
<select
id="panonscrollmode"
value={panOnScrollMode}
onChange={(event) => setPanOnScrollMode(event.target.value)}
onChange={(event) => setPanOnScrollMode(event.target.value as PanOnScrollMode)}
className="react-flow__panonscrollmode"
>
<option value="free">free</option>
@@ -1,5 +1,16 @@
import React, { useState } from 'react';
import ReactFlow, { ReactFlowProvider, addEdge, removeElements, Controls, isNode } from 'react-flow-renderer';
import ReactFlow, {
ReactFlowProvider,
addEdge,
removeElements,
Controls,
isNode,
Elements,
Connection,
Edge,
NodeExtent,
Position,
} from 'react-flow-renderer';
import dagre from 'dagre';
import initialElements from './initial-elements';
@@ -9,17 +20,17 @@ import './layouting.css';
const dagreGraph = new dagre.graphlib.Graph();
dagreGraph.setDefaultEdgeLabel(() => ({}));
const nodeExtent = [
const nodeExtent: NodeExtent = [
[0, 0],
[1000, 1000],
];
const LayoutFlow = () => {
const [elements, setElements] = useState(initialElements);
const onConnect = (params) => setElements((els) => addEdge(params, els));
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
const [elements, setElements] = useState<Elements>(initialElements);
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
const onLayout = (direction) => {
const onLayout = (direction: string) => {
const isHorizontal = direction === 'LR';
dagreGraph.setGraph({ rankdir: direction });
@@ -36,8 +47,8 @@ const LayoutFlow = () => {
const layoutedElements = elements.map((el) => {
if (isNode(el)) {
const nodeWithPosition = dagreGraph.node(el.id);
el.targetPosition = isHorizontal ? 'left' : 'top';
el.sourcePosition = isHorizontal ? 'right' : 'bottom';
el.targetPosition = isHorizontal ? Position.Left : Position.Top;
el.sourcePosition = isHorizontal ? Position.Right : Position.Bottom;
// we need to pass a slighltiy 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?
el.position = { x: nodeWithPosition.x + Math.random() / 1000, y: nodeWithPosition.y };
@@ -1,6 +1,8 @@
const position = { x: 0, y: 0 };
import { Elements, XYPosition } from 'react-flow-renderer';
export default [
const position: XYPosition = { x: 0, y: 0 };
const elements: Elements = [
{
id: '1',
type: 'input',
@@ -65,3 +67,5 @@ export default [
{ id: 'e56', source: '5', target: '6', type: 'smoothstep' },
{ id: 'e57', source: '5', target: '7', type: 'smoothstep' },
];
export default elements;
@@ -1,13 +1,13 @@
import React, { useState } from 'react';
import React, { useState, CSSProperties } from 'react';
import ReactFlow, { addEdge, isEdge } from 'react-flow-renderer';
import ReactFlow, { addEdge, isEdge, OnLoadParams, Elements, Position, Connection, Edge } from 'react-flow-renderer';
const onLoad = (reactFlowInstance) => reactFlowInstance.fitView();
const onLoad = (reactFlowInstance: OnLoadParams) => reactFlowInstance.fitView();
const initialElements = [
const initialElements: Elements = [
{
id: '1',
sourcePosition: 'right',
sourcePosition: Position.Right,
type: 'input',
data: { label: 'Input' },
position: { x: 0, y: 80 },
@@ -15,17 +15,19 @@ const initialElements = [
{
id: '2',
type: 'output',
sourcePosition: 'right',
targetPosition: 'left',
sourcePosition: Position.Right,
targetPosition: Position.Left,
data: { label: 'A Node' },
position: { x: 250, y: 0 },
},
{ id: 'e1-2', source: '1', type: 'smoothstep', target: '2', animated: true },
];
const buttonStyle: CSSProperties = { position: 'absolute', right: 10, top: 30, zIndex: 4 };
const NodeTypeChangeFlow = () => {
const [elements, setElements] = useState(initialElements);
const onConnect = (params) => setElements((els) => addEdge(params, els));
const [elements, setElements] = useState<Elements>(initialElements);
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
const changeType = () => {
setElements((elms) =>
elms.map((el) => {
@@ -43,7 +45,7 @@ const NodeTypeChangeFlow = () => {
return (
<ReactFlow elements={elements} onConnect={onConnect} onLoad={onLoad}>
<button onClick={changeType} style={{ position: 'absolute', right: 10, top: 30, zIndex: 4 }}>
<button onClick={changeType} style={buttonStyle}>
change type
</button>
</ReactFlow>
@@ -1,30 +1,47 @@
import React, { useState } from 'react';
import React, { useState, MouseEvent, CSSProperties } from 'react';
import ReactFlow, { removeElements, addEdge, MiniMap, Controls, Background, isNode } from 'react-flow-renderer';
import ReactFlow, {
removeElements,
addEdge,
MiniMap,
Controls,
Background,
isNode,
Node,
Elements,
FlowElement,
OnLoadParams,
FlowTransform,
SnapGrid,
ArrowHeadType,
Connection,
Edge,
} from 'react-flow-renderer';
const onNodeDragStart = (event, node) => console.log('drag start', node);
const onNodeDrag = (event, node) => console.log('drag', node);
const onNodeDragStop = (event, node) => console.log('drag stop', node);
const onPaneClick = (event) => console.log('pane click', event);
const onPaneScroll = (event) => console.log('pane scroll', event);
const onPaneContextMenu = (event) => console.log('pane context menu', event);
const onSelectionDrag = (event, nodes) => console.log('selection drag', nodes);
const onSelectionDragStart = (event, nodes) => console.log('selection drag start', nodes);
const onSelectionDragStop = (event, nodes) => console.log('selection drag stop', nodes);
const onSelectionContextMenu = (event, nodes) => {
const onNodeDragStart = (_: MouseEvent, node: Node) => console.log('drag start', node);
const onNodeDrag = (_: MouseEvent, node: Node) => console.log('drag', node);
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
const onPaneClick = (event: MouseEvent) => console.log('pane click', event);
const onPaneScroll = (event?: MouseEvent) => console.log('pane scroll', event);
const onPaneContextMenu = (event: MouseEvent) => console.log('pane context menu', event);
const onSelectionDrag = (_: MouseEvent, nodes: Node[]) => console.log('selection drag', nodes);
const onSelectionDragStart = (_: MouseEvent, nodes: Node[]) => console.log('selection drag start', nodes);
const onSelectionDragStop = (_: MouseEvent, nodes: Node[]) => console.log('selection drag stop', nodes);
const onSelectionContextMenu = (event: MouseEvent, nodes: Node[]) => {
event.preventDefault();
console.log('selection context menu', nodes);
};
const onElementClick = (event, element) => console.log(`${isNode(element) ? 'node' : 'edge'} click:`, element);
const onSelectionChange = (elements) => console.log('selection change', elements);
const onLoad = (reactFlowInstance) => {
const onElementClick = (_: MouseEvent, element: FlowElement) =>
console.log(`${isNode(element) ? 'node' : 'edge'} click:`, element);
const onSelectionChange = (elements: Elements | null) => console.log('selection change', elements);
const onLoad = (reactFlowInstance: OnLoadParams) => {
console.log('flow loaded:', reactFlowInstance);
reactFlowInstance.fitView();
};
const onMoveEnd = (transform) => console.log('zoom/move end', transform);
const onMoveEnd = (transform?: FlowTransform) => console.log('zoom/move end', transform);
const initialElements = [
const initialElements: Elements = [
{
id: '1',
type: 'input',
@@ -101,7 +118,7 @@ const initialElements = [
{ id: 'e1-2', source: '1', target: '2', label: 'this is an edge label' },
{ id: 'e1-3', source: '1', target: '3' },
{ id: 'e3-4', source: '3', target: '4', animated: true, label: 'animated edge' },
{ id: 'e4-5', source: '4', target: '5', arrowHeadType: 'arrowclosed', label: 'edge with arrow head' },
{ id: 'e4-5', source: '4', target: '5', arrowHeadType: ArrowHeadType.Arrow, label: 'edge with arrow head' },
{ id: 'e5-6', source: '5', target: '6', type: 'smoothstep', label: 'smooth step edge' },
{
id: 'e5-7',
@@ -115,13 +132,28 @@ const initialElements = [
},
];
const connectionLineStyle = { stroke: '#ddd' };
const snapGrid = [16, 16];
const connectionLineStyle: CSSProperties = { stroke: '#ddd' };
const snapGrid: SnapGrid = [16, 16];
const nodeStrokeColor = (n: Node): string => {
if (n.style?.background) return n.style.background as string;
if (n.type === 'input') return '#0041d0';
if (n.type === 'output') return '#ff0072';
if (n.type === 'default') return '#1a192b';
return '#eee';
};
const nodeColor = (n: Node): string => {
if (n.style?.background) return n.style.background as string;
return '#fff';
};
const OverviewFlow = () => {
const [elements, setElements] = useState(initialElements);
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params) => setElements((els) => addEdge(params, els));
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
return (
<ReactFlow
@@ -146,22 +178,7 @@ const OverviewFlow = () => {
snapToGrid={true}
snapGrid={snapGrid}
>
<MiniMap
nodeStrokeColor={(n) => {
if (n.style?.background) return n.style.background;
if (n.type === 'input') return '#0041d0';
if (n.type === 'output') return '#ff0072';
if (n.type === 'default') return '#1a192b';
return '#eee';
}}
nodeColor={(n) => {
if (n.style?.background) return n.style.background;
return '#fff';
}}
nodeBorderRadius={2}
/>
<MiniMap nodeStrokeColor={nodeStrokeColor} nodeColor={nodeColor} nodeBorderRadius={2} />
<Controls />
<Background color="#aaa" gap={16} />
</ReactFlow>
@@ -1,5 +1,5 @@
import React from 'react';
import { useStoreState, useStoreActions, isNode } from 'react-flow-renderer';
import { useStoreState, useStoreActions } from 'react-flow-renderer';
const Sidebar = () => {
const nodes = useStoreState((store) => store.nodes);
@@ -1,14 +1,25 @@
import React, { useState } from 'react';
import ReactFlow, { ReactFlowProvider, addEdge, removeElements, Controls } from 'react-flow-renderer';
import React, { useState, MouseEvent } from 'react';
import ReactFlow, {
ReactFlowProvider,
addEdge,
removeElements,
Controls,
OnLoadParams,
FlowElement,
Connection,
Edge,
Elements,
ConnectionMode,
} from 'react-flow-renderer';
import Sidebar from './Sidebar';
import './provider.css';
const onElementClick = (event, element) => console.log('click', element);
const onLoad = (reactFlowInstance) => console.log('flow loaded:', reactFlowInstance);
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element);
const onLoad = (reactFlowInstance: OnLoadParams) => console.log('flow loaded:', reactFlowInstance);
const initialElements = [
const initialElements: Elements = [
{ 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: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
@@ -18,9 +29,9 @@ const initialElements = [
];
const ProviderFlow = () => {
const [elements, setElements] = useState(initialElements);
const onConnect = (params) => setElements((els) => addEdge(params, els));
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
const [elements, setElements] = useState<Elements>(initialElements);
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
return (
<div className="providerflow">
@@ -33,7 +44,7 @@ const ProviderFlow = () => {
onConnect={onConnect}
onElementsRemove={onElementsRemove}
onLoad={onLoad}
connectionMode="loose"
connectionMode={ConnectionMode.Loose}
>
<Controls />
</ReactFlow>
@@ -1,5 +1,5 @@
import React, { memo, useCallback } from 'react';
import { useZoomPanHelper } from 'react-flow-renderer';
import React, { memo, useCallback, Dispatch, FC } from 'react';
import { useZoomPanHelper, OnLoadParams, Elements, FlowExportObject } from 'react-flow-renderer';
import localforage from 'localforage';
localforage.config({
@@ -11,7 +11,12 @@ const flowKey = 'example-flow';
const getNodeId = () => `randomnode_${+new Date()}`;
const Controls = memo(({ rfInstance, setElements }) => {
type ControlsProps = {
rfInstance?: OnLoadParams;
setElements: Dispatch<React.SetStateAction<Elements<any>>>;
};
const Controls: FC<ControlsProps> = ({ rfInstance, setElements }) => {
const { transform } = useZoomPanHelper();
const onSave = useCallback(() => {
@@ -23,7 +28,7 @@ const Controls = memo(({ rfInstance, setElements }) => {
const onRestore = useCallback(() => {
const restoreFlow = async () => {
const flow = await localforage.getItem(flowKey);
const flow: FlowExportObject | null = await localforage.getItem(flowKey);
if (flow) {
const [x = 0, y = 0] = flow.position;
@@ -51,6 +56,6 @@ const Controls = memo(({ rfInstance, setElements }) => {
<button onClick={onAdd}>add node</button>
</div>
);
});
};
export default Controls;
export default memo(Controls);
@@ -1,21 +1,29 @@
import React, { memo, useState } from 'react';
import ReactFlow, { ReactFlowProvider, removeElements, addEdge } from 'react-flow-renderer';
import React, { useState } from 'react';
import ReactFlow, {
ReactFlowProvider,
removeElements,
addEdge,
Elements,
Connection,
Edge,
OnLoadParams,
} from 'react-flow-renderer';
import Controls from './Controls';
import './save.css';
const initialElements = [
const initialElements: Elements = [
{ id: '1', data: { label: 'Node 1' }, position: { x: 100, y: 100 } },
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 200 } },
{ id: 'e1-2', source: '1', target: '2' },
];
const SaveRestore = () => {
const [rfInstance, setRfInstance] = useState(null);
const [elements, setElements] = useState(initialElements);
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params) => setElements((els) => addEdge(params, els));
const [rfInstance, setRfInstance] = useState<OnLoadParams>();
const [elements, setElements] = useState<Elements>(initialElements);
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
return (
<ReactFlowProvider>
@@ -1,19 +1,32 @@
import React, { useState } from 'react';
import React, { useState, CSSProperties } from 'react';
import ReactFlow, {
removeElements,
addEdge,
MiniMap,
isNode,
Controls,
Background,
OnLoadParams,
Elements,
Connection,
Edge,
} from 'react-flow-renderer';
import ReactFlow, { removeElements, addEdge, MiniMap, isNode, Controls, Background } from 'react-flow-renderer';
import { getElements } from './utils';
const onLoad = (reactFlowInstance) => {
const buttonWrapperStyles: CSSProperties = { position: 'absolute', right: 10, top: 10, zIndex: 4 };
const onLoad = (reactFlowInstance: OnLoadParams) => {
reactFlowInstance.fitView();
console.log(reactFlowInstance.getElements());
};
const initialElements = getElements(30, 30);
const initialElements: Elements = getElements(30, 30);
const StressFlow = () => {
const [elements, setElements] = useState(initialElements);
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params) => setElements((els) => addEdge(params, els));
const [elements, setElements] = useState<Elements>(initialElements);
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
const updatePos = () => {
setElements((elms) => {
@@ -44,7 +57,7 @@ const StressFlow = () => {
<Controls />
<Background />
<div style={{ position: 'absolute', right: 10, top: 10, zIndex: 4 }}>
<div style={buttonWrapperStyles}>
<button onClick={updatePos} style={{ marginRight: 5 }}>
change pos
</button>
@@ -1,4 +1,6 @@
export function getElements(xElements = 10, yElements = 10) {
import { Elements } from 'react-flow-renderer';
export function getElements(xElements: number = 10, yElements: number = 10): Elements {
const initialElements = [];
let nodeId = 1;
let recentNodeId = null;
@@ -1,11 +1,11 @@
import React, { useState } from 'react';
import React, { useState, MouseEvent } from 'react';
import ReactFlow, { removeElements, addEdge } from 'react-flow-renderer';
import ReactFlow, { removeElements, addEdge, Node, FlowElement, Elements, Connection, Edge } from 'react-flow-renderer';
const onNodeDragStop = (event, node) => console.log('drag stop', node);
const onElementClick = (event, element) => console.log('click', element);
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element);
const elementsA = [
const elementsA: Elements = [
{ 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: '3a', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, className: 'light' },
@@ -14,7 +14,7 @@ const elementsA = [
{ id: 'e1-3', source: '1a', target: '3a' },
];
const elementsB = [
const elementsB: Elements = [
{ 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: '2b', data: { label: 'Node 2' }, position: { x: 200, y: 100 }, className: 'light' },
@@ -28,9 +28,9 @@ const elementsB = [
];
const BasicFlow = () => {
const [elements, setElements] = useState(elementsA);
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params) => setElements((els) => addEdge(params, els));
const [elements, setElements] = useState<Elements>(elementsA);
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
return (
<ReactFlow
@@ -39,7 +39,6 @@ const BasicFlow = () => {
onElementsRemove={onElementsRemove}
onConnect={onConnect}
onNodeDragStop={onNodeDragStop}
className="react-flow-basic-example"
>
<div style={{ position: 'absolute', right: 10, top: 10, zIndex: 4 }}>
<button onClick={() => setElements(elementsA)} style={{ marginRight: 5 }}>
@@ -1,7 +1,15 @@
import React, { useState } from 'react';
import ReactFlow, { Controls, updateEdge, addEdge } from 'react-flow-renderer';
import ReactFlow, {
Controls,
updateEdge,
addEdge,
Elements,
OnLoadParams,
Connection,
Edge,
} from 'react-flow-renderer';
const initialElements = [
const initialElements: Elements = [
{
id: '1',
type: 'input',
@@ -40,12 +48,13 @@ const initialElements = [
{ id: 'e1-2', source: '1', target: '2', label: 'This is a draggable edge' },
];
const onLoad = (reactFlowInstance) => reactFlowInstance.fitView();
const onLoad = (reactFlowInstance: OnLoadParams) => reactFlowInstance.fitView();
const UpdatableEdge = () => {
const [elements, setElements] = useState(initialElements);
const onEdgeUpdate = (oldEdge, newConnection) => setElements((els) => updateEdge(oldEdge, newConnection, els));
const onConnect = (params) => setElements((els) => addEdge(params, els));
const [elements, setElements] = useState<Elements>(initialElements);
const onEdgeUpdate = (oldEdge: Edge, newConnection: Connection) =>
setElements((els) => updateEdge(oldEdge, newConnection, els));
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
return (
<ReactFlow elements={elements} onLoad={onLoad} snapToGrid={true} onEdgeUpdate={onEdgeUpdate} onConnect={onConnect}>
@@ -1,19 +1,19 @@
import React, { useEffect, useState } from 'react';
import ReactFlow from 'react-flow-renderer';
import ReactFlow, { Elements } from 'react-flow-renderer';
import './updatenode.css';
const initialElements = [
const initialElements: Elements = [
{ id: '1', data: { label: '-' }, position: { x: 100, y: 100 } },
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 200 } },
{ id: 'e1-2', source: '1', target: '2' },
];
const UpdateNode = () => {
const [elements, setElements] = useState(initialElements);
const [nodeName, setNodeName] = useState('Node 1');
const [nodeBg, setNodeBg] = useState('#eee');
const [nodeHidden, setNodeHidden] = useState(false);
const [elements, setElements] = useState<Elements>(initialElements);
const [nodeName, setNodeName] = useState<string>('Node 1');
const [nodeBg, setNodeBg] = useState<string>('#eee');
const [nodeHidden, setNodeHidden] = useState<boolean>(false);
useEffect(() => {
setElements((els) =>
@@ -7,9 +7,13 @@ import ReactFlow, {
MiniMap,
useZoomPanHelper,
ReactFlowProvider,
Elements,
ElementId,
Connection,
Edge,
} from 'react-flow-renderer';
const initialElements = [
const initialElements: Elements = [
{ 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: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, className: 'light' },
@@ -19,12 +23,12 @@ const initialElements = [
];
let id = 5;
const getId = () => `${id++}`;
const getId = (): ElementId => `${id++}`;
const UseZoomPanHelperFlow = () => {
const [elements, setElements] = useState(initialElements);
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params) => setElements((els) => addEdge(params, els));
const [elements, setElements] = useState<Elements>(initialElements);
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
const { project } = useZoomPanHelper();
const onPaneClick = useCallback(
@@ -53,8 +57,10 @@ const UseZoomPanHelperFlow = () => {
);
};
export default () => (
const WrappedFlow = () => (
<ReactFlowProvider>
<UseZoomPanHelperFlow />
</ReactFlowProvider>
);
export default WrappedFlow;
-62
View File
@@ -1,62 +0,0 @@
import React, { useState } from 'react';
import ReactFlow, { addEdge, Handle } from 'react-flow-renderer';
import './validation.css';
const initialElements = [
{ id: '0', type: 'custominput', position: { x: 0, y: 150 } },
{ id: 'A', type: 'customnode', position: { x: 250, y: 0 } },
{ id: 'B', type: 'customnode', position: { x: 250, y: 150 } },
{ id: 'C', type: 'customnode', position: { x: 250, y: 300 } },
];
const onLoad = (reactFlowInstance) => reactFlowInstance.fitView();
const isValidConnection = (connection) => connection.target === 'B';
const onConnectStart = (event, { nodeId, handleType }) => console.log('on connect start', { nodeId, handleType });
const onConnectStop = (event) => console.log('on connect stop', event);
const onConnectEnd = (event) => console.log('on connect end', event);
const CustomInput = () => (
<>
<div>Only connectable with B</div>
<Handle type="source" position="right" isValidConnection={isValidConnection} />
</>
);
const CustomNode = ({ id }) => (
<>
<Handle type="target" position="left" isValidConnection={isValidConnection} />
<div>{id}</div>
<Handle type="source" position="right" isValidConnection={isValidConnection} />
</>
);
const nodeTypes = {
custominput: CustomInput,
customnode: CustomNode,
};
const HorizontalFlow = () => {
const [elements, setElements] = useState(initialElements);
const onConnect = (params) => {
console.log('on connect', params);
setElements((els) => addEdge(params, els));
};
return (
<ReactFlow
elements={elements}
onConnect={onConnect}
selectNodesOnDrag={false}
onLoad={onLoad}
className="validationflow"
nodeTypes={nodeTypes}
onConnectStart={onConnectStart}
onConnectStop={onConnectStop}
onConnectEnd={onConnectEnd}
/>
);
};
export default HorizontalFlow;
+73
View File
@@ -0,0 +1,73 @@
import React, { useState, MouseEvent as ReactMouseEvent, FC } from 'react';
import ReactFlow, {
addEdge,
Handle,
OnLoadParams,
Connection,
Position,
Elements,
Edge,
OnConnectStartParams,
NodeProps,
NodeTypesType,
} from 'react-flow-renderer';
import './validation.css';
const initialElements: Elements = [
{ id: '0', type: 'custominput', position: { x: 0, y: 150 } },
{ id: 'A', type: 'customnode', position: { x: 250, y: 0 } },
{ id: 'B', type: 'customnode', position: { x: 250, y: 150 } },
{ id: 'C', type: 'customnode', position: { x: 250, y: 300 } },
];
const onLoad = (reactFlowInstance: OnLoadParams) => reactFlowInstance.fitView();
const isValidConnection = (connection: Connection) => connection.target === 'B';
const onConnectStart = (_: ReactMouseEvent, { nodeId, handleType }: OnConnectStartParams) =>
console.log('on connect start', { nodeId, handleType });
const onConnectStop = (event: MouseEvent) => console.log('on connect stop', event);
const onConnectEnd = (event: MouseEvent) => console.log('on connect end', event);
const CustomInput: FC<NodeProps> = () => (
<>
<div>Only connectable with B</div>
<Handle type="source" position={Position.Right} isValidConnection={isValidConnection} />
</>
);
const CustomNode: FC<NodeProps> = ({ id }) => (
<>
<Handle type="target" position={Position.Left} isValidConnection={isValidConnection} />
<div>{id}</div>
<Handle type="source" position={Position.Right} isValidConnection={isValidConnection} />
</>
);
const nodeTypes: NodeTypesType = {
custominput: CustomInput,
customnode: CustomNode,
};
const HorizontalFlow = () => {
const [elements, setElements] = useState<Elements>(initialElements);
const onConnect = (params: Connection | Edge) => {
console.log('on connect', params);
setElements((els) => addEdge(params, els));
};
return (
<ReactFlow
elements={elements}
onConnect={onConnect}
selectNodesOnDrag={false}
onLoad={onLoad}
className="validationflow"
nodeTypes={nodeTypes}
onConnectStart={onConnectStart}
onConnectStop={onConnectStop}
onConnectEnd={onConnectEnd}
/>
);
};
export default HorizontalFlow;
@@ -1,4 +1,4 @@
import React from 'react';
import React, { ChangeEvent } from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route, Switch, withRouter } from 'react-router-dom';
@@ -109,7 +109,7 @@ const routes = [
];
const Header = withRouter(({ history, location }) => {
const onChange = (event) => history.push(event.target.value);
const onChange = (event: ChangeEvent<HTMLSelectElement>) => history.push(event.target.value);
return (
<header>
+1
View File
@@ -0,0 +1 @@
/// <reference types="react-scripts" />