feat(website): init

This commit is contained in:
moklick
2020-10-05 10:14:49 +02:00
parent f54b93b319
commit 277e032770
140 changed files with 30517 additions and 0 deletions
@@ -0,0 +1,25 @@
import React from 'react';
export default ({
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
connectionLineType,
connectionLineStyle,
}) => {
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>
);
};
@@ -0,0 +1,37 @@
import React, { useState } from 'react';
import ReactFlow, {
removeElements,
addEdge,
Background,
} from 'react-flow-renderer';
import ConnectionLine from './ConnectionLine';
const initialElements = [
{
id: 'connectionline-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,22 @@
import React, { memo } from 'react';
import { Handle } from 'react-flow-renderer';
export default memo(({ data }) => {
return (
<>
<Handle
type="target"
position="left"
style={{ background: '#fff' }}
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: '#fff' }} />
<Handle type="source" position="right" id="b" style={{ bottom: 10, top: 'auto', background: '#fff' }} />
</>
);
});
@@ -0,0 +1,7 @@
.react-flow__node-selectorNode {
font-size: 12px;
background: #eee;
border: 1px solid #555;
border-radius: 5px;
text-align: center;
}
@@ -0,0 +1,141 @@
import React, { useState, useEffect } from 'react';
import ReactFlow, {
isEdge,
removeElements,
addEdge,
MiniMap,
Controls,
} from 'react-flow-renderer';
import ColorSelectorNode from './ColorSelectorNode';
import './index.css';
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 initBgColor = '#f0e742';
const connectionLineStyle = { stroke: '#fff' };
const snapGrid = [16, 16];
const nodeTypes = {
selectorNode: ColorSelectorNode,
};
const CustomNodeFlow = () => {
const [elements, setElements] = useState([]);
const [bgColor, setBgColor] = useState(initBgColor);
useEffect(() => {
const onChange = (event) => {
setElements((els) =>
els.map((e) => {
if (isEdge(e) || e.id !== 'custom-2') {
return e;
}
const color = event.target.value;
setBgColor(color);
return {
...e,
data: {
...e.data,
color,
},
};
})
);
};
setElements([
{
id: 'custom-1',
type: 'input',
data: { label: 'An input node' },
position: { x: 0, y: 50 },
sourcePosition: 'right',
},
{
id: 'custom-2',
type: 'selectorNode',
data: { onChange: onChange, color: initBgColor },
style: { border: '1px solid #777', padding: 10 },
position: { x: 250, y: 50 },
},
{
id: 'custom-3',
type: 'output',
data: { label: 'Output A' },
position: { x: 550, y: 25 },
targetPosition: 'left',
},
{
id: 'custom-4',
type: 'output',
data: { label: 'Output B' },
position: { x: 550, y: 100 },
targetPosition: 'left',
},
{
id: 'custom-e1-2',
source: 'custom-1',
target: 'custom-2',
animated: true,
style: { stroke: '#fff' },
},
{
id: 'custom-e2a-3',
source: 'custom-2__a',
target: 'custom-3',
animated: true,
style: { stroke: '#fff' },
},
{
id: 'custom-e2b-4',
source: 'custom-2__b',
target: 'custom-4',
animated: true,
style: { stroke: '#fff' },
},
]);
}, []);
const onElementsRemove = (elementsToRemove) =>
setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params) =>
setElements((els) =>
addEdge({ ...params, animated: true, style: { stroke: '#fff' } }, els)
);
return (
<ReactFlow
elements={elements}
onElementClick={onElementClick}
onElementsRemove={onElementsRemove}
onConnect={onConnect}
onNodeDragStop={onNodeDragStop}
style={{ background: bgColor }}
onLoad={onLoad}
nodeTypes={nodeTypes}
connectionLineStyle={connectionLineStyle}
snapToGrid={true}
snapGrid={snapGrid}
>
<MiniMap
nodeColor={(n) => {
if (n.type === 'input') return 'blue';
if (n.type === 'selectorNode') return bgColor;
if (n.type === 'output') return 'green';
}}
/>
<Controls />
</ReactFlow>
);
};
export default CustomNodeFlow;
@@ -0,0 +1,36 @@
/**
* Example for checking the different edge types and source and target positions
*/
import React, { useState } from 'react';
import ReactFlow, { removeElements, addEdge, MiniMap, Controls, Background } from 'react-flow-renderer';
import { getElements } from './utils';
const onLoad = (reactFlowInstance) => {
reactFlowInstance.fitView();
console.log(reactFlowInstance.getElements());
};
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));
return (
<ReactFlow
elements={elements}
onLoad={onLoad}
onElementsRemove={onElementsRemove}
onConnect={onConnect}
minZoom={0.2}
>
<MiniMap />
<Controls />
<Background />
</ReactFlow>
);
};
export default EdgeTypesFlow;
@@ -0,0 +1,120 @@
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' },
];
const nodeColors = [
['#1e9e99', '#4cb3ac', '#6ec9c0', '#8ddfd4'],
['#0f4c75', '#1b5d8b', '#276fa1', '#3282b8'],
];
const edgeTypes = ['default', 'step', 'smoothstep', 'straight'];
const offsets = [
{
x: 0,
y: -nodeGapWidth,
},
{
x: nodeGapWidth,
y: -nodeGapWidth,
},
{
x: nodeGapWidth,
y: 0,
},
{
x: nodeGapWidth,
y: nodeGapWidth,
},
{
x: 0,
y: nodeGapWidth,
},
{
x: -nodeGapWidth,
y: nodeGapWidth,
},
{
x: -nodeGapWidth,
y: 0,
},
{
x: -nodeGapWidth,
y: -nodeGapWidth,
},
];
let id = 0;
const getNodeId = () => `edgetypes-${(id++).toString()}`;
export function getElements() {
const initialElements = [];
for (
let sourceTargetIndex = 0;
sourceTargetIndex < sourceTargetPositions.length;
sourceTargetIndex++
) {
const currSourceTargetPos = sourceTargetPositions[sourceTargetIndex];
for (
let edgeTypeIndex = 0;
edgeTypeIndex < edgeTypes.length;
edgeTypeIndex++
) {
const currEdgeType = edgeTypes[edgeTypeIndex];
for (let offsetIndex = 0; offsetIndex < offsets.length; offsetIndex++) {
const currOffset = offsets[offsetIndex];
const style = {
...nodeStyle,
background: nodeColors[sourceTargetIndex][edgeTypeIndex],
};
const sourcePosition = {
x: offsetIndex * nodeWidth * 4,
y: edgeTypeIndex * 300 + sourceTargetIndex * edgeTypes.length * 300,
};
const sourceId = getNodeId();
const sourceData = { label: `Source ${sourceId}` };
const sourceNode = {
id: sourceId,
style,
data: sourceData,
position: sourcePosition,
sourcePosition: currSourceTargetPos.source,
targetPosition: currSourceTargetPos.target,
};
const targetId = getNodeId();
const targetData = { label: `Target ${targetId}` };
const targetPosition = {
x: sourcePosition.x + currOffset.x,
y: sourcePosition.y + currOffset.y,
};
const targetNode = {
id: targetId,
style,
data: targetData,
position: targetPosition,
sourcePosition: currSourceTargetPos.source,
targetPosition: currSourceTargetPos.target,
};
initialElements.push(sourceNode);
initialElements.push(targetNode);
initialElements.push({
id: `${sourceId}-${targetId}`,
source: sourceId,
target: targetId,
type: currEdgeType,
});
}
}
}
return initialElements;
}
@@ -0,0 +1,30 @@
import React from 'react';
import { getBezierPath, getMarkerEnd } from 'react-flow-renderer';
export default function CustomEdge({
id,
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
style = {},
data,
arrowHeadType,
markerEndId,
}) {
const edgePath = getBezierPath({ sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition });
const markerEnd = getMarkerEnd(arrowHeadType, markerEndId);
return (
<>
<path id={id} style={style} className="react-flow__edge-path" d={edgePath} markerEnd={markerEnd} />
<text>
<textPath href={`#${id}`} style={{ fontSize: '12px' }} startOffset="50%" textAnchor="middle">
{data.text}
</textPath>
</text>
</>
);
}
+152
View File
@@ -0,0 +1,152 @@
import React, { useState } from 'react';
import ReactFlow, {
removeElements,
addEdge,
MiniMap,
Controls,
Background,
} 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 initialElements = [
{
id: 'edges-1',
type: 'input',
data: { label: 'Input 1' },
position: { x: 250, y: 0 },
},
{ id: 'edges-2', data: { label: 'Node 2' }, position: { x: 150, y: 100 } },
{ id: 'edges-2a', data: { label: 'Node 2a' }, position: { x: 0, y: 180 } },
{ id: 'edges-3', data: { label: 'Node 3' }, position: { x: 250, y: 200 } },
{ id: 'edges-4', data: { label: 'Node 4' }, position: { x: 400, y: 300 } },
{ id: 'edges-3a', data: { label: 'Node 3a' }, position: { x: 150, y: 300 } },
{ id: 'edges-5', data: { label: 'Node 5' }, position: { x: 250, y: 400 } },
{
id: 'edges-6',
type: 'output',
data: { label: 'Output 6' },
position: { x: 50, y: 550 },
},
{
id: 'edges-7',
type: 'output',
data: { label: 'Output 7' },
position: { x: 250, y: 550 },
},
{
id: 'edges-8',
type: 'output',
data: { label: 'Output 8' },
position: { x: 525, y: 600 },
},
{
id: 'edges-e1-2',
source: 'edges-1',
target: 'edges-2',
label: 'bezier edge (default)',
className: 'normal-edge',
},
{
id: 'edges-e2-2a',
source: 'edges-2',
target: 'edges-2a',
type: 'smoothstep',
label: 'smoothstep edge',
},
{
id: 'edges-e2-3',
source: 'edges-2',
target: 'edges-3',
type: 'step',
label: 'step edge',
},
{
id: 'edges-e3-4',
source: 'edges-3',
target: 'edges-4',
type: 'straight',
label: 'straight edge',
},
{
id: 'edges-e3-3a',
source: 'edges-3',
target: 'edges-3a',
type: 'straight',
label: 'label only edge',
style: { stroke: 'none' },
},
{
id: 'edges-e3-5',
source: 'edges-4',
target: 'edges-5',
animated: true,
label: 'animated styled edge',
style: { stroke: 'red' },
},
{
id: 'edges-e5-6',
source: 'edges-5',
target: 'edges-6',
label: 'styled label',
labelStyle: { fill: 'red', fontWeight: 700 },
arrowHeadType: 'arrow',
},
{
id: 'edges-e5-7',
source: 'edges-5',
target: 'edges-7',
label: 'label with styled bg',
labelBgPadding: [8, 4],
labelBgBorderRadius: 4,
labelBgStyle: { fill: '#FFCC00', color: '#fff', fillOpacity: 0.7 },
arrowHeadType: 'arrowclosed',
},
{
id: 'edges-e5-8',
source: 'edges-5',
target: 'edges-8',
type: 'custom',
data: { text: 'custom edge' },
arrowHeadType: 'arrowclosed',
},
];
const edgeTypes = {
custom: CustomEdge,
};
const EdgesFlow = () => {
const [elements, setElements] = useState(initialElements);
const onElementsRemove = (elementsToRemove) =>
setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params) => setElements((els) => addEdge(params, els));
console.log('render edges');
return (
<ReactFlow
elements={elements}
onElementClick={onElementClick}
onElementsRemove={onElementsRemove}
onConnect={onConnect}
onNodeDragStop={onNodeDragStop}
onLoad={onLoad}
snapToGrid={true}
edgeTypes={edgeTypes}
key="edges"
>
<MiniMap />
<Controls />
<Background />
</ReactFlow>
);
};
export default EdgesFlow;
+58
View File
@@ -0,0 +1,58 @@
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 = `nodes-${(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}
>
<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;
+58
View File
@@ -0,0 +1,58 @@
import React, { useState } from 'react';
import ReactFlow, { addEdge, MiniMap, Controls } from 'react-flow-renderer';
import { useEffect } from 'react';
const initialElements = [
{
id: 'hidden-1',
type: 'input',
data: { label: 'Node 1' },
position: { x: 250, y: 5 },
},
{ id: 'hidden-2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
{ id: 'hidden-3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
{ id: 'hidden-4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
{ id: 'hidden-e1-2', source: 'hidden-1', target: 'hidden-2' },
{ id: 'hidden-e1-3', source: 'hidden-1', target: 'hidden-3' },
{ id: 'hidden-e3-4', source: 'hidden-3', target: 'hidden-4' },
];
const HiddenFlow = () => {
const [elements, setElements] = useState(initialElements);
const [isHidden, setIsHidden] = useState(false);
const onConnect = (params) => setElements((els) => addEdge(params, els));
useEffect(() => {
setElements((els) =>
els.map((e) => {
e.isHidden = isHidden;
return e;
})
);
}, [isHidden]);
return (
<ReactFlow elements={elements} onConnect={onConnect}>
<MiniMap />
<Controls />
<div style={{ position: 'absolute', left: 10, top: 10, zIndex: 4 }}>
<div>
<label htmlFor="ishidden">
isHidden
<input
id="ishidden"
type="checkbox"
checked={isHidden}
onChange={(event) => setIsHidden(event.target.checked)}
className="react-flow__ishidden"
/>
</label>
</div>
</div>
</ReactFlow>
);
};
export default HiddenFlow;
@@ -0,0 +1,164 @@
import React, { useState } from 'react';
import ReactFlow, { removeElements, addEdge } from 'react-flow-renderer';
const onLoad = (reactFlowInstance) => reactFlowInstance.fitView();
const onNodeMouseEnter = (event, node) => console.log('mouse enter:', node);
const onNodeMouseMove = (event, node) => console.log('mouse move:', node);
const onNodeMouseLeave = (event, node) => console.log('mouse leave:', node);
const onNodeContextMenu = (event, node) => {
event.preventDefault();
console.log('context menu:', node);
};
const initialElements = [
{
id: 'horizontal-1',
sourcePosition: 'right',
type: 'input',
className: 'dark-node',
data: { label: 'Input' },
position: { x: 0, y: 80 },
},
{
id: 'horizontal-2',
sourcePosition: 'right',
targetPosition: 'left',
data: { label: 'A Node' },
position: { x: 250, y: 0 },
},
{
id: 'horizontal-3',
sourcePosition: 'right',
targetPosition: 'left',
data: { label: 'Node 3' },
position: { x: 250, y: 160 },
},
{
id: 'horizontal-4',
sourcePosition: 'right',
targetPosition: 'left',
data: { label: 'Node 4' },
position: { x: 500, y: 0 },
},
{
id: 'horizontal-5',
sourcePosition: 'top',
targetPosition: 'bottom',
data: { label: 'Node 5' },
position: { x: 500, y: 100 },
},
{
id: 'horizontal-6',
sourcePosition: 'bottom',
targetPosition: 'top',
data: { label: 'Node 6' },
position: { x: 500, y: 230 },
},
{
id: 'horizontal-7',
sourcePosition: 'right',
targetPosition: 'left',
data: { label: 'Node 7' },
position: { x: 750, y: 50 },
},
{
id: 'horizontal-8',
sourcePosition: 'right',
targetPosition: 'left',
data: { label: 'Node 8' },
position: { x: 750, y: 300 },
},
{
id: 'horizontal-e1-2',
source: 'horizontal-1',
type: 'smoothstep',
target: 'horizontal-2',
animated: true,
},
{
id: 'horizontal-e1-3',
source: 'horizontal-1',
type: 'smoothstep',
target: 'horizontal-3',
animated: true,
},
{
id: 'horizontal-e1-4',
source: 'horizontal-2',
type: 'smoothstep',
target: 'horizontal-4',
label: 'edge label',
},
{
id: 'horizontal-e3-5',
source: 'horizontal-3',
type: 'smoothstep',
target: 'horizontal-5',
animated: true,
},
{
id: 'horizontal-e3-6',
source: 'horizontal-3',
type: 'smoothstep',
target: 'horizontal-6',
animated: true,
},
{
id: 'horizontal-e5-7',
source: 'horizontal-5',
type: 'smoothstep',
target: 'horizontal-7',
animated: true,
},
{
id: 'horizontal-e6-8',
source: 'horizontal-6',
type: 'smoothstep',
target: 'horizontal-8',
animated: true,
},
];
const HorizontalFlow = () => {
const [elements, setElements] = useState(initialElements);
const onElementsRemove = (elementsToRemove) =>
setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params) => setElements((els) => addEdge(params, els));
const changeClassName = () => {
setElements((elms) =>
elms.map((el) => {
if (el.type === 'input') {
el.className = el.className ? '' : 'dark-node';
}
return { ...el };
})
);
};
return (
<ReactFlow
elements={elements}
onElementsRemove={onElementsRemove}
onConnect={onConnect}
onLoad={onLoad}
selectNodesOnDrag={false}
onNodeMouseEnter={onNodeMouseEnter}
onNodeMouseMove={onNodeMouseMove}
onNodeMouseLeave={onNodeMouseLeave}
onNodeContextMenu={onNodeContextMenu}
>
<button
onClick={changeClassName}
style={{ position: 'absolute', right: 10, top: 30, zIndex: 4 }}
>
change class name
</button>
</ReactFlow>
);
};
export default HorizontalFlow;
@@ -0,0 +1,191 @@
import React, { useState } from 'react';
import ReactFlow, { addEdge, MiniMap, Controls } from 'react-flow-renderer';
const initialElements = [
{
id: 'interaction-1',
type: 'input',
data: { label: 'Node 1' },
position: { x: 250, y: 5 },
},
{
id: 'interaction-2',
data: { label: 'Node 2' },
position: { x: 100, y: 100 },
},
{
id: 'interaction-3',
data: { label: 'Node 3' },
position: { x: 400, y: 100 },
},
{
id: 'interaction-4',
data: { label: 'Node 4' },
position: { x: 400, y: 200 },
},
{
id: 'interaction-e1-2',
source: 'interaction-1',
target: 'interaction-2',
animated: true,
},
{ id: 'interaction-e1-3', source: 'interaction-1', target: 'interaction-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 InteractionFlow = () => {
const [elements, setElements] = useState(initialElements);
const onConnect = (params) => 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 [zoomOnDoubleClick, setZoomOnDoubleClick] = useState(false);
const [paneMoveable, setPaneMoveable] = useState(true);
const [captureZoomClick, setCaptureZoomClick] = useState(false);
const [captureZoomScroll, setCaptureZoomScroll] = useState(false);
const [captureElementClick, setCaptureElementClick] = useState(false);
return (
<ReactFlow
elements={elements}
elementsSelectable={isSelectable}
nodesConnectable={isConnectable}
nodesDraggable={isDraggable}
zoomOnScroll={zoomOnScroll}
zoomOnDoubleClick={zoomOnDoubleClick}
onConnect={onConnect}
onElementClick={captureElementClick ? onElementClick : undefined}
onNodeDragStart={onNodeDragStart}
onNodeDragStop={onNodeDragStop}
paneMoveable={paneMoveable}
onPaneClick={captureZoomClick ? onPaneClick : undefined}
onPaneScroll={captureZoomScroll ? onPaneScroll : undefined}
onPaneContextMenu={captureZoomClick ? onPaneContextMenu : undefined}
>
<MiniMap />
<Controls />
<div style={{ position: 'absolute', left: 10, top: 10, zIndex: 4 }}>
<div>
<label htmlFor="draggable">
draggable
<input
id="draggable"
type="checkbox"
checked={isDraggable}
onChange={(event) => setIsDraggable(event.target.checked)}
className="react-flow__draggable"
/>
</label>
</div>
<div>
<label htmlFor="connectable">
connectable
<input
id="connectable"
type="checkbox"
checked={isConnectable}
onChange={(event) => setIsConnectable(event.target.checked)}
className="react-flow__connectable"
/>
</label>
</div>
<div>
<label htmlFor="selectable">
selectable
<input
id="selectable"
type="checkbox"
checked={isSelectable}
onChange={(event) => setIsSelectable(event.target.checked)}
className="react-flow__selectable"
/>
</label>
</div>
<div>
<label htmlFor="zoomonscroll">
zoom on scroll
<input
id="zoomonscroll"
type="checkbox"
checked={zoomOnScroll}
onChange={(event) => setZoomOnScroll(event.target.checked)}
className="react-flow__zoomonscroll"
/>
</label>
</div>
<div>
<label htmlFor="zoomondbl">
zoom on double click
<input
id="zoomondbl"
type="checkbox"
checked={zoomOnDoubleClick}
onChange={(event) => setZoomOnDoubleClick(event.target.checked)}
className="react-flow__zoomondbl"
/>
</label>
</div>
<div>
<label htmlFor="panemoveable">
pane moveable
<input
id="panemoveable"
type="checkbox"
checked={paneMoveable}
onChange={(event) => setPaneMoveable(event.target.checked)}
className="react-flow__panemoveable"
/>
</label>
</div>
<div>
<label htmlFor="capturezoompaneclick">
capture zoom pane click
<input
id="capturezoompaneclick"
type="checkbox"
checked={captureZoomClick}
onChange={(event) => setCaptureZoomClick(event.target.checked)}
className="react-flow__capturezoompaneclick"
/>
</label>
</div>
<div>
<label htmlFor="capturezoompanescroll">
capture zoom pane scroll
<input
id="capturezoompanescroll"
type="checkbox"
checked={captureZoomScroll}
onChange={(event) => setCaptureZoomScroll(event.target.checked)}
className="react-flow__capturezoompanescroll"
/>
</label>
</div>
<div>
<label htmlFor="captureelementclick">
capture element click
<input
id="captureelementclick"
type="checkbox"
checked={captureElementClick}
onChange={(event) => setCaptureElementClick(event.target.checked)}
className="react-flow__captureelementclick"
/>
</label>
</div>
</div>
</ReactFlow>
);
};
export default InteractionFlow;
+209
View File
@@ -0,0 +1,209 @@
import React, { useState } from 'react';
import ReactFlow, {
removeElements,
addEdge,
MiniMap,
Controls,
Background,
isNode,
} from 'react-flow-renderer';
const onNodeDragStart = (event, node) => console.log('drag start', node);
const onNodeDragStop = (event, node) => console.log('drag stop', node);
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) => {
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) => {
console.log('flow loaded:', reactFlowInstance);
reactFlowInstance.fitView();
};
const onMoveEnd = (transform) => console.log('zoom/move end', transform);
const initialElements = [
{
id: 'overview-1',
type: 'input',
data: {
label: (
<>
Welcome to <strong>React Flow!</strong>
</>
),
},
position: { x: 250, y: 0 },
},
{
id: 'overview-2',
data: {
label: (
<>
This is a <strong>default node</strong>
</>
),
},
position: { x: 100, y: 100 },
},
{
id: 'overview-3',
data: {
label: (
<>
This one has a <strong>custom style</strong>
</>
),
},
position: { x: 400, y: 100 },
style: {
background: '#D6D5E6',
color: '#333',
border: '1px solid #222138',
width: 180,
},
},
{
id: 'overview-4',
position: { x: 250, y: 200 },
data: {
label: (
<>
You can find the docs on{' '}
<a
href="https://github.com/wbkd/react-flow"
target="_blank"
rel="noopener noreferrer"
>
Github
</a>
</>
),
},
},
{
id: 'overview-5',
data: {
label: (
<>
Or check out the other <strong>examples</strong>
</>
),
},
position: { x: 250, y: 325 },
},
{
id: 'overview-6',
type: 'output',
data: {
label: (
<>
An <strong>output node</strong>
</>
),
},
position: { x: 100, y: 480 },
},
{
id: 'overview-7',
type: 'output',
data: { label: 'Another output node' },
position: { x: 400, y: 450 },
},
{
id: 'overview-e1-2',
source: 'overview-1',
target: 'overview-2',
label: 'this is an edge label',
},
{ id: 'overview-e1-3', source: 'overview-1', target: 'overview-3' },
{
id: 'overview-e3-4',
source: 'overview-3',
target: 'overview-4',
animated: true,
label: 'animated edge',
},
{
id: 'overview-e4-5',
source: 'overview-4',
target: 'overview-5',
arrowHeadType: 'arrowclosed',
label: 'edge with arrow head',
},
{
id: 'overview-e5-6',
source: 'overview-5',
target: 'overview-6',
type: 'smoothstep',
label: 'smooth step edge',
},
{
id: 'overview-e5-7',
source: 'overview-5',
target: 'overview-7',
type: 'step',
style: { stroke: '#f6ab6c' },
label: 'a step edge',
animated: true,
labelStyle: { fill: '#f6ab6c', fontWeight: 700 },
},
];
const connectionLineStyle = { stroke: '#ddd' };
const snapGrid = [16, 16];
const OverviewFlow = () => {
const [elements, setElements] = useState(initialElements);
const onElementsRemove = (elementsToRemove) =>
setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params) => setElements((els) => addEdge(params, els));
console.log('render overview');
return (
<ReactFlow
elements={elements}
onElementClick={onElementClick}
onElementsRemove={onElementsRemove}
onConnect={onConnect}
onNodeDragStart={onNodeDragStart}
onNodeDragStop={onNodeDragStop}
onSelectionDragStart={onSelectionDragStart}
onSelectionDrag={onSelectionDrag}
onSelectionDragStop={onSelectionDragStop}
onSelectionContextMenu={onSelectionContextMenu}
onSelectionChange={onSelectionChange}
onMoveEnd={onMoveEnd}
onLoad={onLoad}
connectionLineStyle={connectionLineStyle}
snapToGrid={true}
snapGrid={snapGrid}
key="overview"
>
<MiniMap
nodeColor={(n) => {
if (n.style?.background) return n.style.background;
if (n.type === 'input') return '#9999ff';
if (n.type === 'output') return '#79c9b7';
if (n.type === 'default') return '#ff6060';
return '#eee';
}}
/>
<Controls />
<Background color="#aaa" gap={16} />
</ReactFlow>
);
};
export default OverviewFlow;
@@ -0,0 +1,34 @@
import React from 'react';
import { useStoreState, useStoreActions } from 'react-flow-renderer';
export default () => {
const nodes = useStoreState((store) => store.nodes);
const transform = useStoreState((store) => store.transform);
const setSelectedElements = useStoreActions((actions) => actions.setSelectedElements);
const selectAll = () => {
setSelectedElements(nodes.map((node) => ({ id: node.id, type: node.type })));
};
return (
<aside>
<div className="description">
This is an example of how you can access the internal state outside of the ReactFlow component.
</div>
<div className="title">Zoom & pan transform</div>
<div className="transform">
[{transform[0].toFixed(2)}, {transform[1].toFixed(2)}, {transform[2].toFixed(2)}]
</div>
<div className="title">Nodes</div>
{nodes.map((node) => (
<div key={node.id}>
Node {node.id} - x: {node.__rf.position.x.toFixed(2)}, y: {node.__rf.position.y.toFixed(2)}
</div>
))}
<div className="selectall">
<button onClick={selectAll}>select all nodes</button>
</div>
</aside>
);
};
@@ -0,0 +1,62 @@
import React, { useState } from 'react';
import ReactFlow, {
ReactFlowProvider,
addEdge,
removeElements,
Controls,
} 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 initialElements = [
{
id: 'provider-1',
type: 'input',
data: { label: 'Node 1' },
position: { x: 250, y: 5 },
},
{ id: 'provider-2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
{ id: 'provider-3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
{ id: 'provider-4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
{
id: 'provider-e1-2',
source: 'provider-1',
target: 'provider-2',
animated: true,
},
{ id: 'provider-e1-3', source: 'provider-1', target: 'provider-3' },
];
const ProviderFlow = () => {
const [elements, setElements] = useState(initialElements);
const onConnect = (params) => setElements((els) => addEdge(params, els));
const onElementsRemove = (elementsToRemove) =>
setElements((els) => removeElements(elementsToRemove, els));
return (
<div className="providerflow">
<ReactFlowProvider>
<div className="reactflow-wrapper">
<ReactFlow
elements={elements}
onElementClick={onElementClick}
onConnect={onConnect}
onElementsRemove={onElementsRemove}
onLoad={onLoad}
>
<Controls />
</ReactFlow>
</div>
<Sidebar />
</ReactFlowProvider>
</div>
);
};
export default ProviderFlow;
@@ -0,0 +1,46 @@
.providerflow {
flex-direction: column;
display: flex;
height: 100%;
flex-grow: 1;
}
.providerflow aside {
border-left: 1px solid #eee;
padding: 15px 10px;
font-size: 12px;
background: #fff;
}
.providerflow aside .description {
margin-bottom: 10px;
}
.providerflow aside .title {
font-weight: 700;
margin-bottom: 5px;
}
.providerflow aside .transform {
margin-bottom: 20px;
}
.providerflow .reactflow-wrapper {
flex-grow: 1;
height: 100%;
}
.providerflow .selectall {
margin-top: 10px;
}
@media screen and (min-width: 768px) {
.providerflow {
flex-direction: row;
}
.providerflow aside {
width: 20%;
max-width: 250px;
}
}
+49
View File
@@ -0,0 +1,49 @@
import React, { useState } from 'react';
import ReactFlow, { removeElements, addEdge, MiniMap, isNode, Controls, Background } from 'react-flow-renderer';
import { getElements } from './utils';
const onLoad = (reactFlowInstance) => {
reactFlowInstance.fitView();
console.log(reactFlowInstance.getElements());
};
const initialElements = getElements(10, 10);
const StressFlow = () => {
const [elements, setElements] = useState(initialElements);
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
const onConnect = (params) => setElements((els) => addEdge(params, els));
const updatePos = () => {
setElements((elms) => {
return elms.map((el) => {
if (isNode(el)) {
return {
...el,
position: {
x: Math.random() * window.innerWidth,
y: Math.random() * window.innerHeight,
},
};
}
return el;
});
});
};
return (
<ReactFlow elements={elements} onLoad={onLoad} onElementsRemove={onElementsRemove} onConnect={onConnect}>
<MiniMap />
<Controls />
<Background />
<button onClick={updatePos} style={{ position: 'absolute', right: 10, top: 30, zIndex: 4 }}>
change pos
</button>
</ReactFlow>
);
};
export default StressFlow;
+32
View File
@@ -0,0 +1,32 @@
export function getElements(xElements = 10, yElements = 10) {
const initialElements = [];
let nodeId = 1;
let recentNodeId = null;
for (let y = 0; y < yElements; y++) {
for (let x = 0; x < xElements; x++) {
const position = { x: x * 100, y: y * 50 };
const data = { label: `Node ${nodeId}` };
const node = {
id: `stress-${nodeId.toString()}`,
style: { width: 50, fontSize: 11 },
data,
position,
};
initialElements.push(node);
if (recentNodeId && nodeId <= xElements * yElements) {
initialElements.push({
id: `${x}-${y}`,
source: `stress-${recentNodeId.toString()}`,
target: `stress-${nodeId.toString()}`,
});
}
recentNodeId = nodeId;
nodeId++;
}
}
return initialElements;
}
@@ -0,0 +1,62 @@
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;
@@ -0,0 +1,31 @@
.validationflow .react-flow__node {
width: 150px;
border-radius: 5px;
padding: 10px;
color: #555;
border: 1px solid #ddd;
text-align: center;
font-size: 12px;
}
.validationflow .react-flow__node-customnode {
background: #e6e6e9;
border: 1px solid #ddd;
}
.react-flow__node-custominput .react-flow__handle {
background: #e6e6e9;
}
.validationflow .react-flow__node-custominput {
background: #fff;
}
.validationflow .react-flow__handle-connecting {
background: #ff6060;
}
.validationflow .react-flow__handle-valid {
background: #55dd99;
}