refactor(examples): switch examples from cra to nextjs
This commit is contained in:
@@ -1,25 +0,0 @@
|
|||||||
# 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*
|
|
||||||
|
|
||||||
/src_oldapi
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# React Flow Examples
|
|
||||||
|
|
||||||
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
## Start
|
|
||||||
|
|
||||||
Starts a dev server at http://localhost:3000
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm start
|
|
||||||
```
|
|
||||||
|
|
||||||
## Build
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
Generated
-39417
File diff suppressed because it is too large
Load Diff
@@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "react-flow-examples",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"private": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@react-flow/core": "11.0.0",
|
|
||||||
"dagre": "^0.8.5",
|
|
||||||
"localforage": "^1.10.0",
|
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-dom": "^18.2.0",
|
|
||||||
"react-router-dom": "^6.3.0",
|
|
||||||
"react-scripts": "5.0.1",
|
|
||||||
"typescript": "^4.7.4"
|
|
||||||
},
|
|
||||||
"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/dagre": "^0.7.47",
|
|
||||||
"@types/localforage": "0.0.34",
|
|
||||||
"@types/react-dom": "^18.0.6",
|
|
||||||
"@types/react-router-dom": "^5.3.3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
/* /index.html 200
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
|
|
||||||
<title>React Flow Examples</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="root"></div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# https://www.robotstxt.org/robotstxt.html
|
|
||||||
User-agent: *
|
|
||||||
Disallow:
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
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 left.</div>
|
|
||||||
<div className="react-flow__node-input" onDragStart={(event: DragEvent) => onDragStart(event, 'input')} draggable>
|
|
||||||
Input Node
|
|
||||||
</div>
|
|
||||||
<div className="react-flow__node-default" onDragStart={(event: DragEvent) => onDragStart(event, 'default')} draggable>
|
|
||||||
Default Node
|
|
||||||
</div>
|
|
||||||
<div className="react-flow__node-output" onDragStart={(event: DragEvent) => onDragStart(event, 'output')} draggable>
|
|
||||||
Output Node
|
|
||||||
</div>
|
|
||||||
</aside>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Sidebar;
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
.react-flow__example-multiflows {
|
|
||||||
display: flex;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-flow__example-multiflows .react-flow {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-flow__example-multiflows .react-flow:first-child {
|
|
||||||
border-right: 2px solid #333;
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
.validationflow .react-flow__node {
|
|
||||||
width: 150px;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 10px;
|
|
||||||
color: #555;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.validationflow .react-flow__node-customnode {
|
|
||||||
background: #e6e6e9;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-flow__node-custominput .react-flow__handle {
|
|
||||||
background: #e6e6e9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.validationflow .react-flow__node-custominput {
|
|
||||||
background: #fff;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.validationflow .react-flow__handle-connecting {
|
|
||||||
background: #ff6060;
|
|
||||||
}
|
|
||||||
|
|
||||||
.validationflow .react-flow__handle-valid {
|
|
||||||
background: #55dd99;
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
body {
|
|
||||||
font-family: sans-serif;
|
|
||||||
color: #111;
|
|
||||||
}
|
|
||||||
|
|
||||||
html,
|
|
||||||
body,
|
|
||||||
#root {
|
|
||||||
margin: 0;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#root {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
|
||||||
padding: 10px;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
display: flex;
|
|
||||||
font-weight: 700;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
text-decoration: none;
|
|
||||||
display: block;
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
header a,
|
|
||||||
header a:focus,
|
|
||||||
header a:active,
|
|
||||||
header a:visited {
|
|
||||||
color: #111;
|
|
||||||
}
|
|
||||||
|
|
||||||
header a:hover {
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
header select {
|
|
||||||
margin-left: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.overview-example__add {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-flow__node a {
|
|
||||||
font-weight: 700;
|
|
||||||
color: #111;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-flow__node.dark-node {
|
|
||||||
background: #0041d0;
|
|
||||||
color: #f8f8f8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-flow__node.dark {
|
|
||||||
background: #557;
|
|
||||||
color: #f8f8f8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-flow__node-selectorNode {
|
|
||||||
font-size: 12px;
|
|
||||||
background: #f0f2f3;
|
|
||||||
border: 1px solid 555;
|
|
||||||
border-radius: 5px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-flow__node-selectorNode .react-flow__handle {
|
|
||||||
border-color: #f0f2f3;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 768px) {
|
|
||||||
.overview-example__add {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,203 +0,0 @@
|
|||||||
import { ChangeEvent } from 'react';
|
|
||||||
import { createRoot } from 'react-dom/client';
|
|
||||||
import { BrowserRouter, Route, Routes, useLocation, useNavigate } from 'react-router-dom';
|
|
||||||
|
|
||||||
import Basic from './Basic';
|
|
||||||
import ControlledUncontrolled from './ControlledUncontrolled';
|
|
||||||
import CustomConnectionLine from './CustomConnectionLine';
|
|
||||||
import CustomNode from './CustomNode';
|
|
||||||
import DefaultNodes from './DefaultNodes';
|
|
||||||
import DragHandle from './DragHandle';
|
|
||||||
import DragNDrop from './DragNDrop';
|
|
||||||
import Edges from './Edges';
|
|
||||||
import EdgeTypes from './EdgeTypes';
|
|
||||||
import Empty from './Empty';
|
|
||||||
import FloatingEdges from './FloatingEdges';
|
|
||||||
import Hidden from './Hidden';
|
|
||||||
import './index.css';
|
|
||||||
import Interaction from './Interaction';
|
|
||||||
import Layouting from './Layouting';
|
|
||||||
import MultiFlows from './MultiFlows';
|
|
||||||
import NestedNodes from './NestedNodes';
|
|
||||||
import NodeTypeChange from './NodeTypeChange';
|
|
||||||
import NodeTypesObjectChange from './NodeTypesObjectChange';
|
|
||||||
import Overview from './Overview';
|
|
||||||
import Provider from './Provider';
|
|
||||||
import SaveRestore from './SaveRestore';
|
|
||||||
import Stress from './Stress';
|
|
||||||
import Subflow from './Subflow';
|
|
||||||
import SwitchFlow from './Switch';
|
|
||||||
import TouchDevice from './TouchDevice';
|
|
||||||
import Undirectional from './Undirectional';
|
|
||||||
import UpdatableEdge from './UpdatableEdge';
|
|
||||||
import UpdateNode from './UpdateNode';
|
|
||||||
import UseUpdateNodeInternals from './UseUpdateNodeInternals';
|
|
||||||
import UseReactFlow from './UseReactFlow';
|
|
||||||
import Validation from './Validation';
|
|
||||||
import UseKeyPress from './UseKeyPress';
|
|
||||||
|
|
||||||
const routes = [
|
|
||||||
{
|
|
||||||
path: '/',
|
|
||||||
component: Overview,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/basic',
|
|
||||||
component: Basic,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/default-nodes',
|
|
||||||
component: DefaultNodes,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/custom-connectionline',
|
|
||||||
component: CustomConnectionLine,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/custom-node',
|
|
||||||
component: CustomNode,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/draghandle',
|
|
||||||
component: DragHandle,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/dragndrop',
|
|
||||||
component: DragNDrop,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/edges',
|
|
||||||
component: Edges,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/edge-types',
|
|
||||||
component: EdgeTypes,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/empty',
|
|
||||||
component: Empty,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/floating-edges',
|
|
||||||
component: FloatingEdges,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/hidden',
|
|
||||||
component: Hidden,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/interaction',
|
|
||||||
component: Interaction,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/layouting',
|
|
||||||
component: Layouting,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/multiflows',
|
|
||||||
component: MultiFlows,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/nested-nodes',
|
|
||||||
component: NestedNodes,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/nodetype-change',
|
|
||||||
component: NodeTypeChange,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/nodetypesobject-change',
|
|
||||||
component: NodeTypesObjectChange,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/provider',
|
|
||||||
component: Provider,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/save-restore',
|
|
||||||
component: SaveRestore,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/stress',
|
|
||||||
component: Stress,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/subflow',
|
|
||||||
component: Subflow,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/switch',
|
|
||||||
component: SwitchFlow,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/touch-device',
|
|
||||||
component: TouchDevice,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/undirectional',
|
|
||||||
component: Undirectional,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/updatable-edge',
|
|
||||||
component: UpdatableEdge,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/update-node',
|
|
||||||
component: UpdateNode,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/usereactflow',
|
|
||||||
component: UseReactFlow,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/useupdatenodeinternals',
|
|
||||||
component: UseUpdateNodeInternals,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/validation',
|
|
||||||
component: Validation,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/controlled-uncontrolled',
|
|
||||||
component: ControlledUncontrolled,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/use-key-press',
|
|
||||||
component: UseKeyPress,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const Header = () => {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const location = useLocation();
|
|
||||||
const onChange = (event: ChangeEvent<HTMLSelectElement>) => navigate(event.target.value);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<header>
|
|
||||||
<a className="logo" href="https://github.com/wbkd/react-flow">
|
|
||||||
React Flow Dev
|
|
||||||
</a>
|
|
||||||
<select defaultValue={location.pathname} onChange={onChange}>
|
|
||||||
{routes.map((route) => (
|
|
||||||
<option value={route.path} key={route.path}>
|
|
||||||
{route.path === '/' ? 'overview' : route.path.substring(1, route.path.length)}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</header>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const container = document.getElementById('root');
|
|
||||||
const root = createRoot(container!);
|
|
||||||
|
|
||||||
root.render(
|
|
||||||
<BrowserRouter>
|
|
||||||
<Header />
|
|
||||||
<Routes>
|
|
||||||
{routes.map((route) => (
|
|
||||||
<Route path={route.path} key={route.path} element={<route.component />} />
|
|
||||||
))}
|
|
||||||
</Routes>
|
|
||||||
</BrowserRouter>
|
|
||||||
);
|
|
||||||
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
/// <reference types="react-scripts" />
|
|
||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
/// <reference types="next" />
|
||||||
|
/// <reference types="next/image-types/global" />
|
||||||
|
|
||||||
|
// NOTE: This file should not be edited
|
||||||
|
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "nextjs",
|
"name": "react-flow-examples",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -11,11 +11,13 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@preconstruct/next": "^4.0.0",
|
"@preconstruct/next": "^4.0.0",
|
||||||
"@react-flow/core": "11.0.0",
|
"@react-flow/core": "11.0.0",
|
||||||
|
"dagre": "^0.8.5",
|
||||||
"next": "12.2.2",
|
"next": "12.2.2",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0"
|
"react-dom": "18.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/dagre": "^0.7.47",
|
||||||
"eslint": "8.19.0",
|
"eslint": "8.19.0",
|
||||||
"eslint-config-next": "12.2.2"
|
"eslint-config-next": "12.2.2"
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -1,3 +1,5 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
useReactFlow,
|
useReactFlow,
|
||||||
Background,
|
Background,
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Node,
|
Node,
|
||||||
addEdge,
|
addEdge,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect, MouseEvent } from 'react';
|
import React, { useState, useEffect, MouseEvent } from 'react';
|
||||||
import { ChangeEvent } from 'react';
|
import { ChangeEvent } from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
+2
@@ -1,3 +1,5 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
useReactFlow,
|
useReactFlow,
|
||||||
Background,
|
Background,
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import { memo, FC } from 'react';
|
import React, { memo, FC } from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Handle,
|
Handle,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { MouseEvent } from 'react';
|
import React, { MouseEvent } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Node,
|
Node,
|
||||||
Edge,
|
Edge,
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import React, { DragEvent } from 'react';
|
||||||
|
import styles from './dnd.module.css';
|
||||||
|
|
||||||
|
const onDragStart = (event: DragEvent, nodeType: string) => {
|
||||||
|
event.dataTransfer.setData('application/reactflow', nodeType);
|
||||||
|
event.dataTransfer.effectAllowed = 'move';
|
||||||
|
};
|
||||||
|
|
||||||
|
const Sidebar = () => {
|
||||||
|
return (
|
||||||
|
<aside className={styles.aside}>
|
||||||
|
<div className={styles.description}>
|
||||||
|
You can drag these nodes to the pane on the left.
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className='react-flow__node-input'
|
||||||
|
onDragStart={(event: DragEvent) => onDragStart(event, 'input')}
|
||||||
|
draggable
|
||||||
|
>
|
||||||
|
Input Node
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className='react-flow__node-default'
|
||||||
|
onDragStart={(event: DragEvent) => onDragStart(event, 'default')}
|
||||||
|
draggable
|
||||||
|
>
|
||||||
|
Default Node
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className='react-flow__node-output'
|
||||||
|
onDragStart={(event: DragEvent) => onDragStart(event, 'output')}
|
||||||
|
draggable
|
||||||
|
>
|
||||||
|
Output Node
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Sidebar;
|
||||||
+9
-9
@@ -4,34 +4,34 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dndflow aside {
|
.aside {
|
||||||
border-right: 1px solid #eee;
|
border-right: 1px solid #eee;
|
||||||
padding: 15px 10px;
|
padding: 15px 10px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
background: #fcfcfc;
|
background: #fcfcfc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dndflow aside > * {
|
.aside > * {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dndflow aside .description {
|
.description {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dndflow .reactflow-wrapper {
|
.wrapper {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 768px) {
|
||||||
.dndflow {
|
.aside {
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dndflow aside {
|
|
||||||
width: 20%;
|
width: 20%;
|
||||||
max-width: 180px;
|
max-width: 180px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dndflow {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, DragEvent } from 'react';
|
import React, { useState, DragEvent } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
ReactFlowProvider,
|
ReactFlowProvider,
|
||||||
addEdge,
|
addEdge,
|
||||||
@@ -13,7 +13,7 @@ import ReactFlow, {
|
|||||||
|
|
||||||
import Sidebar from './Sidebar';
|
import Sidebar from './Sidebar';
|
||||||
|
|
||||||
import './dnd.css';
|
import styles from './dnd.module.css';
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
{
|
{
|
||||||
@@ -63,9 +63,9 @@ const DnDFlow = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='dndflow'>
|
<div className={styles.dndflow}>
|
||||||
<ReactFlowProvider>
|
<ReactFlowProvider>
|
||||||
<div className='reactflow-wrapper'>
|
<div className={styles.wrapper}>
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
edges={edges}
|
edges={edges}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* Example for checking the different edge types and source and target positions
|
* Example for checking the different edge types and source and target positions
|
||||||
*/
|
*/
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { EdgeProps, getBezierPath } from '@react-flow/core';
|
import { EdgeProps, getBezierPath } from '@react-flow/core';
|
||||||
|
|
||||||
const CustomEdge: FC<EdgeProps> = ({
|
const CustomEdge: FC<EdgeProps> = ({
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import {
|
import {
|
||||||
EdgeProps,
|
EdgeProps,
|
||||||
getBezierPath,
|
getBezierPath,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { MouseEvent } from 'react';
|
import React, { MouseEvent } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
Background,
|
Background,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { MouseEvent, CSSProperties } from 'react';
|
import React, { MouseEvent, CSSProperties } from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import {
|
import {
|
||||||
getBezierPath,
|
getBezierPath,
|
||||||
ConnectionLineComponentProps,
|
ConnectionLineComponentProps,
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import { FC, useMemo, CSSProperties } from 'react';
|
import React, { FC, useMemo, CSSProperties } from 'react';
|
||||||
import {
|
import {
|
||||||
EdgeProps,
|
EdgeProps,
|
||||||
useStore,
|
useStore,
|
||||||
+6
-6
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
@@ -10,17 +10,17 @@ import ReactFlow, {
|
|||||||
useEdgesState,
|
useEdgesState,
|
||||||
} from '@react-flow/core';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import './style.css';
|
import styles from './style.module.css';
|
||||||
|
|
||||||
import FloatingEdge from './FloatingEdge';
|
|
||||||
import FloatingConnectionLine from './FloatingConnectionLine';
|
import FloatingConnectionLine from './FloatingConnectionLine';
|
||||||
|
import FloatingEdge from './FloatingEdge';
|
||||||
import { createElements } from './utils';
|
import { createElements } from './utils';
|
||||||
|
|
||||||
const onInit = (reactFlowInstance: ReactFlowInstance) =>
|
const onInit = (reactFlowInstance: ReactFlowInstance) =>
|
||||||
reactFlowInstance.fitView();
|
reactFlowInstance.fitView();
|
||||||
|
|
||||||
const { nodes: initialNodes, edges: initialEdges } = createElements();
|
const { nodes: initialNodes, edges: initialEdges } =
|
||||||
|
typeof window !== 'undefined' ? createElements() : { nodes: [], edges: [] };
|
||||||
const edgeTypes: EdgeTypes = {
|
const edgeTypes: EdgeTypes = {
|
||||||
floating: FloatingEdge,
|
floating: FloatingEdge,
|
||||||
};
|
};
|
||||||
@@ -34,7 +34,7 @@ const FloatingEdges = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='floatingedges'>
|
<div className={styles.floatingedges}>
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
edges={edges}
|
edges={edges}
|
||||||
+1
-1
@@ -4,6 +4,6 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.floatingedges .react-flow__handle {
|
.floatingedges :global .react-flow__handle {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import { Position, XYPosition, Node, Edge } from '@react-flow/core';
|
import React, { Position, XYPosition, Node, Edge } from '@react-flow/core';
|
||||||
|
|
||||||
// this helper function returns the intersection point
|
// this helper function returns the intersection point
|
||||||
// of the line between the center of the intersectionNode and the target node
|
// of the line between the center of the intersectionNode and the target node
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useState, useCallback } from 'react';
|
import React, { useState, useEffect, useCallback } from 'react';
|
||||||
|
|
||||||
import { useEffect } from 'react';
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
MiniMap,
|
MiniMap,
|
||||||
+5
-1
@@ -1,4 +1,8 @@
|
|||||||
import { useState, MouseEvent as ReactMouseEvent, WheelEvent } from 'react';
|
import React, {
|
||||||
|
useState,
|
||||||
|
MouseEvent as ReactMouseEvent,
|
||||||
|
WheelEvent,
|
||||||
|
} from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
MiniMap,
|
MiniMap,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
ReactFlowProvider,
|
ReactFlowProvider,
|
||||||
addEdge,
|
addEdge,
|
||||||
@@ -15,7 +15,7 @@ import dagre from 'dagre';
|
|||||||
|
|
||||||
import initialItems from './initial-elements';
|
import initialItems from './initial-elements';
|
||||||
|
|
||||||
import './layouting.css';
|
import styles from './layouting.module.css';
|
||||||
|
|
||||||
const dagreGraph = new dagre.graphlib.Graph();
|
const dagreGraph = new dagre.graphlib.Graph();
|
||||||
dagreGraph.setDefaultEdgeLabel(() => ({}));
|
dagreGraph.setDefaultEdgeLabel(() => ({}));
|
||||||
@@ -86,7 +86,7 @@ const LayoutFlow = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='layoutflow'>
|
<div className={styles.layoutflow}>
|
||||||
<ReactFlowProvider>
|
<ReactFlowProvider>
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
@@ -99,7 +99,7 @@ const LayoutFlow = () => {
|
|||||||
>
|
>
|
||||||
<Controls />
|
<Controls />
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
<div className='controls'>
|
<div className={styles.controls}>
|
||||||
<button onClick={() => onLayout('TB')} style={{ marginRight: 10 }}>
|
<button onClick={() => onLayout('TB')} style={{ marginRight: 10 }}>
|
||||||
vertical layout
|
vertical layout
|
||||||
</button>
|
</button>
|
||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layoutflow .controls {
|
.controls {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
@@ -12,7 +12,7 @@ import ReactFlow, {
|
|||||||
MarkerType,
|
MarkerType,
|
||||||
} from '@react-flow/core';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import './multiflows.css';
|
import styles from './multiflows.module.css';
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
{
|
{
|
||||||
@@ -77,7 +77,7 @@ const Flow: FC<{ id: string }> = ({ id }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const MultiFlows: FC = () => (
|
const MultiFlows: FC = () => (
|
||||||
<div className='react-flow__example-multiflows'>
|
<div className={styles.multiflows}>
|
||||||
<Flow id='flow-a' />
|
<Flow id='flow-a' />
|
||||||
<Flow id='flow-b' />
|
<Flow id='flow-b' />
|
||||||
</div>
|
</div>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
.multiflows {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.multiflows :global .react-flow {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.multiflows :global .react-flow:first-child {
|
||||||
|
border-right: 2px solid #333;
|
||||||
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import { useState, MouseEvent, useCallback } from 'react';
|
import React, { useState, MouseEvent, useCallback } from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import { CSSProperties } from 'react';
|
import React, { CSSProperties } from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import { useState, CSSProperties, FC } from 'react';
|
import React, { useState, CSSProperties, FC } from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
import {
|
import React, {
|
||||||
MouseEvent as ReactMouseEvent,
|
MouseEvent as ReactMouseEvent,
|
||||||
CSSProperties,
|
CSSProperties,
|
||||||
useCallback,
|
useCallback,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
MiniMap,
|
MiniMap,
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
|
import React from 'react';
|
||||||
import { useStore, useStoreApi } from '@react-flow/core';
|
import { useStore, useStoreApi } from '@react-flow/core';
|
||||||
|
|
||||||
|
import styles from './provider.module.css';
|
||||||
|
|
||||||
const Sidebar = () => {
|
const Sidebar = () => {
|
||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
const nodeInternals = useStore((store) => store.nodeInternals);
|
const nodeInternals = useStore((store) => store.nodeInternals);
|
||||||
@@ -11,17 +14,17 @@ const Sidebar = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside>
|
<aside className={styles.aside}>
|
||||||
<div className='description'>
|
<div className={styles.description}>
|
||||||
This is an example of how you can access the internal state outside of
|
This is an example of how you can access the internal state outside of
|
||||||
the ReactFlow component.
|
the ReactFlow component.
|
||||||
</div>
|
</div>
|
||||||
<div className='title'>Zoom & pan transform</div>
|
<div className={styles.title}>Zoom & pan transform</div>
|
||||||
<div className='transform'>
|
<div className={styles.transform}>
|
||||||
[{transform[0].toFixed(2)}, {transform[1].toFixed(2)},{' '}
|
[{transform[0].toFixed(2)}, {transform[1].toFixed(2)},{' '}
|
||||||
{transform[2].toFixed(2)}]
|
{transform[2].toFixed(2)}]
|
||||||
</div>
|
</div>
|
||||||
<div className='title'>Nodes</div>
|
<div className={styles.title}>Nodes</div>
|
||||||
{Array.from(nodeInternals).map(([, node]) => (
|
{Array.from(nodeInternals).map(([, node]) => (
|
||||||
<div key={node.id}>
|
<div key={node.id}>
|
||||||
Node {node.id} - x: {node.position.x.toFixed(2)}, y:{' '}
|
Node {node.id} - x: {node.position.x.toFixed(2)}, y:{' '}
|
||||||
@@ -29,7 +32,7 @@ const Sidebar = () => {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<div className='selectall'>
|
<div className={styles.selectall}>
|
||||||
<button onClick={selectAll}>select all nodes</button>
|
<button onClick={selectAll}>select all nodes</button>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { MouseEvent } from 'react';
|
import React, { MouseEvent } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
ReactFlowProvider,
|
ReactFlowProvider,
|
||||||
addEdge,
|
addEdge,
|
||||||
@@ -14,7 +14,7 @@ import ReactFlow, {
|
|||||||
|
|
||||||
import Sidebar from './Sidebar';
|
import Sidebar from './Sidebar';
|
||||||
|
|
||||||
import './provider.css';
|
import styles from './provider.module.css';
|
||||||
|
|
||||||
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
||||||
const onInit = (reactFlowInstance: ReactFlowInstance) =>
|
const onInit = (reactFlowInstance: ReactFlowInstance) =>
|
||||||
@@ -44,10 +44,10 @@ const ProviderFlow = () => {
|
|||||||
setEdges((els) => addEdge(params, els));
|
setEdges((els) => addEdge(params, els));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='providerflow'>
|
<div className={styles.providerflow}>
|
||||||
<ReactFlowProvider>
|
<ReactFlowProvider>
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<div className='reactflow-wrapper'>
|
<div className={styles.wrapper}>
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
edges={edges}
|
edges={edges}
|
||||||
+8
-8
@@ -4,32 +4,32 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.providerflow aside {
|
.aside {
|
||||||
border-right: 1px solid #eee;
|
border-right: 1px solid #eee;
|
||||||
padding: 15px 10px;
|
padding: 15px 10px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
background: #fcfcfc;
|
background: #fcfcfc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.providerflow aside .description {
|
.description {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.providerflow aside .title {
|
.title {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.providerflow aside .transform {
|
.transform {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.providerflow .reactflow-wrapper {
|
.wrapper {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.providerflow .selectall {
|
.selectall {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,8 +38,8 @@
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
|
|
||||||
.providerflow aside {
|
.aside {
|
||||||
width: 20%;
|
width: 20%;
|
||||||
max-width: 250px;
|
max-width: 250px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+12
-4
@@ -7,6 +7,8 @@ import {
|
|||||||
} from '@react-flow/core';
|
} from '@react-flow/core';
|
||||||
import localforage from 'localforage';
|
import localforage from 'localforage';
|
||||||
|
|
||||||
|
import styles from './save.module.css';
|
||||||
|
|
||||||
localforage.config({
|
localforage.config({
|
||||||
name: 'react-flow',
|
name: 'react-flow',
|
||||||
storeName: 'flows',
|
storeName: 'flows',
|
||||||
@@ -60,10 +62,16 @@ const Controls: FC<ControlsProps> = ({ setNodes, setEdges }) => {
|
|||||||
}, [setNodes]);
|
}, [setNodes]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='save__controls'>
|
<div className={styles.controls}>
|
||||||
<button onClick={onSave}>save</button>
|
<button className={styles.button} onClick={onSave}>
|
||||||
<button onClick={onRestore}>restore</button>
|
save
|
||||||
<button onClick={onAdd}>add node</button>
|
</button>
|
||||||
|
<button className={styles.button} onClick={onRestore}>
|
||||||
|
restore
|
||||||
|
</button>
|
||||||
|
<button className={styles.button} onClick={onAdd}>
|
||||||
|
add node
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
+1
-3
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
ReactFlowProvider,
|
ReactFlowProvider,
|
||||||
Node,
|
Node,
|
||||||
@@ -11,8 +11,6 @@ import ReactFlow, {
|
|||||||
|
|
||||||
import Controls from './Controls';
|
import Controls from './Controls';
|
||||||
|
|
||||||
import './save.css';
|
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
{ 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 } },
|
||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
.save__controls {
|
.controls {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
@@ -6,6 +6,6 @@
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.save__controls button {
|
.button {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, CSSProperties, useCallback } from 'react';
|
import React, { useState, CSSProperties, useCallback } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
MiniMap,
|
MiniMap,
|
||||||
Controls,
|
Controls,
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import { memo, FC, CSSProperties } from 'react';
|
import React, { memo, FC, CSSProperties } from 'react';
|
||||||
|
|
||||||
import { Handle, NodeProps, Position } from '@react-flow/core';
|
import { Handle, NodeProps, Position } from '@react-flow/core';
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, MouseEvent, useCallback } from 'react';
|
import React, { useState, MouseEvent, useCallback } from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { MouseEvent } from 'react';
|
import React, { MouseEvent } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
Node,
|
Node,
|
||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Node,
|
Node,
|
||||||
Edge,
|
Edge,
|
||||||
@@ -9,7 +9,7 @@ import ReactFlow, {
|
|||||||
addEdge,
|
addEdge,
|
||||||
} from '@react-flow/core';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import './touch-device.css';
|
import styles from './touch-device.module.css';
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
{
|
{
|
||||||
@@ -59,7 +59,7 @@ const TouchDeviceFlow = () => {
|
|||||||
onConnectStop={onConnectStop}
|
onConnectStop={onConnectStop}
|
||||||
onClickConnectStart={onClickConnectStart}
|
onClickConnectStart={onClickConnectStart}
|
||||||
onClickConnectStop={onClickConnectStop}
|
onClickConnectStop={onClickConnectStop}
|
||||||
className='touchdevice-flow'
|
className={styles.flow}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
.touchdevice-flow .react-flow__handle {
|
.flow :global .react-flow__handle {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
background-color: #9f7aea;
|
background-color: #9f7aea;
|
||||||
}
|
}
|
||||||
|
|
||||||
.touchdevice-flow .react-flow__handle.connecting {
|
.flow :global .react-flow__handle.connecting {
|
||||||
animation: bounce 1600ms infinite ease-out;
|
animation: bounce 1600ms infinite ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Node,
|
Node,
|
||||||
Edge,
|
Edge,
|
||||||
@@ -6,7 +6,7 @@ import ReactFlow, {
|
|||||||
useEdgesState,
|
useEdgesState,
|
||||||
} from '@react-flow/core';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import './updatenode.css';
|
import styles from './updatenode.module.css';
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
{ id: '1', data: { label: '-' }, position: { x: 100, y: 100 } },
|
{ id: '1', data: { label: '-' }, position: { x: 100, y: 100 } },
|
||||||
@@ -75,14 +75,14 @@ const UpdateNode = () => {
|
|||||||
onNodesChange={onNodesChange}
|
onNodesChange={onNodesChange}
|
||||||
onEdgesChange={onEdgesChange}
|
onEdgesChange={onEdgesChange}
|
||||||
>
|
>
|
||||||
<div className='updatenode__controls'>
|
<div className={styles.controls}>
|
||||||
<label>label:</label>
|
<label>label:</label>
|
||||||
<input
|
<input
|
||||||
value={nodeName}
|
value={nodeName}
|
||||||
onChange={(evt) => setNodeName(evt.target.value)}
|
onChange={(evt) => setNodeName(evt.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<label className='updatenode__bglabel'>background:</label>
|
<label className={styles.bgLabel}>background:</label>
|
||||||
<input value={nodeBg} onChange={(evt) => setNodeBg(evt.target.value)} />
|
<input value={nodeBg} onChange={(evt) => setNodeBg(evt.target.value)} />
|
||||||
|
|
||||||
<div className='updatenode__checkboxwrapper'>
|
<div className='updatenode__checkboxwrapper'>
|
||||||
+4
-4
@@ -1,4 +1,4 @@
|
|||||||
.updatenode__controls {
|
.controls {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
@@ -6,15 +6,15 @@
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.updatenode__controls label {
|
.controlsLabel {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.updatenode__bglabel {
|
.bgLabel {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.updatenode__checkboxwrapper {
|
.checkboxWrapper {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import React from 'react';
|
||||||
import { useKeyPress } from '@react-flow/core';
|
import { useKeyPress } from '@react-flow/core';
|
||||||
|
|
||||||
const UseKeyPressComponent = () => {
|
const UseKeyPressComponent = () => {
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback, MouseEvent, useEffect } from 'react';
|
import React, { useCallback, MouseEvent, useEffect } from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Node,
|
Node,
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback, CSSProperties, MouseEvent } from 'react';
|
import React, { useCallback, CSSProperties, MouseEvent } from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
NodeTypes,
|
NodeTypes,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { FC, useCallback, useState } from 'react';
|
import React, { FC, useCallback, useState } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
Handle,
|
Handle,
|
||||||
@@ -13,7 +13,7 @@ import ReactFlow, {
|
|||||||
OnConnectStartParams,
|
OnConnectStartParams,
|
||||||
} from '@react-flow/core';
|
} from '@react-flow/core';
|
||||||
|
|
||||||
import './validation.css';
|
import styles from './validation.module.css';
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
{ id: '0', type: 'custominput', position: { x: 0, y: 150 }, data: null },
|
{ id: '0', type: 'custominput', position: { x: 0, y: 150 }, data: null },
|
||||||
@@ -93,7 +93,7 @@ const ValidationFlow = () => {
|
|||||||
onEdgesChange={onEdgesChange}
|
onEdgesChange={onEdgesChange}
|
||||||
onConnect={onConnect}
|
onConnect={onConnect}
|
||||||
selectNodesOnDrag={false}
|
selectNodesOnDrag={false}
|
||||||
className='validationflow'
|
className={styles.validationflow}
|
||||||
nodeTypes={nodeTypes}
|
nodeTypes={nodeTypes}
|
||||||
onConnectStart={onConnectStart}
|
onConnectStart={onConnectStart}
|
||||||
onConnectEnd={onConnectEnd}
|
onConnectEnd={onConnectEnd}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
.validationflow {
|
||||||
|
}
|
||||||
|
|
||||||
|
.validationflow :global .react-flow__node {
|
||||||
|
width: 150px;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 10px;
|
||||||
|
color: #555;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.validationflow :global .react-flow__node-customnode {
|
||||||
|
background: #e6e6e9;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.validationflow :global .react-flow__node-custominput .react-flow__handle {
|
||||||
|
background: #e6e6e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.validationflow :global .react-flow__node-custominput {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.validationflow :global .react-flow__handle-connecting {
|
||||||
|
background: #ff6060;
|
||||||
|
}
|
||||||
|
|
||||||
|
.validationflow :global .react-flow__handle-valid {
|
||||||
|
background: #55dd99;
|
||||||
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import '../styles/globals.css'
|
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }) {
|
|
||||||
return <Component {...pageProps} />
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MyApp
|
|
||||||
Executable
+66
@@ -0,0 +1,66 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
import '../styles/globals.css';
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
'/',
|
||||||
|
'/ControlledUncontrolled',
|
||||||
|
'/CustomConnectionLine',
|
||||||
|
'/CustomNode',
|
||||||
|
'/DefaultNodes',
|
||||||
|
'/DragHandle',
|
||||||
|
'/DragNDrop',
|
||||||
|
'/EdgeTypes',
|
||||||
|
'/Edges',
|
||||||
|
'/Empty',
|
||||||
|
'/FloatingEdges',
|
||||||
|
'/Hidden',
|
||||||
|
'/Interaction',
|
||||||
|
'/Layouting',
|
||||||
|
'/MultiFlows',
|
||||||
|
'/NestedNodes',
|
||||||
|
'/NodeTypeChange',
|
||||||
|
'/NodeTypesObjectChange',
|
||||||
|
'/Overview',
|
||||||
|
'/Provider',
|
||||||
|
'/SaveRestore',
|
||||||
|
'/Stress',
|
||||||
|
'/Subflow',
|
||||||
|
'/Switch',
|
||||||
|
'/TouchDevice',
|
||||||
|
'/Undirectional',
|
||||||
|
'/UpdatableEdge',
|
||||||
|
'/UpdateNode',
|
||||||
|
'/UseKeyPress',
|
||||||
|
'/UseReactFlow',
|
||||||
|
'/UseUpdateNodeInternals',
|
||||||
|
'/Validation',
|
||||||
|
];
|
||||||
|
|
||||||
|
function MyApp({ Component, pageProps }) {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const onRouteChange = (evt) => {
|
||||||
|
router.push(evt.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<header>
|
||||||
|
<a className='logo' href='https://github.com/wbkd/react-flow'>
|
||||||
|
React Flow Dev
|
||||||
|
</a>
|
||||||
|
<select defaultValue={router.pathname} onChange={onRouteChange}>
|
||||||
|
{routes.map((route) => (
|
||||||
|
<option value={route} key={route}>
|
||||||
|
{route === '/' ? 'Basic' : route.substring(1, route.length)}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</header>
|
||||||
|
<Component {...pageProps} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MyApp;
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import ReactFlow from '@react-flow/core';
|
|
||||||
|
|
||||||
export default function Home() {
|
|
||||||
return (
|
|
||||||
<div style={{ height: '100vh' }}>
|
|
||||||
<ReactFlow defaultNodes={[]} defaultEdges={[]} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Regular → Executable
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import { MouseEvent } from 'react';
|
import React, { MouseEvent } from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
ReactFlowProvider,
|
ReactFlowProvider,
|
||||||
Executable → Regular
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 34 KiB |
@@ -1,4 +0,0 @@
|
|||||||
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,16 +1,82 @@
|
|||||||
html,
|
|
||||||
body {
|
body {
|
||||||
padding: 0;
|
font-family: sans-serif;
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
#__next {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
|
height: 100%;
|
||||||
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
#__next {
|
||||||
color: inherit;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
padding: 10px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
display: flex;
|
||||||
|
font-weight: 700;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
header a,
|
||||||
box-sizing: border-box;
|
header a:focus,
|
||||||
|
header a:active,
|
||||||
|
header a:visited {
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
header a:hover {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
header select {
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overview-example__add {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-flow__node a {
|
||||||
|
font-weight: 700;
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-flow__node.dark-node {
|
||||||
|
background: #0041d0;
|
||||||
|
color: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-flow__node.dark {
|
||||||
|
background: #557;
|
||||||
|
color: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-flow__node-selectorNode {
|
||||||
|
font-size: 12px;
|
||||||
|
background: #f0f2f3;
|
||||||
|
border: 1px solid 555;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-flow__node-selectorNode .react-flow__handle {
|
||||||
|
border-color: #f0f2f3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 768px) {
|
||||||
|
.overview-example__add {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,29 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"esModuleInterop": true,
|
"strict": false,
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"strict": true,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noEmit": true,
|
||||||
|
"incremental": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"moduleResolution": "node",
|
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"noEmit": true,
|
"jsx": "preserve"
|
||||||
"jsx": "react-jsx"
|
|
||||||
},
|
},
|
||||||
"include": ["src"],
|
"include": [
|
||||||
"exclude": ["src_oldapi"]
|
"next-env.d.ts",
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,22 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-flow/minimap",
|
"name": "@react-flow/minimap",
|
||||||
"version": "11.0.0",
|
"version": "11.0.0",
|
||||||
"description": "A minimap component for usage with React Flow",
|
"description": "A minimap component that shows the React Flow graph.",
|
||||||
"main": "dist/react-flow-minimap.cjs.js",
|
"main": "dist/react-flow-minimap.cjs.js",
|
||||||
"license": "MIT"
|
"module": "dist/react-flow-minimap.esm.js",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"classcat": "^5.0.3",
|
||||||
|
"d3-drag": "^3.0.0",
|
||||||
|
"d3-selection": "^3.0.0",
|
||||||
|
"zustand": "^4.0.0-rc.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^18.1.0",
|
||||||
|
"react-flow-renderer": "^10.3.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/d3-drag": "^3.0.1",
|
||||||
|
"@types/d3-selection": "^3.0.2"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import React, { useEffect, useRef } from 'react';
|
||||||
|
import { drag, D3DragEvent, SubjectPosition } from 'd3-drag';
|
||||||
|
import { select } from 'd3-selection';
|
||||||
|
import { useReactFlow } from 'react-flow-renderer';
|
||||||
|
|
||||||
|
function MiniMapDrag({ x = 0, y = 0, width = 0, height = 0 }) {
|
||||||
|
const dragRef = useRef<SVGRectElement>(null);
|
||||||
|
const { getViewport, setViewport } = useReactFlow();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (dragRef.current) {
|
||||||
|
const onDrag = (
|
||||||
|
evt: D3DragEvent<SVGRectElement, null, SubjectPosition>
|
||||||
|
) => {
|
||||||
|
const { x, y, zoom } = getViewport();
|
||||||
|
setViewport({ x: x - evt.dx * zoom, y: y - evt.dy * zoom, zoom });
|
||||||
|
};
|
||||||
|
|
||||||
|
const selection = select(dragRef.current as Element);
|
||||||
|
const dragBehaviour = drag().on('drag', onDrag);
|
||||||
|
|
||||||
|
selection.call(dragBehaviour);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
selection.on('.drag', null);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, [getViewport, setViewport]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<rect
|
||||||
|
ref={dragRef}
|
||||||
|
fill='rgba(255, 0,0,.5)'
|
||||||
|
x={x}
|
||||||
|
y={y}
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MiniMapDrag;
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import React, { memo, CSSProperties } from 'react';
|
||||||
|
import cc from 'classcat';
|
||||||
|
|
||||||
|
interface MiniMapNodeProps {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
borderRadius: number;
|
||||||
|
className: string;
|
||||||
|
color: string;
|
||||||
|
shapeRendering: string;
|
||||||
|
strokeColor: string;
|
||||||
|
strokeWidth: number;
|
||||||
|
style?: CSSProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MiniMapNode = ({
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
style,
|
||||||
|
color,
|
||||||
|
strokeColor,
|
||||||
|
strokeWidth,
|
||||||
|
className,
|
||||||
|
borderRadius,
|
||||||
|
shapeRendering,
|
||||||
|
}: MiniMapNodeProps) => {
|
||||||
|
const { background, backgroundColor } = style || {};
|
||||||
|
const fill = (color || background || backgroundColor) as string;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<rect
|
||||||
|
className={cc(['react-flow__minimap-node', className])}
|
||||||
|
x={x}
|
||||||
|
y={y}
|
||||||
|
rx={borderRadius}
|
||||||
|
ry={borderRadius}
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
fill={fill}
|
||||||
|
stroke={strokeColor}
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
shapeRendering={shapeRendering}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
MiniMapNode.displayName = 'MiniMapNode';
|
||||||
|
|
||||||
|
export default memo(MiniMapNode);
|
||||||
@@ -1 +0,0 @@
|
|||||||
export default 'Minimap';
|
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
import React, { memo } from 'react';
|
||||||
|
import cc from 'classcat';
|
||||||
|
import shallow from 'zustand/shallow';
|
||||||
|
import {
|
||||||
|
useStore,
|
||||||
|
getRectOfNodes,
|
||||||
|
Box,
|
||||||
|
MiniMapProps,
|
||||||
|
GetMiniMapNodeAttribute,
|
||||||
|
ReactFlowState,
|
||||||
|
Rect,
|
||||||
|
} from 'react-flow-renderer';
|
||||||
|
|
||||||
|
import MiniMapNode from './MiniMapNode';
|
||||||
|
import MiniMapDrag from './MiniMapDrag';
|
||||||
|
|
||||||
|
declare const window: any;
|
||||||
|
|
||||||
|
const defaultWidth = 200;
|
||||||
|
const defaultHeight = 150;
|
||||||
|
|
||||||
|
const selector = (s: ReactFlowState) => ({
|
||||||
|
width: s.width,
|
||||||
|
height: s.height,
|
||||||
|
transform: s.transform,
|
||||||
|
nodes: Array.from(s.nodeInternals.values()),
|
||||||
|
});
|
||||||
|
|
||||||
|
const getAttrFunction = (func: any): GetMiniMapNodeAttribute =>
|
||||||
|
func instanceof Function ? func : () => func;
|
||||||
|
|
||||||
|
export const getBoundsOfBoxes = (box1: Box, box2: Box): Box => ({
|
||||||
|
x: Math.min(box1.x, box2.x),
|
||||||
|
y: Math.min(box1.y, box2.y),
|
||||||
|
x2: Math.max(box1.x2, box2.x2),
|
||||||
|
y2: Math.max(box1.y2, box2.y2),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const rectToBox = ({ x, y, width, height }: Rect): Box => ({
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
x2: x + width,
|
||||||
|
y2: y + height,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const boxToRect = ({ x, y, x2, y2 }: Box): Rect => ({
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width: x2 - x,
|
||||||
|
height: y2 - y,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getBoundsofRects = (rect1: Rect, rect2: Rect): Rect =>
|
||||||
|
boxToRect(getBoundsOfBoxes(rectToBox(rect1), rectToBox(rect2)));
|
||||||
|
|
||||||
|
const MiniMap = ({
|
||||||
|
style,
|
||||||
|
className,
|
||||||
|
nodeStrokeColor = '#555',
|
||||||
|
nodeColor = '#fff',
|
||||||
|
nodeClassName = '',
|
||||||
|
nodeBorderRadius = 5,
|
||||||
|
nodeStrokeWidth = 2,
|
||||||
|
maskColor = 'rgb(240, 242, 243, 0.7)',
|
||||||
|
}: MiniMapProps) => {
|
||||||
|
const {
|
||||||
|
width: containerWidth,
|
||||||
|
height: containerHeight,
|
||||||
|
transform,
|
||||||
|
nodes,
|
||||||
|
} = useStore(selector, shallow);
|
||||||
|
const elementWidth = (style?.width as number) ?? defaultWidth;
|
||||||
|
const elementHeight = (style?.height as number) ?? defaultHeight;
|
||||||
|
const nodeColorFunc = getAttrFunction(nodeColor);
|
||||||
|
const nodeStrokeColorFunc = getAttrFunction(nodeStrokeColor);
|
||||||
|
const nodeClassNameFunc = getAttrFunction(nodeClassName);
|
||||||
|
const viewBB: Rect = {
|
||||||
|
x: -transform[0] / transform[2],
|
||||||
|
y: -transform[1] / transform[2],
|
||||||
|
width: containerWidth / transform[2],
|
||||||
|
height: containerHeight / transform[2],
|
||||||
|
};
|
||||||
|
const boundingRect =
|
||||||
|
nodes.length > 0 ? getBoundsofRects(getRectOfNodes(nodes), viewBB) : viewBB;
|
||||||
|
const scaledWidth = boundingRect.width / elementWidth;
|
||||||
|
const scaledHeight = boundingRect.height / elementHeight;
|
||||||
|
const viewScale = Math.max(scaledWidth, scaledHeight);
|
||||||
|
const viewWidth = viewScale * elementWidth;
|
||||||
|
const viewHeight = viewScale * elementHeight;
|
||||||
|
const offset = 5 * viewScale;
|
||||||
|
const x = boundingRect.x - (viewWidth - boundingRect.width) / 2 - offset;
|
||||||
|
const y = boundingRect.y - (viewHeight - boundingRect.height) / 2 - offset;
|
||||||
|
const width = viewWidth + offset * 2;
|
||||||
|
const height = viewHeight + offset * 2;
|
||||||
|
const shapeRendering =
|
||||||
|
typeof window === 'undefined' || !!window.chrome
|
||||||
|
? 'crispEdges'
|
||||||
|
: 'geometricPrecision';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width={elementWidth}
|
||||||
|
height={elementHeight}
|
||||||
|
viewBox={`${x} ${y} ${width} ${height}`}
|
||||||
|
style={style}
|
||||||
|
className={cc(['react-flow__minimap', className])}
|
||||||
|
>
|
||||||
|
{nodes
|
||||||
|
.filter((node) => !node.hidden && node.width && node.height)
|
||||||
|
.map((node) => {
|
||||||
|
return (
|
||||||
|
<MiniMapNode
|
||||||
|
key={node.id}
|
||||||
|
x={node.positionAbsolute?.x ?? 0}
|
||||||
|
y={node.positionAbsolute?.y ?? 0}
|
||||||
|
width={node.width!}
|
||||||
|
height={node.height!}
|
||||||
|
style={node.style}
|
||||||
|
className={nodeClassNameFunc(node)}
|
||||||
|
color={nodeColorFunc(node)}
|
||||||
|
borderRadius={nodeBorderRadius}
|
||||||
|
strokeColor={nodeStrokeColorFunc(node)}
|
||||||
|
strokeWidth={nodeStrokeWidth}
|
||||||
|
shapeRendering={shapeRendering}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<MiniMapDrag
|
||||||
|
x={viewBB.x}
|
||||||
|
y={viewBB.y}
|
||||||
|
width={viewBB.width}
|
||||||
|
height={viewBB.height}
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
className='react-flow__minimap-mask'
|
||||||
|
d={`M${x - offset},${y - offset}h${width + offset * 2}v${
|
||||||
|
height + offset * 2
|
||||||
|
}h${-width - offset * 2}z
|
||||||
|
M${viewBB.x},${viewBB.y}h${viewBB.width}v${
|
||||||
|
viewBB.height
|
||||||
|
}h${-viewBB.width}z`}
|
||||||
|
fill={maskColor}
|
||||||
|
fillRule='evenodd'
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
MiniMap.displayName = 'MiniMap';
|
||||||
|
|
||||||
|
export default memo(MiniMap);
|
||||||
Reference in New Issue
Block a user