refactor(examples): use cra + ts
This commit is contained in:
@@ -0,0 +1,23 @@
|
|||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.js
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# Getting Started with Create React App
|
||||||
|
|
||||||
|
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
||||||
|
|
||||||
|
## Available Scripts
|
||||||
|
|
||||||
|
In the project directory, you can run:
|
||||||
|
|
||||||
|
### `npm start`
|
||||||
|
|
||||||
|
Runs the app in the development mode.\
|
||||||
|
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
|
||||||
|
|
||||||
|
The page will reload if you make edits.\
|
||||||
|
You will also see any lint errors in the console.
|
||||||
|
|
||||||
|
### `npm test`
|
||||||
|
|
||||||
|
Launches the test runner in the interactive watch mode.\
|
||||||
|
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
||||||
|
|
||||||
|
### `npm run build`
|
||||||
|
|
||||||
|
Builds the app for production to the `build` folder.\
|
||||||
|
It correctly bundles React in production mode and optimizes the build for the best performance.
|
||||||
|
|
||||||
|
The build is minified and the filenames include the hashes.\
|
||||||
|
Your app is ready to be deployed!
|
||||||
|
|
||||||
|
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
|
||||||
|
|
||||||
|
### `npm run eject`
|
||||||
|
|
||||||
|
**Note: this is a one-way operation. Once you `eject`, you can’t go back!**
|
||||||
|
|
||||||
|
If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
|
||||||
|
|
||||||
|
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
|
||||||
|
|
||||||
|
You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
|
||||||
|
|
||||||
|
## Learn More
|
||||||
|
|
||||||
|
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
|
||||||
|
|
||||||
|
To learn React, check out the [React documentation](https://reactjs.org/).
|
||||||
Generated
+16608
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"name": "react-flow-examples",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"dagre": "^0.8.5",
|
||||||
|
"localforage": "^1.9.0",
|
||||||
|
"react": "file:../node_modules/react",
|
||||||
|
"react-dom": "file:../node_modules/react-dom",
|
||||||
|
"react-flow-renderer": "file:../",
|
||||||
|
"react-router-dom": "^5.2.0",
|
||||||
|
"react-scripts": "4.0.3",
|
||||||
|
"typescript": "^4.1.5"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "react-scripts start",
|
||||||
|
"build": "react-scripts build"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"extends": [
|
||||||
|
"react-app"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"browserslist": {
|
||||||
|
"production": [
|
||||||
|
">0.2%",
|
||||||
|
"not dead",
|
||||||
|
"not op_mini all"
|
||||||
|
],
|
||||||
|
"development": [
|
||||||
|
"last 1 chrome version",
|
||||||
|
"last 1 firefox version",
|
||||||
|
"last 1 safari version"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react-router-dom": "^5.1.7",
|
||||||
|
"@types/dagre": "^0.7.44",
|
||||||
|
"@types/localforage": "0.0.34",
|
||||||
|
"@types/react": "^17.0.2",
|
||||||
|
"@types/react-dom": "^17.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
/* /index.html 200
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -2,13 +2,11 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="description" content="React Flow test flows" />
|
|
||||||
<title>React Flow - Test Flows</title>
|
<title>React Flow Examples</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|
||||||
<script src="/dist/index.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
|
# https://www.robotstxt.org/robotstxt.html
|
||||||
User-agent: *
|
User-agent: *
|
||||||
|
Disallow:
|
||||||
|
|||||||
@@ -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 onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
||||||
const onElementClick = (event, element) => console.log('click', element);
|
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: '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' },
|
||||||
@@ -15,11 +27,11 @@ const initialElements = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const BasicFlow = () => {
|
const BasicFlow = () => {
|
||||||
const [rfInstance, setRfInstance] = useState(null);
|
const [rfInstance, setRfInstance] = useState<OnLoadParams | null>(null);
|
||||||
const [elements, setElements] = useState(initialElements);
|
const [elements, setElements] = useState<Elements>(initialElements);
|
||||||
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
|
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
|
||||||
const onConnect = (params) => setElements((els) => addEdge(params, els));
|
const onConnect = (params: Edge | Connection) => setElements((els) => addEdge(params, els));
|
||||||
const onLoad = (reactFlowInstance) => setRfInstance(reactFlowInstance);
|
const onLoad = (reactFlowInstance: OnLoadParams) => setRfInstance(reactFlowInstance);
|
||||||
|
|
||||||
const updatePos = () => {
|
const updatePos = () => {
|
||||||
setElements((elms) => {
|
setElements((elms) => {
|
||||||
@@ -36,8 +48,8 @@ const BasicFlow = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const logToObject = () => console.log(rfInstance.toObject());
|
const logToObject = () => console.log(rfInstance?.toObject());
|
||||||
const resetTransform = () => rfInstance.setTransform({ x: 0, y: 0, zoom: 1 });
|
const resetTransform = () => rfInstance?.setTransform({ x: 0, y: 0, zoom: 1 });
|
||||||
|
|
||||||
const toggleClassnames = () => {
|
const toggleClassnames = () => {
|
||||||
setElements((elms) => {
|
setElements((elms) => {
|
||||||
@@ -64,7 +76,7 @@ const BasicFlow = () => {
|
|||||||
minZoom={0.2}
|
minZoom={0.2}
|
||||||
maxZoom={4}
|
maxZoom={4}
|
||||||
>
|
>
|
||||||
<Background variant="lines" />
|
<Background variant={BackgroundVariant.Lines} />
|
||||||
|
|
||||||
<div style={{ position: 'absolute', right: 10, top: 10, zIndex: 4 }}>
|
<div style={{ position: 'absolute', right: 10, top: 10, zIndex: 4 }}>
|
||||||
<button onClick={resetTransform} style={{ marginRight: 5 }}>
|
<button onClick={resetTransform} style={{ marginRight: 5 }}>
|
||||||
+5
-11
@@ -1,15 +1,7 @@
|
|||||||
import React from 'react';
|
import React, { FC } from 'react';
|
||||||
|
import { ConnectionLineComponentProps } from 'react-flow-renderer';
|
||||||
|
|
||||||
export default ({
|
const ConnectionLine: FC<ConnectionLineComponentProps> = ({ sourceX, sourceY, targetX, targetY }) => {
|
||||||
sourceX,
|
|
||||||
sourceY,
|
|
||||||
sourcePosition,
|
|
||||||
targetX,
|
|
||||||
targetY,
|
|
||||||
targetPosition,
|
|
||||||
connectionLineType,
|
|
||||||
connectionLineStyle,
|
|
||||||
}) => {
|
|
||||||
return (
|
return (
|
||||||
<g>
|
<g>
|
||||||
<path
|
<path
|
||||||
@@ -23,3 +15,5 @@ export default ({
|
|||||||
</g>
|
</g>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default ConnectionLine;
|
||||||
@@ -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';
|
import ColorSelectorNode from './ColorSelectorNode';
|
||||||
|
|
||||||
const onLoad = (reactFlowInstance) => console.log('flow loaded:', reactFlowInstance);
|
const onLoad = (reactFlowInstance: OnLoadParams) => console.log('flow loaded:', reactFlowInstance);
|
||||||
const onNodeDragStop = (event, node) => console.log('drag stop', node);
|
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
||||||
const onElementClick = (event, element) => console.log('click', element);
|
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element);
|
||||||
|
|
||||||
const initBgColor = '#1A192B';
|
const initBgColor = '#1A192B';
|
||||||
|
|
||||||
const connectionLineStyle = { stroke: '#fff' };
|
const connectionLineStyle = { stroke: '#fff' };
|
||||||
const snapGrid = [16, 16];
|
const snapGrid: SnapGrid = [16, 16];
|
||||||
const nodeTypes = {
|
const nodeTypes = {
|
||||||
selectorNode: ColorSelectorNode,
|
selectorNode: ColorSelectorNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
const CustomNodeFlow = () => {
|
const CustomNodeFlow = () => {
|
||||||
const [elements, setElements] = useState([]);
|
const [elements, setElements] = useState<Elements>([]);
|
||||||
const [bgColor, setBgColor] = useState(initBgColor);
|
const [bgColor, setBgColor] = useState<string>(initBgColor);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const onChange = (event) => {
|
const onChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
setElements((els) =>
|
setElements((els) =>
|
||||||
els.map((e) => {
|
els.map((e) => {
|
||||||
if (isEdge(e) || e.id !== '2') {
|
if (isEdge(e) || e.id !== '2') {
|
||||||
@@ -44,7 +59,13 @@ const CustomNodeFlow = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
setElements([
|
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',
|
id: '2',
|
||||||
type: 'selectorNode',
|
type: 'selectorNode',
|
||||||
@@ -52,8 +73,20 @@ const CustomNodeFlow = () => {
|
|||||||
style: { border: '1px solid #777', padding: 10 },
|
style: { border: '1px solid #777', padding: 10 },
|
||||||
position: { x: 250, y: 50 },
|
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: 'e1-2', source: '1', target: '2', animated: true, style: { stroke: '#fff' } },
|
||||||
{ id: 'e2a-3', source: '2', sourceHandle: 'a', target: '3', animated: true, style: { stroke: '#fff' } },
|
{ id: '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 onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
|
||||||
const onConnect = (params) =>
|
const onConnect = (params: Connection | Edge) =>
|
||||||
setElements((els) => addEdge({ ...params, animated: true, style: { stroke: '#fff' } }, els));
|
setElements((els) => addEdge({ ...params, animated: true, style: { stroke: '#fff' } }, els));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -81,13 +114,16 @@ const CustomNodeFlow = () => {
|
|||||||
defaultZoom={1.5}
|
defaultZoom={1.5}
|
||||||
>
|
>
|
||||||
<MiniMap
|
<MiniMap
|
||||||
nodeStrokeColor={(n) => {
|
nodeStrokeColor={(n: Node): string => {
|
||||||
if (n.type === 'input') return '#0041d0';
|
if (n.type === 'input') return '#0041d0';
|
||||||
if (n.type === 'selectorNode') return bgColor;
|
if (n.type === 'selectorNode') return bgColor;
|
||||||
if (n.type === 'output') return '#ff0072';
|
if (n.type === 'output') return '#ff0072';
|
||||||
|
|
||||||
|
return '#eee';
|
||||||
}}
|
}}
|
||||||
nodeColor={(n) => {
|
nodeColor={(n: Node): string => {
|
||||||
if (n.type === 'selectorNode') return bgColor;
|
if (n.type === 'selectorNode') return bgColor;
|
||||||
|
|
||||||
return '#fff';
|
return '#fff';
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -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>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -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;
|
||||||
@@ -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;
|
|
||||||
@@ -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 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';
|
import { getElements } from './utils';
|
||||||
|
|
||||||
const onLoad = (reactFlowInstance) => {
|
const onLoad = (reactFlowInstance: OnLoadParams) => {
|
||||||
reactFlowInstance.fitView();
|
reactFlowInstance.fitView();
|
||||||
console.log(reactFlowInstance.getElements());
|
console.log(reactFlowInstance.getElements());
|
||||||
};
|
};
|
||||||
@@ -14,9 +24,9 @@ const onLoad = (reactFlowInstance) => {
|
|||||||
const initialElements = getElements();
|
const initialElements = getElements();
|
||||||
|
|
||||||
const EdgeTypesFlow = () => {
|
const EdgeTypesFlow = () => {
|
||||||
const [elements, setElements] = useState(initialElements);
|
const [elements, setElements] = useState<Elements>(initialElements);
|
||||||
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
|
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
|
||||||
const onConnect = (params) => setElements((els) => addEdge(params, els));
|
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
|
import { ElementId, Elements, Position } from 'react-flow-renderer';
|
||||||
|
|
||||||
const nodeWidth = 80;
|
const nodeWidth = 80;
|
||||||
const nodeGapWidth = nodeWidth * 2;
|
const nodeGapWidth = nodeWidth * 2;
|
||||||
const nodeStyle = { width: nodeWidth, fontSize: 11, color: 'white' };
|
const nodeStyle = { width: nodeWidth, fontSize: 11, color: 'white' };
|
||||||
|
|
||||||
const sourceTargetPositions = [
|
const sourceTargetPositions = [
|
||||||
{ source: 'bottom', target: 'top' },
|
{ source: Position.Bottom, target: Position.Top },
|
||||||
{ source: 'right', target: 'left' },
|
{ source: Position.Right, target: Position.Left },
|
||||||
];
|
];
|
||||||
const nodeColors = [
|
const nodeColors = [
|
||||||
['#1e9e99', '#4cb3ac', '#6ec9c0', '#8ddfd4'],
|
['#1e9e99', '#4cb3ac', '#6ec9c0', '#8ddfd4'],
|
||||||
@@ -47,9 +49,9 @@ const offsets = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
let id = 0;
|
let id = 0;
|
||||||
const getNodeId = () => (id++).toString();
|
const getNodeId = (): ElementId => (id++).toString();
|
||||||
|
|
||||||
export function getElements() {
|
export function getElements(): Elements {
|
||||||
const initialElements = [];
|
const initialElements = [];
|
||||||
|
|
||||||
for (let sourceTargetIndex = 0; sourceTargetIndex < sourceTargetPositions.length; sourceTargetIndex++) {
|
for (let sourceTargetIndex = 0; sourceTargetIndex < sourceTargetPositions.length; sourceTargetIndex++) {
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React, { FC } from 'react';
|
||||||
import { getBezierPath, getMarkerEnd } from 'react-flow-renderer';
|
import { EdgeProps, getBezierPath, getMarkerEnd } from 'react-flow-renderer';
|
||||||
|
|
||||||
export default function CustomEdge({
|
const CustomEdge: FC<EdgeProps> = ({
|
||||||
id,
|
id,
|
||||||
sourceX,
|
sourceX,
|
||||||
sourceY,
|
sourceY,
|
||||||
@@ -13,7 +13,7 @@ export default function CustomEdge({
|
|||||||
data,
|
data,
|
||||||
arrowHeadType,
|
arrowHeadType,
|
||||||
markerEndId,
|
markerEndId,
|
||||||
}) {
|
}) => {
|
||||||
const edgePath = getBezierPath({ sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition });
|
const edgePath = getBezierPath({ sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition });
|
||||||
const markerEnd = getMarkerEnd(arrowHeadType, markerEndId);
|
const markerEnd = getMarkerEnd(arrowHeadType, markerEndId);
|
||||||
|
|
||||||
@@ -27,4 +27,6 @@ export default function CustomEdge({
|
|||||||
</text>
|
</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';
|
import CustomEdge from './CustomEdge';
|
||||||
|
|
||||||
const onLoad = (reactFlowInstance) => reactFlowInstance.fitView();
|
const onLoad = (reactFlowInstance: OnLoadParams) => reactFlowInstance.fitView();
|
||||||
const onNodeDragStop = (event, node) => console.log('drag stop', node);
|
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
||||||
const onElementClick = (event, element) => console.log('click', element);
|
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: '1', type: 'input', data: { label: 'Input 1' }, position: { x: 250, y: 0 } },
|
||||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 150, y: 100 } },
|
{ id: '2', data: { label: 'Node 2' }, position: { x: 150, y: 100 } },
|
||||||
{ id: '2a', data: { label: 'Node 2a' }, position: { x: 0, y: 180 } },
|
{ id: '2a', data: { label: 'Node 2a' }, position: { x: 0, y: 180 } },
|
||||||
@@ -31,7 +45,7 @@ const initialElements = [
|
|||||||
target: '6',
|
target: '6',
|
||||||
label: 'styled label',
|
label: 'styled label',
|
||||||
labelStyle: { fill: 'red', fontWeight: 700 },
|
labelStyle: { fill: 'red', fontWeight: 700 },
|
||||||
arrowHeadType: 'arrow',
|
arrowHeadType: ArrowHeadType.Arrow,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'e5-7',
|
id: 'e5-7',
|
||||||
@@ -41,20 +55,27 @@ const initialElements = [
|
|||||||
labelBgPadding: [8, 4],
|
labelBgPadding: [8, 4],
|
||||||
labelBgBorderRadius: 4,
|
labelBgBorderRadius: 4,
|
||||||
labelBgStyle: { fill: '#FFCC00', color: '#fff', fillOpacity: 0.7 },
|
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,
|
custom: CustomEdge,
|
||||||
};
|
};
|
||||||
|
|
||||||
const EdgesFlow = () => {
|
const EdgesFlow = () => {
|
||||||
const [elements, setElements] = useState(initialElements);
|
const [elements, setElements] = useState<Elements>(initialElements);
|
||||||
|
|
||||||
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
|
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
|
||||||
const onConnect = (params) => setElements((els) => addEdge(params, els));
|
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
@@ -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;
|
|
||||||
@@ -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 React, { useState } from 'react';
|
||||||
|
|
||||||
import ReactFlow, { addEdge, MiniMap, Controls } from 'react-flow-renderer';
|
|
||||||
import { useEffect } from 'react';
|
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: '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 } },
|
||||||
@@ -14,9 +14,9 @@ const initialElements = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const HiddenFlow = () => {
|
const HiddenFlow = () => {
|
||||||
const [elements, setElements] = useState(initialElements);
|
const [elements, setElements] = useState<Elements>(initialElements);
|
||||||
const [isHidden, setIsHidden] = useState(false);
|
const [isHidden, setIsHidden] = useState<boolean>(false);
|
||||||
const onConnect = (params) => setElements((els) => addEdge(params, els));
|
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setElements((els) =>
|
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: Elements = [
|
||||||
|
|
||||||
const initialElements = [
|
|
||||||
{ 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 } },
|
||||||
@@ -11,30 +21,30 @@ const initialElements = [
|
|||||||
{ id: 'e1-3', source: '1', target: '3' },
|
{ id: 'e1-3', source: '1', target: '3' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const onNodeDragStart = (event, node) => console.log('drag start', node);
|
const onNodeDragStart = (_: MouseEvent, node: Node) => console.log('drag start', node);
|
||||||
const onNodeDragStop = (event, node) => console.log('drag stop', node);
|
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
||||||
const onElementClick = (event, element) => console.log('click', element);
|
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element);
|
||||||
const onPaneClick = (event) => console.log('onPaneClick', event);
|
const onPaneClick = (event: MouseEvent) => console.log('onPaneClick', event);
|
||||||
const onPaneScroll = (event) => console.log('onPaneScroll', event);
|
const onPaneScroll = (event?: WheelEvent) => console.log('onPaneScroll', event);
|
||||||
const onPaneContextMenu = (event) => console.log('onPaneContextMenu', event);
|
const onPaneContextMenu = (event: MouseEvent) => console.log('onPaneContextMenu', event);
|
||||||
const onMoveEnd = (event) => console.log('onMoveEnd', event);
|
const onMoveEnd = (flowTranasform?: FlowTransform) => console.log('onMoveEnd', flowTranasform);
|
||||||
|
|
||||||
const InteractionFlow = () => {
|
const InteractionFlow = () => {
|
||||||
const [elements, setElements] = useState(initialElements);
|
const [elements, setElements] = useState<Elements>(initialElements);
|
||||||
const onConnect = (params) => setElements((els) => addEdge(params, els));
|
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
|
||||||
|
|
||||||
const [isSelectable, setIsSelectable] = useState(false);
|
const [isSelectable, setIsSelectable] = useState<boolean>(false);
|
||||||
const [isDraggable, setIsDraggable] = useState(false);
|
const [isDraggable, setIsDraggable] = useState<boolean>(false);
|
||||||
const [isConnectable, setIsConnectable] = useState(false);
|
const [isConnectable, setIsConnectable] = useState<boolean>(false);
|
||||||
const [zoomOnScroll, setZoomOnScroll] = useState(false);
|
const [zoomOnScroll, setZoomOnScroll] = useState<boolean>(false);
|
||||||
const [zoomOnPinch, setZoomOnPinch] = useState(false);
|
const [zoomOnPinch, setZoomOnPinch] = useState<boolean>(false);
|
||||||
const [panOnScroll, setPanOnScroll] = useState(false);
|
const [panOnScroll, setPanOnScroll] = useState<boolean>(false);
|
||||||
const [panOnScrollMode, setPanOnScrollMode] = useState('free');
|
const [panOnScrollMode, setPanOnScrollMode] = useState<PanOnScrollMode>(PanOnScrollMode.Free);
|
||||||
const [zoomOnDoubleClick, setZoomOnDoubleClick] = useState(false);
|
const [zoomOnDoubleClick, setZoomOnDoubleClick] = useState<boolean>(false);
|
||||||
const [paneMoveable, setPaneMoveable] = useState(true);
|
const [paneMoveable, setPaneMoveable] = useState<boolean>(true);
|
||||||
const [captureZoomClick, setCaptureZoomClick] = useState(false);
|
const [captureZoomClick, setCaptureZoomClick] = useState<boolean>(false);
|
||||||
const [captureZoomScroll, setCaptureZoomScroll] = useState(false);
|
const [captureZoomScroll, setCaptureZoomScroll] = useState<boolean>(false);
|
||||||
const [captureElementClick, setCaptureElementClick] = useState(false);
|
const [captureElementClick, setCaptureElementClick] = useState<boolean>(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
@@ -139,7 +149,7 @@ const InteractionFlow = () => {
|
|||||||
<select
|
<select
|
||||||
id="panonscrollmode"
|
id="panonscrollmode"
|
||||||
value={panOnScrollMode}
|
value={panOnScrollMode}
|
||||||
onChange={(event) => setPanOnScrollMode(event.target.value)}
|
onChange={(event) => setPanOnScrollMode(event.target.value as PanOnScrollMode)}
|
||||||
className="react-flow__panonscrollmode"
|
className="react-flow__panonscrollmode"
|
||||||
>
|
>
|
||||||
<option value="free">free</option>
|
<option value="free">free</option>
|
||||||
@@ -1,5 +1,16 @@
|
|||||||
import React, { useState } from 'react';
|
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 dagre from 'dagre';
|
||||||
|
|
||||||
import initialElements from './initial-elements';
|
import initialElements from './initial-elements';
|
||||||
@@ -9,17 +20,17 @@ import './layouting.css';
|
|||||||
const dagreGraph = new dagre.graphlib.Graph();
|
const dagreGraph = new dagre.graphlib.Graph();
|
||||||
dagreGraph.setDefaultEdgeLabel(() => ({}));
|
dagreGraph.setDefaultEdgeLabel(() => ({}));
|
||||||
|
|
||||||
const nodeExtent = [
|
const nodeExtent: NodeExtent = [
|
||||||
[0, 0],
|
[0, 0],
|
||||||
[1000, 1000],
|
[1000, 1000],
|
||||||
];
|
];
|
||||||
|
|
||||||
const LayoutFlow = () => {
|
const LayoutFlow = () => {
|
||||||
const [elements, setElements] = useState(initialElements);
|
const [elements, setElements] = useState<Elements>(initialElements);
|
||||||
const onConnect = (params) => setElements((els) => addEdge(params, els));
|
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
|
||||||
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
|
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
|
||||||
|
|
||||||
const onLayout = (direction) => {
|
const onLayout = (direction: string) => {
|
||||||
const isHorizontal = direction === 'LR';
|
const isHorizontal = direction === 'LR';
|
||||||
dagreGraph.setGraph({ rankdir: direction });
|
dagreGraph.setGraph({ rankdir: direction });
|
||||||
|
|
||||||
@@ -36,8 +47,8 @@ const LayoutFlow = () => {
|
|||||||
const layoutedElements = elements.map((el) => {
|
const layoutedElements = elements.map((el) => {
|
||||||
if (isNode(el)) {
|
if (isNode(el)) {
|
||||||
const nodeWithPosition = dagreGraph.node(el.id);
|
const nodeWithPosition = dagreGraph.node(el.id);
|
||||||
el.targetPosition = isHorizontal ? 'left' : 'top';
|
el.targetPosition = isHorizontal ? Position.Left : Position.Top;
|
||||||
el.sourcePosition = isHorizontal ? 'right' : 'bottom';
|
el.sourcePosition = isHorizontal ? Position.Right : Position.Bottom;
|
||||||
// we need to pass a slighltiy different position in order to notify react flow about the change
|
// 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?
|
// @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 };
|
el.position = { x: nodeWithPosition.x + Math.random() / 1000, y: nodeWithPosition.y };
|
||||||
+6
-2
@@ -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',
|
id: '1',
|
||||||
type: 'input',
|
type: 'input',
|
||||||
@@ -65,3 +67,5 @@ export default [
|
|||||||
{ id: 'e56', source: '5', target: '6', type: 'smoothstep' },
|
{ id: 'e56', source: '5', target: '6', type: 'smoothstep' },
|
||||||
{ id: 'e57', source: '5', target: '7', 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',
|
id: '1',
|
||||||
sourcePosition: 'right',
|
sourcePosition: Position.Right,
|
||||||
type: 'input',
|
type: 'input',
|
||||||
data: { label: 'Input' },
|
data: { label: 'Input' },
|
||||||
position: { x: 0, y: 80 },
|
position: { x: 0, y: 80 },
|
||||||
@@ -15,17 +15,19 @@ const initialElements = [
|
|||||||
{
|
{
|
||||||
id: '2',
|
id: '2',
|
||||||
type: 'output',
|
type: 'output',
|
||||||
sourcePosition: 'right',
|
sourcePosition: Position.Right,
|
||||||
targetPosition: 'left',
|
targetPosition: Position.Left,
|
||||||
data: { label: 'A Node' },
|
data: { label: 'A Node' },
|
||||||
position: { x: 250, y: 0 },
|
position: { x: 250, y: 0 },
|
||||||
},
|
},
|
||||||
{ id: 'e1-2', source: '1', type: 'smoothstep', target: '2', animated: true },
|
{ 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 NodeTypeChangeFlow = () => {
|
||||||
const [elements, setElements] = useState(initialElements);
|
const [elements, setElements] = useState<Elements>(initialElements);
|
||||||
const onConnect = (params) => setElements((els) => addEdge(params, els));
|
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
|
||||||
const changeType = () => {
|
const changeType = () => {
|
||||||
setElements((elms) =>
|
setElements((elms) =>
|
||||||
elms.map((el) => {
|
elms.map((el) => {
|
||||||
@@ -43,7 +45,7 @@ const NodeTypeChangeFlow = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow elements={elements} onConnect={onConnect} onLoad={onLoad}>
|
<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
|
change type
|
||||||
</button>
|
</button>
|
||||||
</ReactFlow>
|
</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 onNodeDragStart = (_: MouseEvent, node: Node) => console.log('drag start', node);
|
||||||
const onNodeDrag = (event, node) => console.log('drag', node);
|
const onNodeDrag = (_: MouseEvent, node: Node) => console.log('drag', node);
|
||||||
const onNodeDragStop = (event, node) => console.log('drag stop', node);
|
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
||||||
const onPaneClick = (event) => console.log('pane click', event);
|
const onPaneClick = (event: MouseEvent) => console.log('pane click', event);
|
||||||
const onPaneScroll = (event) => console.log('pane scroll', event);
|
const onPaneScroll = (event?: MouseEvent) => console.log('pane scroll', event);
|
||||||
const onPaneContextMenu = (event) => console.log('pane context menu', event);
|
const onPaneContextMenu = (event: MouseEvent) => console.log('pane context menu', event);
|
||||||
const onSelectionDrag = (event, nodes) => console.log('selection drag', nodes);
|
const onSelectionDrag = (_: MouseEvent, nodes: Node[]) => console.log('selection drag', nodes);
|
||||||
const onSelectionDragStart = (event, nodes) => console.log('selection drag start', nodes);
|
const onSelectionDragStart = (_: MouseEvent, nodes: Node[]) => console.log('selection drag start', nodes);
|
||||||
const onSelectionDragStop = (event, nodes) => console.log('selection drag stop', nodes);
|
const onSelectionDragStop = (_: MouseEvent, nodes: Node[]) => console.log('selection drag stop', nodes);
|
||||||
const onSelectionContextMenu = (event, nodes) => {
|
const onSelectionContextMenu = (event: MouseEvent, nodes: Node[]) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
console.log('selection context menu', nodes);
|
console.log('selection context menu', nodes);
|
||||||
};
|
};
|
||||||
const onElementClick = (event, element) => console.log(`${isNode(element) ? 'node' : 'edge'} click:`, element);
|
const onElementClick = (_: MouseEvent, element: FlowElement) =>
|
||||||
const onSelectionChange = (elements) => console.log('selection change', elements);
|
console.log(`${isNode(element) ? 'node' : 'edge'} click:`, element);
|
||||||
const onLoad = (reactFlowInstance) => {
|
const onSelectionChange = (elements: Elements | null) => console.log('selection change', elements);
|
||||||
|
const onLoad = (reactFlowInstance: OnLoadParams) => {
|
||||||
console.log('flow loaded:', reactFlowInstance);
|
console.log('flow loaded:', reactFlowInstance);
|
||||||
reactFlowInstance.fitView();
|
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',
|
id: '1',
|
||||||
type: 'input',
|
type: 'input',
|
||||||
@@ -101,7 +118,7 @@ const initialElements = [
|
|||||||
{ id: 'e1-2', source: '1', target: '2', label: 'this is an edge label' },
|
{ id: 'e1-2', source: '1', target: '2', label: 'this is an edge label' },
|
||||||
{ id: 'e1-3', source: '1', target: '3' },
|
{ id: 'e1-3', source: '1', target: '3' },
|
||||||
{ id: 'e3-4', source: '3', target: '4', animated: true, label: 'animated edge' },
|
{ id: 'e3-4', source: '3', target: '4', animated: true, label: 'animated edge' },
|
||||||
{ id: 'e4-5', source: '4', target: '5', 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-6', source: '5', target: '6', type: 'smoothstep', label: 'smooth step edge' },
|
||||||
{
|
{
|
||||||
id: 'e5-7',
|
id: 'e5-7',
|
||||||
@@ -115,13 +132,28 @@ const initialElements = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const connectionLineStyle = { stroke: '#ddd' };
|
const connectionLineStyle: CSSProperties = { stroke: '#ddd' };
|
||||||
const snapGrid = [16, 16];
|
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 OverviewFlow = () => {
|
||||||
const [elements, setElements] = useState(initialElements);
|
const [elements, setElements] = useState(initialElements);
|
||||||
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
|
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
|
||||||
const onConnect = (params) => setElements((els) => addEdge(params, els));
|
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
@@ -146,22 +178,7 @@ const OverviewFlow = () => {
|
|||||||
snapToGrid={true}
|
snapToGrid={true}
|
||||||
snapGrid={snapGrid}
|
snapGrid={snapGrid}
|
||||||
>
|
>
|
||||||
<MiniMap
|
<MiniMap nodeStrokeColor={nodeStrokeColor} nodeColor={nodeColor} nodeBorderRadius={2} />
|
||||||
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}
|
|
||||||
/>
|
|
||||||
<Controls />
|
<Controls />
|
||||||
<Background color="#aaa" gap={16} />
|
<Background color="#aaa" gap={16} />
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useStoreState, useStoreActions, isNode } from 'react-flow-renderer';
|
import { useStoreState, useStoreActions } from 'react-flow-renderer';
|
||||||
|
|
||||||
const Sidebar = () => {
|
const Sidebar = () => {
|
||||||
const nodes = useStoreState((store) => store.nodes);
|
const nodes = useStoreState((store) => store.nodes);
|
||||||
@@ -1,14 +1,25 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState, MouseEvent } from 'react';
|
||||||
import ReactFlow, { ReactFlowProvider, addEdge, removeElements, Controls } from 'react-flow-renderer';
|
import ReactFlow, {
|
||||||
|
ReactFlowProvider,
|
||||||
|
addEdge,
|
||||||
|
removeElements,
|
||||||
|
Controls,
|
||||||
|
OnLoadParams,
|
||||||
|
FlowElement,
|
||||||
|
Connection,
|
||||||
|
Edge,
|
||||||
|
Elements,
|
||||||
|
ConnectionMode,
|
||||||
|
} from 'react-flow-renderer';
|
||||||
|
|
||||||
import Sidebar from './Sidebar';
|
import Sidebar from './Sidebar';
|
||||||
|
|
||||||
import './provider.css';
|
import './provider.css';
|
||||||
|
|
||||||
const onElementClick = (event, element) => console.log('click', element);
|
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element);
|
||||||
const onLoad = (reactFlowInstance) => console.log('flow loaded:', reactFlowInstance);
|
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: '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 } },
|
||||||
@@ -18,9 +29,9 @@ const initialElements = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const ProviderFlow = () => {
|
const ProviderFlow = () => {
|
||||||
const [elements, setElements] = useState(initialElements);
|
const [elements, setElements] = useState<Elements>(initialElements);
|
||||||
const onConnect = (params) => setElements((els) => addEdge(params, els));
|
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
|
||||||
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
|
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="providerflow">
|
<div className="providerflow">
|
||||||
@@ -33,7 +44,7 @@ const ProviderFlow = () => {
|
|||||||
onConnect={onConnect}
|
onConnect={onConnect}
|
||||||
onElementsRemove={onElementsRemove}
|
onElementsRemove={onElementsRemove}
|
||||||
onLoad={onLoad}
|
onLoad={onLoad}
|
||||||
connectionMode="loose"
|
connectionMode={ConnectionMode.Loose}
|
||||||
>
|
>
|
||||||
<Controls />
|
<Controls />
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { memo, useCallback } from 'react';
|
import React, { memo, useCallback, Dispatch, FC } from 'react';
|
||||||
import { useZoomPanHelper } from 'react-flow-renderer';
|
import { useZoomPanHelper, OnLoadParams, Elements, FlowExportObject } from 'react-flow-renderer';
|
||||||
import localforage from 'localforage';
|
import localforage from 'localforage';
|
||||||
|
|
||||||
localforage.config({
|
localforage.config({
|
||||||
@@ -11,7 +11,12 @@ const flowKey = 'example-flow';
|
|||||||
|
|
||||||
const getNodeId = () => `randomnode_${+new Date()}`;
|
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 { transform } = useZoomPanHelper();
|
||||||
|
|
||||||
const onSave = useCallback(() => {
|
const onSave = useCallback(() => {
|
||||||
@@ -23,7 +28,7 @@ const Controls = memo(({ rfInstance, setElements }) => {
|
|||||||
|
|
||||||
const onRestore = useCallback(() => {
|
const onRestore = useCallback(() => {
|
||||||
const restoreFlow = async () => {
|
const restoreFlow = async () => {
|
||||||
const flow = await localforage.getItem(flowKey);
|
const flow: FlowExportObject | null = await localforage.getItem(flowKey);
|
||||||
|
|
||||||
if (flow) {
|
if (flow) {
|
||||||
const [x = 0, y = 0] = flow.position;
|
const [x = 0, y = 0] = flow.position;
|
||||||
@@ -51,6 +56,6 @@ const Controls = memo(({ rfInstance, setElements }) => {
|
|||||||
<button onClick={onAdd}>add node</button>
|
<button onClick={onAdd}>add node</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
};
|
||||||
|
|
||||||
export default Controls;
|
export default memo(Controls);
|
||||||
@@ -1,21 +1,29 @@
|
|||||||
import React, { memo, useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import ReactFlow, { ReactFlowProvider, removeElements, addEdge } from 'react-flow-renderer';
|
import ReactFlow, {
|
||||||
|
ReactFlowProvider,
|
||||||
|
removeElements,
|
||||||
|
addEdge,
|
||||||
|
Elements,
|
||||||
|
Connection,
|
||||||
|
Edge,
|
||||||
|
OnLoadParams,
|
||||||
|
} from 'react-flow-renderer';
|
||||||
|
|
||||||
import Controls from './Controls';
|
import Controls from './Controls';
|
||||||
|
|
||||||
import './save.css';
|
import './save.css';
|
||||||
|
|
||||||
const initialElements = [
|
const initialElements: Elements = [
|
||||||
{ id: '1', data: { label: 'Node 1' }, position: { x: 100, y: 100 } },
|
{ id: '1', data: { label: 'Node 1' }, position: { x: 100, y: 100 } },
|
||||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 200 } },
|
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 200 } },
|
||||||
{ id: 'e1-2', source: '1', target: '2' },
|
{ id: 'e1-2', source: '1', target: '2' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const SaveRestore = () => {
|
const SaveRestore = () => {
|
||||||
const [rfInstance, setRfInstance] = useState(null);
|
const [rfInstance, setRfInstance] = useState<OnLoadParams>();
|
||||||
const [elements, setElements] = useState(initialElements);
|
const [elements, setElements] = useState<Elements>(initialElements);
|
||||||
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
|
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
|
||||||
const onConnect = (params) => setElements((els) => addEdge(params, els));
|
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlowProvider>
|
<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';
|
import { getElements } from './utils';
|
||||||
|
|
||||||
const onLoad = (reactFlowInstance) => {
|
const buttonWrapperStyles: CSSProperties = { position: 'absolute', right: 10, top: 10, zIndex: 4 };
|
||||||
|
|
||||||
|
const onLoad = (reactFlowInstance: OnLoadParams) => {
|
||||||
reactFlowInstance.fitView();
|
reactFlowInstance.fitView();
|
||||||
console.log(reactFlowInstance.getElements());
|
console.log(reactFlowInstance.getElements());
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialElements = getElements(30, 30);
|
const initialElements: Elements = getElements(30, 30);
|
||||||
|
|
||||||
const StressFlow = () => {
|
const StressFlow = () => {
|
||||||
const [elements, setElements] = useState(initialElements);
|
const [elements, setElements] = useState<Elements>(initialElements);
|
||||||
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
|
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
|
||||||
const onConnect = (params) => setElements((els) => addEdge(params, els));
|
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
|
||||||
|
|
||||||
const updatePos = () => {
|
const updatePos = () => {
|
||||||
setElements((elms) => {
|
setElements((elms) => {
|
||||||
@@ -44,7 +57,7 @@ const StressFlow = () => {
|
|||||||
<Controls />
|
<Controls />
|
||||||
<Background />
|
<Background />
|
||||||
|
|
||||||
<div style={{ position: 'absolute', right: 10, top: 10, zIndex: 4 }}>
|
<div style={buttonWrapperStyles}>
|
||||||
<button onClick={updatePos} style={{ marginRight: 5 }}>
|
<button onClick={updatePos} style={{ marginRight: 5 }}>
|
||||||
change pos
|
change pos
|
||||||
</button>
|
</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 = [];
|
const initialElements = [];
|
||||||
let nodeId = 1;
|
let nodeId = 1;
|
||||||
let recentNodeId = null;
|
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 onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
||||||
const onElementClick = (event, element) => console.log('click', element);
|
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: '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: '2a', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, className: 'light' },
|
||||||
{ id: '3a', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, className: 'light' },
|
{ id: '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' },
|
{ 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: '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: '1b', data: { label: 'Node 1' }, position: { x: 0, y: 100 }, className: 'light' },
|
||||||
{ id: '2b', data: { label: 'Node 2' }, position: { x: 200, y: 100 }, className: 'light' },
|
{ id: '2b', data: { label: 'Node 2' }, position: { x: 200, y: 100 }, className: 'light' },
|
||||||
@@ -28,9 +28,9 @@ const elementsB = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const BasicFlow = () => {
|
const BasicFlow = () => {
|
||||||
const [elements, setElements] = useState(elementsA);
|
const [elements, setElements] = useState<Elements>(elementsA);
|
||||||
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
|
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
|
||||||
const onConnect = (params) => setElements((els) => addEdge(params, els));
|
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
@@ -39,7 +39,6 @@ const BasicFlow = () => {
|
|||||||
onElementsRemove={onElementsRemove}
|
onElementsRemove={onElementsRemove}
|
||||||
onConnect={onConnect}
|
onConnect={onConnect}
|
||||||
onNodeDragStop={onNodeDragStop}
|
onNodeDragStop={onNodeDragStop}
|
||||||
className="react-flow-basic-example"
|
|
||||||
>
|
>
|
||||||
<div style={{ position: 'absolute', right: 10, top: 10, zIndex: 4 }}>
|
<div style={{ position: 'absolute', right: 10, top: 10, zIndex: 4 }}>
|
||||||
<button onClick={() => setElements(elementsA)} style={{ marginRight: 5 }}>
|
<button onClick={() => setElements(elementsA)} style={{ marginRight: 5 }}>
|
||||||
@@ -1,7 +1,15 @@
|
|||||||
import React, { useState } from 'react';
|
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',
|
id: '1',
|
||||||
type: 'input',
|
type: 'input',
|
||||||
@@ -40,12 +48,13 @@ const initialElements = [
|
|||||||
{ id: 'e1-2', source: '1', target: '2', label: 'This is a draggable edge' },
|
{ 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 UpdatableEdge = () => {
|
||||||
const [elements, setElements] = useState(initialElements);
|
const [elements, setElements] = useState<Elements>(initialElements);
|
||||||
const onEdgeUpdate = (oldEdge, newConnection) => setElements((els) => updateEdge(oldEdge, newConnection, els));
|
const onEdgeUpdate = (oldEdge: Edge, newConnection: Connection) =>
|
||||||
const onConnect = (params) => setElements((els) => addEdge(params, els));
|
setElements((els) => updateEdge(oldEdge, newConnection, els));
|
||||||
|
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow elements={elements} onLoad={onLoad} snapToGrid={true} onEdgeUpdate={onEdgeUpdate} onConnect={onConnect}>
|
<ReactFlow elements={elements} onLoad={onLoad} snapToGrid={true} onEdgeUpdate={onEdgeUpdate} onConnect={onConnect}>
|
||||||
@@ -1,19 +1,19 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import ReactFlow from 'react-flow-renderer';
|
import ReactFlow, { Elements } from 'react-flow-renderer';
|
||||||
|
|
||||||
import './updatenode.css';
|
import './updatenode.css';
|
||||||
|
|
||||||
const initialElements = [
|
const initialElements: Elements = [
|
||||||
{ id: '1', data: { label: '-' }, position: { x: 100, y: 100 } },
|
{ id: '1', data: { label: '-' }, position: { x: 100, y: 100 } },
|
||||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 200 } },
|
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 200 } },
|
||||||
{ id: 'e1-2', source: '1', target: '2' },
|
{ id: 'e1-2', source: '1', target: '2' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const UpdateNode = () => {
|
const UpdateNode = () => {
|
||||||
const [elements, setElements] = useState(initialElements);
|
const [elements, setElements] = useState<Elements>(initialElements);
|
||||||
const [nodeName, setNodeName] = useState('Node 1');
|
const [nodeName, setNodeName] = useState<string>('Node 1');
|
||||||
const [nodeBg, setNodeBg] = useState('#eee');
|
const [nodeBg, setNodeBg] = useState<string>('#eee');
|
||||||
const [nodeHidden, setNodeHidden] = useState(false);
|
const [nodeHidden, setNodeHidden] = useState<boolean>(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setElements((els) =>
|
setElements((els) =>
|
||||||
@@ -7,9 +7,13 @@ import ReactFlow, {
|
|||||||
MiniMap,
|
MiniMap,
|
||||||
useZoomPanHelper,
|
useZoomPanHelper,
|
||||||
ReactFlowProvider,
|
ReactFlowProvider,
|
||||||
|
Elements,
|
||||||
|
ElementId,
|
||||||
|
Connection,
|
||||||
|
Edge,
|
||||||
} from 'react-flow-renderer';
|
} 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: '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' },
|
||||||
@@ -19,12 +23,12 @@ const initialElements = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
let id = 5;
|
let id = 5;
|
||||||
const getId = () => `${id++}`;
|
const getId = (): ElementId => `${id++}`;
|
||||||
|
|
||||||
const UseZoomPanHelperFlow = () => {
|
const UseZoomPanHelperFlow = () => {
|
||||||
const [elements, setElements] = useState(initialElements);
|
const [elements, setElements] = useState<Elements>(initialElements);
|
||||||
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
|
const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
|
||||||
const onConnect = (params) => setElements((els) => addEdge(params, els));
|
const onConnect = (params: Connection | Edge) => setElements((els) => addEdge(params, els));
|
||||||
const { project } = useZoomPanHelper();
|
const { project } = useZoomPanHelper();
|
||||||
|
|
||||||
const onPaneClick = useCallback(
|
const onPaneClick = useCallback(
|
||||||
@@ -53,8 +57,10 @@ const UseZoomPanHelperFlow = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => (
|
const WrappedFlow = () => (
|
||||||
<ReactFlowProvider>
|
<ReactFlowProvider>
|
||||||
<UseZoomPanHelperFlow />
|
<UseZoomPanHelperFlow />
|
||||||
</ReactFlowProvider>
|
</ReactFlowProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export default WrappedFlow;
|
||||||
@@ -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;
|
|
||||||
@@ -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 ReactDOM from 'react-dom';
|
||||||
import { BrowserRouter as Router, Route, Switch, withRouter } from 'react-router-dom';
|
import { BrowserRouter as Router, Route, Switch, withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ const routes = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const Header = withRouter(({ history, location }) => {
|
const Header = withRouter(({ history, location }) => {
|
||||||
const onChange = (event) => history.push(event.target.value);
|
const onChange = (event: ChangeEvent<HTMLSelectElement>) => history.push(event.target.value);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header>
|
<header>
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
/// <reference types="react-scripts" />
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "react-jsx"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user