chore(examples): add examples

This commit is contained in:
moklick
2021-12-22 23:53:05 +01:00
parent c1e5f90c7c
commit 7a85bb9666
13 changed files with 141 additions and 187 deletions
@@ -0,0 +1,36 @@
import ReactFlow, {
Node,
addEdge,
Background,
BackgroundVariant,
Connection,
Edge,
useNodesState,
useEdgesState,
} from 'react-flow-renderer';
import ConnectionLine from './ConnectionLine';
const initialNodes: Node[] = [{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } }];
const initialEdges: Edge[] = [];
const ConnectionLineFlow = () => {
const [nodes, , onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const onConnect = (params: Connection | Edge) => setEdges((eds) => addEdge(params, eds));
return (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
connectionLineComponent={ConnectionLine}
onConnect={onConnect}
>
<Background variant={BackgroundVariant.Lines} />
</ReactFlow>
);
};
export default ConnectionLineFlow;
+3 -3
View File
@@ -33,8 +33,7 @@ const onNodeClick = (_: MouseEvent, node: Node) => console.log('node click:', no
const onSelectionChange = ({ nodes, edges }: OnSelectionChangeParams) => console.log('selection change', nodes, edges); const onSelectionChange = ({ nodes, edges }: OnSelectionChangeParams) => console.log('selection change', nodes, edges);
const onPaneReady = (reactFlowInstance: ReactFlowInstance) => { const onPaneReady = (reactFlowInstance: ReactFlowInstance) => {
console.log('flow loaded:', reactFlowInstance); console.log('pane ready:', reactFlowInstance);
reactFlowInstance.fitView();
}; };
const onMoveStart = (transform?: FlowTransform) => console.log('zoom/move start', transform); const onMoveStart = (transform?: FlowTransform) => console.log('zoom/move start', transform);
@@ -158,7 +157,7 @@ const nodeColor = (n: Node): string => {
}; };
const OverviewFlow = () => { const OverviewFlow = () => {
const [nodes, setNodes, 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));
@@ -193,6 +192,7 @@ const OverviewFlow = () => {
onEdgeMouseMove={onEdgeMouseMove} onEdgeMouseMove={onEdgeMouseMove}
onEdgeMouseLeave={onEdgeMouseLeave} onEdgeMouseLeave={onEdgeMouseLeave}
onEdgeDoubleClick={onEdgeDoubleClick} onEdgeDoubleClick={onEdgeDoubleClick}
fitViewOnInit
> >
<MiniMap nodeStrokeColor={nodeStrokeColor} nodeColor={nodeColor} nodeBorderRadius={2} /> <MiniMap nodeStrokeColor={nodeStrokeColor} nodeColor={nodeColor} nodeBorderRadius={2} />
<Controls /> <Controls />
@@ -1,13 +1,13 @@
import React from 'react'; import { useStore, useStoreApi } from 'react-flow-renderer';
import { useStoreState, useStoreActions } from 'react-flow-renderer';
const Sidebar = () => { const Sidebar = () => {
const nodes = useStoreState((store) => store.nodes); const store = useStoreApi();
const transform = useStoreState((store) => store.transform); const nodeInternals = useStore((store) => store.nodeInternals);
const setSelectedElements = useStoreActions((actions) => actions.setSelectedElements); const transform = useStore((store) => store.transform);
const selectAll = () => { const selectAll = () => {
setSelectedElements(nodes.map((node) => ({ id: node.id, type: node.type }))); nodeInternals.forEach((node) => (node.selected = true));
store.setState({ nodeInternals: new Map(nodeInternals) });
}; };
return ( return (
@@ -20,9 +20,9 @@ const Sidebar = () => {
[{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>
{nodes.map((node) => ( {Array.from(nodeInternals).map(([, node]) => (
<div key={node.id}> <div key={node.id}>
Node {node.id} - x: {node.__rf.position.x.toFixed(2)}, y: {node.__rf.position.y.toFixed(2)} Node {node.id} - x: {node.position.x.toFixed(2)}, y: {node.position.y.toFixed(2)}
</div> </div>
))} ))}
@@ -1,37 +1,40 @@
import React, { useState, MouseEvent } from 'react'; import { MouseEvent } from 'react';
import ReactFlow, { import ReactFlow, {
ReactFlowProvider, ReactFlowProvider,
addEdge, addEdge,
removeElements, Node,
Controls, Controls,
OnLoadParams,
FlowElement,
Connection, Connection,
Edge, Edge,
Elements,
ConnectionMode, ConnectionMode,
useNodesState,
useEdgesState,
ReactFlowInstance,
} from 'react-flow-renderer'; } from 'react-flow-renderer';
import Sidebar from './Sidebar'; import Sidebar from './Sidebar';
import './provider.css'; import './provider.css';
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element); const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
const onLoad = (reactFlowInstance: OnLoadParams) => console.log('flow loaded:', reactFlowInstance); const onPaneReady = (reactFlowInstance: ReactFlowInstance) => console.log('pane ready:', reactFlowInstance);
const initialElements: Elements = [ 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 } },
];
const initialEdges: Edge[] = [
{ id: 'e1-2', source: '1', target: '2', animated: true }, { id: 'e1-2', source: '1', target: '2', animated: true },
{ id: 'e1-3', source: '1', target: '3' }, { id: 'e1-3', source: '1', target: '3' },
]; ];
const ProviderFlow = () => { const ProviderFlow = () => {
const [elements, setElements] = useState<Elements>(initialElements); const [nodes, , onNodesChange] = useNodesState(initialNodes);
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els)); const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els)); const onConnect = (params: Edge | Connection) => setEdges((els) => addEdge(params, els));
return ( return (
<div className="providerflow"> <div className="providerflow">
@@ -39,11 +42,13 @@ const ProviderFlow = () => {
<Sidebar /> <Sidebar />
<div className="reactflow-wrapper"> <div className="reactflow-wrapper">
<ReactFlow <ReactFlow
elements={elements} nodes={nodes}
onElementClick={onElementClick} edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onNodeClick={onNodeClick}
onConnect={onConnect} onConnect={onConnect}
onElementsRemove={onElementsRemove} onPaneReady={onPaneReady}
onLoad={onLoad}
connectionMode={ConnectionMode.Loose} connectionMode={ConnectionMode.Loose}
> >
<Controls /> <Controls />
@@ -1,66 +1,79 @@
import React, { useState, useCallback } from 'react'; import { useCallback } from 'react';
import ReactFlow, { import ReactFlow, {
NodeTypesType, NodeTypesType,
addEdge, addEdge,
useZoomPanHelper, useZoomPanHelper,
ReactFlowProvider, ReactFlowProvider,
Elements, Node,
Connection, Connection,
Edge, Edge,
ElementId,
ConnectionLineType, ConnectionLineType,
ConnectionMode, ConnectionMode,
updateEdge, updateEdge,
useNodesState,
useEdgesState,
} from 'react-flow-renderer'; } from 'react-flow-renderer';
import CustomNode from './CustomNode'; import CustomNode from './CustomNode';
const initialElements: Elements = [ const initialNodes: Node[] = [
{ {
id: '00', id: '00',
type: 'custom', type: 'custom',
position: { x: 300, y: 250 }, position: { x: 300, y: 250 },
data: null,
}, },
{ {
id: '01', id: '01',
type: 'custom', type: 'custom',
position: { x: 100, y: 50 }, position: { x: 100, y: 50 },
data: null,
}, },
{ {
id: '02', id: '02',
type: 'custom', type: 'custom',
position: { x: 500, y: 50 }, position: { x: 500, y: 50 },
data: null,
}, },
{ {
id: '03', id: '03',
type: 'custom', type: 'custom',
position: { x: 500, y: 500 }, position: { x: 500, y: 500 },
data: null,
}, },
{ {
id: '04', id: '04',
type: 'custom', type: 'custom',
position: { x: 100, y: 500 }, position: { x: 100, y: 500 },
data: null,
}, },
{ {
id: '10', id: '10',
type: 'custom', type: 'custom',
position: { x: 300, y: 5 }, position: { x: 300, y: 5 },
data: null,
}, },
{ {
id: '20', id: '20',
type: 'custom', type: 'custom',
position: { x: 600, y: 250 }, position: { x: 600, y: 250 },
data: null,
}, },
{ {
id: '30', id: '30',
type: 'custom', type: 'custom',
position: { x: 300, y: 600 }, position: { x: 300, y: 600 },
data: null,
}, },
{ {
id: '40', id: '40',
type: 'custom', type: 'custom',
position: { x: 5, y: 250 }, position: { x: 5, y: 250 },
data: null,
}, },
];
const initialEdges: Edge[] = [
{ {
id: 'e0-1a', id: 'e0-1a',
source: '00', source: '00',
@@ -164,22 +177,25 @@ const nodeTypes: NodeTypesType = {
}; };
let id = 4; let id = 4;
const getId = (): ElementId => `${id++}`; const getId = () => `${id++}`;
const UpdateNodeInternalsFlow = () => { const UpdateNodeInternalsFlow = () => {
const [elements, setElements] = useState<Elements>(initialElements); const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge({ ...params, type: 'default' }, els)); const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const onConnect = (params: Edge | Connection) => setEdges((els) => addEdge(params, els));
const { project } = useZoomPanHelper(); const { project } = useZoomPanHelper();
const onEdgeUpdate = (oldEdge: Edge, newConnection: Connection) => const onEdgeUpdate = (oldEdge: Edge, newConnection: Connection) =>
setElements((els) => updateEdge(oldEdge, newConnection, els)); setEdges((els) => updateEdge(oldEdge, newConnection, els));
const onPaneClick = useCallback( const onPaneClick = useCallback(
(evt) => (evt) =>
setElements((els) => setNodes((nds) =>
els.concat({ nds.concat({
id: getId(), id: getId(),
position: project({ x: evt.clientX, y: evt.clientY - 40 }), position: project({ x: evt.clientX, y: evt.clientY - 40 }),
type: 'custom', type: 'custom',
data: null,
}) })
), ),
[project] [project]
@@ -187,7 +203,10 @@ const UpdateNodeInternalsFlow = () => {
return ( return (
<ReactFlow <ReactFlow
elements={elements} nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
nodeTypes={nodeTypes} nodeTypes={nodeTypes}
onConnect={onConnect} onConnect={onConnect}
onPaneClick={onPaneClick} onPaneClick={onPaneClick}
@@ -1,42 +1,46 @@
import React, { useState, useCallback } from 'react'; import { useCallback } from 'react';
import ReactFlow, { import ReactFlow, {
removeElements, Node,
addEdge, addEdge,
Background, Background,
MiniMap, MiniMap,
useZoomPanHelper, useZoomPanHelper,
ReactFlowProvider, ReactFlowProvider,
Elements,
ElementId,
Connection, Connection,
Edge, Edge,
useNodesState,
useEdgesState,
} from 'react-flow-renderer'; } from 'react-flow-renderer';
const initialElements: Elements = [ 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', data: { label: 'Node 2' }, position: { x: 100, 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' }, { 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' }, { id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 }, className: 'light' },
];
const initialEdges: Edge[] = [
{ id: 'e1-2', source: '1', target: '2', animated: true }, { id: 'e1-2', source: '1', target: '2', animated: true },
{ id: 'e1-3', source: '1', target: '3' }, { id: 'e1-3', source: '1', target: '3' },
]; ];
let id = 5; let id = 5;
const getId = (): ElementId => `${id++}`;
const getId = () => `${id++}`;
const UseZoomPanHelperFlow = () => { const UseZoomPanHelperFlow = () => {
const [elements, setElements] = useState<Elements>(initialElements); const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els)); const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els)); const onConnect = (params: Connection | Edge) => setEdges((eds) => addEdge(params, eds));
const { project, setCenter, zoomIn, zoomOut } = useZoomPanHelper(); const { project, setCenter, zoomIn, zoomOut } = useZoomPanHelper();
const onPaneClick = useCallback( const onPaneClick = useCallback(
(evt) => { (evt) => {
const projectedPosition = project({ x: evt.clientX, y: evt.clientY - 40 }); const projectedPosition = project({ x: evt.clientX, y: evt.clientY - 40 });
setElements((els) => setNodes((nds) =>
els.concat({ nds.concat({
id: getId(), id: getId(),
position: projectedPosition, position: projectedPosition,
data: { data: {
@@ -48,25 +52,27 @@ const UseZoomPanHelperFlow = () => {
[project] [project]
); );
const onElementClick = useCallback( const onNodeClick = useCallback(
(_, element) => { (_, element) => {
const { x, y } = element.position; const { x, y } = element.position;
setCenter(x, y, 1); setCenter(x, y, { zoom: 1 });
}, },
[setCenter] [setCenter]
); );
return ( return (
<ReactFlow <ReactFlow
elements={elements} nodes={nodes}
onElementClick={onElementClick} edges={edges}
onElementsRemove={onElementsRemove} onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onNodeClick={onNodeClick}
onConnect={onConnect} onConnect={onConnect}
onPaneClick={onPaneClick} onPaneClick={onPaneClick}
> >
<div style={{ position: 'absolute', left: 0, top: 0, zIndex: 100 }}> <div style={{ position: 'absolute', left: 0, top: 0, zIndex: 100 }}>
<button onClick={() => zoomIn(1200)}>zoomIn</button> <button onClick={() => zoomIn({ duration: 1200 })}>zoomIn</button>
<button onClick={() => zoomOut(0)}>zoomOut</button> <button onClick={() => zoomOut({ duration: 0 })}>zoomOut</button>
</div> </div>
<Background /> <Background />
<MiniMap /> <MiniMap />
+20
View File
@@ -17,6 +17,10 @@ import Subflow from './Subflow';
import Interaction from './Interaction'; import Interaction from './Interaction';
import Empty from './Empty'; import Empty from './Empty';
import DragHandle from './DragHandle'; import DragHandle from './DragHandle';
import Undirectional from './Undirectional';
import Provider from './Provider';
import CustomConnectionLine from './CustomConnectionLine';
import UseZoomPanHelper from './UseZoomPanHelper';
import './index.css'; import './index.css';
@@ -81,6 +85,22 @@ const routes = [
path: '/draghandle', path: '/draghandle',
component: DragHandle, component: DragHandle,
}, },
{
path: '/undirectional',
component: Undirectional,
},
{
path: '/provider',
component: Provider,
},
{
path: '/custom-connectionline',
component: CustomConnectionLine,
},
{
path: '/usezoompanhelper',
component: UseZoomPanHelper,
},
]; ];
const Header = withRouter(({ history, location }) => { const Header = withRouter(({ history, location }) => {
@@ -1,33 +0,0 @@
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;
-78
View File
@@ -1,78 +0,0 @@
import React, { useEffect, useState } from 'react';
import ReactFlow, { Elements } from 'react-flow-renderer';
import './updatenode.css';
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<Elements>(initialElements);
const [nodeName, setNodeName] = useState<string>('Node 1');
const [nodeBg, setNodeBg] = useState<string>('#eee');
const [nodeHidden, setNodeHidden] = useState<boolean>(false);
useEffect(() => {
setElements((els) =>
els.map((el) => {
if (el.id === '1') {
// it's important that you create a new object here in order to notify react flow about the change
el.data = {
...el.data,
label: nodeName,
};
}
return el;
})
);
}, [nodeName, setElements]);
useEffect(() => {
setElements((els) =>
els.map((el) => {
if (el.id === '1') {
// it's important that you create a new object here in order to notify react flow about the change
el.style = { ...el.style, backgroundColor: nodeBg };
}
return el;
})
);
}, [nodeBg, setElements]);
useEffect(() => {
setElements((els) =>
els.map((el) => {
if (el.id === '1' || el.id === 'e1-2') {
// when you update a simple type you can just update the value
el.isHidden = nodeHidden;
}
return el;
})
);
}, [nodeHidden, setElements]);
return (
<ReactFlow elements={elements} defaultZoom={1.5} minZoom={0.2} maxZoom={4}>
<div className="updatenode__controls">
<label>label:</label>
<input value={nodeName} onChange={(evt) => setNodeName(evt.target.value)} />
<label className="updatenode__bglabel">background:</label>
<input value={nodeBg} onChange={(evt) => setNodeBg(evt.target.value)} />
<div className="updatenode__checkboxwrapper">
<label>hidden:</label>
<input type="checkbox" checked={nodeHidden} onChange={(evt) => setNodeHidden(evt.target.checked)} />
</div>
</div>
</ReactFlow>
);
};
export default UpdateNode;
@@ -1,21 +0,0 @@
.updatenode__controls {
position: absolute;
right: 10px;
top: 10px;
z-index: 4;
font-size: 12px;
}
.updatenode__controls label {
display: block;
}
.updatenode__bglabel {
margin-top: 10px;
}
.updatenode__checkboxwrapper {
margin-top: 10px;
display: flex;
align-items: center;
}