├── .nvmrc ├── .npmrc ├── .prettierignore ├── static ├── robots.txt ├── favicon.ico ├── fonts │ ├── JetBrainsMono-Bold.eot │ ├── JetBrainsMono-Bold.woff │ ├── JetBrainsMono-Bold.woff2 │ ├── JetBrainsMono-Regular.eot │ ├── JetBrainsMono-Regular.woff │ └── JetBrainsMono-Regular.woff2 └── images │ └── react-flow-header.jpg ├── netlify.toml ├── .prettierrc ├── src ├── assets │ ├── images │ │ ├── blog-webkid-teaser.jpg │ │ ├── showcases │ │ │ ├── circles-showcase.png │ │ │ ├── botfront-showcase.png │ │ │ └── datablocks-showcase.png │ │ ├── react-flow-logo.svg │ │ ├── logo.svg │ │ └── logo-white.svg │ ├── icons │ │ ├── lightning.svg │ │ ├── pen.svg │ │ ├── graph_bar.svg │ │ ├── arrow_right.svg │ │ ├── close.svg │ │ ├── mail.svg │ │ ├── info_circle.svg │ │ ├── arrow_right_circle.svg │ │ ├── menu.svg │ │ ├── link.svg │ │ ├── eye.svg │ │ ├── twitter_circle.svg │ │ ├── favicon_stroke.svg │ │ ├── code.svg │ │ ├── phone.svg │ │ ├── github_circle.svg │ │ └── twitter_outline.svg │ └── data │ │ └── showcases.json ├── example-flows │ ├── CustomNode │ │ ├── index.css │ │ └── ColorSelectorNode.js │ ├── FloatingEdges │ │ ├── style.css │ │ ├── FloatingConnectionLine.tsx │ │ ├── FloatingEdge.tsx │ │ ├── index.tsx │ │ └── utils.ts │ ├── SaveRestore │ │ ├── save.css │ │ └── index.js │ ├── Layouting │ │ ├── layouting.css │ │ ├── initial-elements.js │ │ └── index.js │ ├── SmoothTransition │ │ ├── transition.css │ │ └── index.js │ ├── UpdateNode │ │ ├── updatenode.css │ │ └── index.js │ ├── ContextualZoomFeatures │ │ ├── index.css │ │ ├── ZoomNode.js │ │ └── index.js │ ├── EdgeWithButton │ │ ├── index.css │ │ ├── index.js │ │ └── ButtonEdge.js │ ├── DragHandle │ │ ├── index.tsx │ │ └── DragHandleNode.tsx │ ├── CustomConnectionLine │ │ ├── ConnectionLine.js │ │ └── index.js │ ├── Validation │ │ ├── validation.css │ │ └── index.js │ ├── ZoomPanHelper │ │ ├── zoompanhelper.css │ │ ├── Sidebar.js │ │ └── index.js │ ├── DragNDrop │ │ ├── Sidebar.js │ │ ├── dnd.css │ │ └── index.js │ ├── Provider │ │ ├── provider.css │ │ ├── Sidebar.js │ │ └── index.js │ ├── Edges │ │ └── CustomEdge.js │ ├── Stress │ │ ├── utils.js │ │ └── index.js │ ├── EdgeTypes │ │ ├── index.js │ │ └── utils.js │ ├── UpdatableEdge │ │ └── index.js │ ├── Overview │ │ ├── index.js │ │ └── initial-elements.js │ ├── Empty │ │ └── index.js │ └── Hidden │ │ └── index.js ├── templates │ ├── mdx-renderer │ │ ├── DefaultMdx.js │ │ └── DocMdx.js │ ├── example-page.js │ └── doc-page.js ├── utils │ ├── browser-utils.js │ ├── project-utils.js │ └── css-utils.js ├── pages │ └── 404.js ├── components │ ├── CenterContent │ │ └── index.js │ ├── Link │ │ └── index.js │ ├── InfoBox │ │ └── index.js │ ├── Close │ │ └── index.js │ ├── Page │ │ ├── Doc.js │ │ ├── index.js │ │ ├── MetaTags.js │ │ └── Example.js │ ├── ContentSection │ │ └── index.js │ ├── Logo │ │ └── index.js │ ├── SectionIntro │ │ └── index.js │ ├── CodeBlock │ │ ├── index.js │ │ └── Mdx.js │ ├── Footer │ │ └── index.js │ ├── Showcases │ │ └── index.js │ ├── HeroFlow │ │ └── ColorPickerNode.js │ ├── Button │ │ └── index.js │ ├── TeaserFlow │ │ ├── A.js │ │ ├── index.js │ │ └── C.js │ ├── Icon │ │ └── index.js │ ├── Typo │ │ └── index.js │ └── Sidebar │ │ └── index.js ├── themes │ ├── normalize.js │ ├── global.js │ └── index.js ├── hooks │ ├── useMenuHeight.js │ ├── useExamplePages.js │ └── useShowcaseImages.js ├── markdown │ └── docs │ │ ├── api │ │ ├── components │ │ │ ├── background.md │ │ │ ├── minimap.md │ │ │ ├── provider.md │ │ │ └── controls.md │ │ ├── node-types │ │ │ ├── node-types.js │ │ │ └── index.md │ │ ├── nodes.md │ │ ├── internal-state-actions.md │ │ ├── edges.md │ │ ├── edge-types.md │ │ ├── react-flow-instance.md │ │ ├── helper-functions.md │ │ ├── edge-utils.md │ │ ├── hooks.md │ │ └── handle.md │ │ ├── getting-started │ │ ├── Basic.js │ │ ├── BasicFunctions.js │ │ └── index.md │ │ ├── index.md │ │ └── theming.md └── styles │ └── global.css ├── .gitignore ├── gatsby-browser.js ├── generators ├── utils.js ├── examples.js ├── docs.js └── markdown-pages.js ├── README.md ├── .eslintrc.js ├── LICENSE ├── gatsby-node.js ├── gatsby-config.js └── package.json /.nvmrc: -------------------------------------------------------------------------------- 1 | v15.10.0 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | legacy-peer-deps=true -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | src/pages/blog/**/*.md -------------------------------------------------------------------------------- /static/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [[plugins]] 2 | package = "netlify-plugin-gatsby-cache" -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyflow/react-flow-docs-v9/HEAD/static/favicon.ico -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "semi": true, 4 | "singleQuote": true, 5 | "printWidth": 120 6 | } 7 | -------------------------------------------------------------------------------- /static/fonts/JetBrainsMono-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyflow/react-flow-docs-v9/HEAD/static/fonts/JetBrainsMono-Bold.eot -------------------------------------------------------------------------------- /static/fonts/JetBrainsMono-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyflow/react-flow-docs-v9/HEAD/static/fonts/JetBrainsMono-Bold.woff -------------------------------------------------------------------------------- /static/images/react-flow-header.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyflow/react-flow-docs-v9/HEAD/static/images/react-flow-header.jpg -------------------------------------------------------------------------------- /static/fonts/JetBrainsMono-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyflow/react-flow-docs-v9/HEAD/static/fonts/JetBrainsMono-Bold.woff2 -------------------------------------------------------------------------------- /static/fonts/JetBrainsMono-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyflow/react-flow-docs-v9/HEAD/static/fonts/JetBrainsMono-Regular.eot -------------------------------------------------------------------------------- /src/assets/images/blog-webkid-teaser.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyflow/react-flow-docs-v9/HEAD/src/assets/images/blog-webkid-teaser.jpg -------------------------------------------------------------------------------- /static/fonts/JetBrainsMono-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyflow/react-flow-docs-v9/HEAD/static/fonts/JetBrainsMono-Regular.woff -------------------------------------------------------------------------------- /static/fonts/JetBrainsMono-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyflow/react-flow-docs-v9/HEAD/static/fonts/JetBrainsMono-Regular.woff2 -------------------------------------------------------------------------------- /src/assets/images/showcases/circles-showcase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyflow/react-flow-docs-v9/HEAD/src/assets/images/showcases/circles-showcase.png -------------------------------------------------------------------------------- /src/assets/images/showcases/botfront-showcase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyflow/react-flow-docs-v9/HEAD/src/assets/images/showcases/botfront-showcase.png -------------------------------------------------------------------------------- /src/assets/images/showcases/datablocks-showcase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyflow/react-flow-docs-v9/HEAD/src/assets/images/showcases/datablocks-showcase.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | public 3 | .gatsby-context.js 4 | .DS_Store 5 | .intermediate-representation/ 6 | .cache/ 7 | yarn.lock 8 | *.log 9 | .env 10 | .yalc 11 | yalc.lock -------------------------------------------------------------------------------- /gatsby-browser.js: -------------------------------------------------------------------------------- 1 | import 'babel-polyfill'; 2 | import './src/styles/global.css'; 3 | 4 | export const onRouteUpdate = () => { 5 | document.body.classList.remove('noscroll'); 6 | }; 7 | -------------------------------------------------------------------------------- /src/example-flows/CustomNode/index.css: -------------------------------------------------------------------------------- 1 | .react-flow__node-selectorNode { 2 | font-size: 12px; 3 | background: #eee; 4 | border: 1px solid #555; 5 | border-radius: 5px; 6 | text-align: center; 7 | } 8 | -------------------------------------------------------------------------------- /src/example-flows/FloatingEdges/style.css: -------------------------------------------------------------------------------- 1 | .floatingedges { 2 | flex-direction: column; 3 | display: flex; 4 | flex-grow: 1; 5 | } 6 | 7 | .floatingedges .react-flow__handle { 8 | opacity: 0; 9 | } 10 | -------------------------------------------------------------------------------- /src/example-flows/SaveRestore/save.css: -------------------------------------------------------------------------------- 1 | .save__controls { 2 | position: absolute; 3 | right: 10px; 4 | top: 10px; 5 | z-index: 4; 6 | font-size: 12px; 7 | } 8 | 9 | .save__controls button { 10 | margin-left: 5px; 11 | } 12 | -------------------------------------------------------------------------------- /generators/utils.js: -------------------------------------------------------------------------------- 1 | function filterPublished(post) { 2 | const isPublished = post.node.frontmatter && post.node.frontmatter.published; 3 | return process.env.NODE_ENV === 'development' || isPublished; 4 | } 5 | 6 | module.exports = { 7 | filterPublished, 8 | }; 9 | -------------------------------------------------------------------------------- /src/assets/icons/lightning.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-flow-docs-v9 2 | 3 | #### ⚠️ These are the old docs for React Flow v9. For the up-to-date documentation, please refer to: [wbkd/react-flow-docs](https://github.com/wbkd/react-flow-docs) ⚠️ 4 | 5 | ## Development 6 | 7 | - `npm install` 8 | - `npm run dev` 9 | 10 | ## Build 11 | 12 | - `npm run build` 13 | -------------------------------------------------------------------------------- /src/assets/icons/pen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/example-flows/Layouting/layouting.css: -------------------------------------------------------------------------------- 1 | .layoutflow { 2 | flex-grow: 1; 3 | position: relative; 4 | } 5 | 6 | .layoutflow .controls { 7 | position: absolute; 8 | right: 10px; 9 | top: 10px; 10 | z-index: 10; 11 | font-size: 12px; 12 | } 13 | 14 | .layoutflow .controls button:first-child { 15 | margin-right: 10px; 16 | } 17 | -------------------------------------------------------------------------------- /src/assets/icons/graph_bar.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/example-flows/SmoothTransition/transition.css: -------------------------------------------------------------------------------- 1 | .transition { 2 | flex-grow: 1; 3 | position: relative; 4 | } 5 | 6 | .transition .controls { 7 | position: absolute; 8 | right: 10px; 9 | top: 10px; 10 | z-index: 10; 11 | font-size: 12px; 12 | } 13 | 14 | .transition .controls button + button { 15 | margin-left: 10px; 16 | } 17 | -------------------------------------------------------------------------------- /src/templates/mdx-renderer/DefaultMdx.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { MDXProvider } from '@mdx-js/react'; 3 | import { MDXRenderer } from 'gatsby-plugin-mdx'; 4 | 5 | const Mdx = ({ content = null }) => { 6 | return ( 7 | 8 | {content} 9 | 10 | ); 11 | }; 12 | 13 | export default Mdx; 14 | -------------------------------------------------------------------------------- /src/utils/browser-utils.js: -------------------------------------------------------------------------------- 1 | export function isOldIE() { 2 | if (typeof navigator === 'undefined') { 3 | return false; 4 | } 5 | 6 | // https://stackoverflow.com/a/22242528 7 | return ( 8 | navigator.userAgent.indexOf('MSIE') !== -1 || 9 | navigator.appVersion.indexOf('Trident/') > -1 10 | ); 11 | } 12 | 13 | export default { 14 | isOldIE, 15 | }; 16 | -------------------------------------------------------------------------------- /src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import Page from 'components/Page'; 4 | 5 | const metaTags = { 6 | title: 'React Flow - 404', 7 | siteUrl: 'https://reactflow.dev/404', 8 | robots: 'noindex, nofollow', 9 | }; 10 | 11 | const NotFound = () => { 12 | return Page not Found; 13 | }; 14 | 15 | export default NotFound; 16 | -------------------------------------------------------------------------------- /src/assets/icons/arrow_right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es6: true, 5 | }, 6 | plugins: ['react'], 7 | globals: { 8 | graphql: false, 9 | __REACT_FLOW_VERSION__: true, 10 | }, 11 | parserOptions: { 12 | sourceType: 'module', 13 | ecmaFeatures: { 14 | experimentalObjectRestSpread: true, 15 | jsx: true, 16 | }, 17 | }, 18 | extends: 'react-app', 19 | }; 20 | -------------------------------------------------------------------------------- /src/assets/icons/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/example-flows/UpdateNode/updatenode.css: -------------------------------------------------------------------------------- 1 | .updatenode__controls { 2 | position: absolute; 3 | right: 10px; 4 | top: 10px; 5 | z-index: 4; 6 | font-size: 12px; 7 | } 8 | 9 | .updatenode__controls label { 10 | display: block; 11 | } 12 | 13 | .updatenode__bglabel { 14 | margin-top: 10px; 15 | } 16 | 17 | .updatenode__checkboxwrapper { 18 | margin-top: 10px; 19 | display: flex; 20 | align-items: center; 21 | } 22 | -------------------------------------------------------------------------------- /src/assets/icons/mail.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/info_circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/assets/icons/arrow_right_circle.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/CenterContent/index.js: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled'; 2 | import { Box } from 'reflexbox'; 3 | 4 | import { getThemeSpacePx } from 'utils/css-utils'; 5 | 6 | export default styled(Box)` 7 | max-width: ${(p) => 8 | p.maxWidth || (p.big ? p.theme.maxWidthBig : p.theme.maxWidth)}; 9 | margin-left: auto; 10 | margin-right: auto; 11 | padding-left: ${getThemeSpacePx(3)}; 12 | padding-right: ${getThemeSpacePx(3)}; 13 | `; 14 | -------------------------------------------------------------------------------- /src/themes/normalize.js: -------------------------------------------------------------------------------- 1 | import React, { memo } from 'react'; 2 | import { Global, css, jsx } from '@emotion/react'; 3 | import emotionNormalize from 'emotion-normalize'; 4 | 5 | const NormalizeStyle = memo(() => { 6 | const globalStyles = css` 7 | ${emotionNormalize} 8 | 9 | input { 10 | box-sizing: border-box; 11 | } 12 | `; 13 | 14 | return ; 15 | }); 16 | 17 | export default NormalizeStyle; 18 | -------------------------------------------------------------------------------- /src/example-flows/ContextualZoomFeatures/index.css: -------------------------------------------------------------------------------- 1 | .react-flow__node-zoom { 2 | font-size: 12px; 3 | background: #fff; 4 | border: 1px solid #555; 5 | border-radius: 5px; 6 | text-align: center; 7 | width: 150px; 8 | padding: 10px; 9 | line-height: 1.2; 10 | } 11 | 12 | .react-flow__node-zoom img { 13 | pointer-events: none; 14 | } 15 | 16 | .placeholder div { 17 | background: #eee; 18 | width: 100%; 19 | height: 10px; 20 | margin-bottom: 4px; 21 | } 22 | 23 | .placeholder div:last-child { 24 | margin-bottom: 0; 25 | } 26 | -------------------------------------------------------------------------------- /src/assets/data/showcases.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "title": "Botfront - Conversational platform", 4 | "url": "https://botfront.io/", 5 | "image": "../images/showcases/botfront-showcase.png" 6 | }, 7 | { 8 | "title": "datablocks - Node-based data editor", 9 | "url": "https://datablocks.pro", 10 | "image": "../images/showcases/datablocks-showcase.png" 11 | }, 12 | { 13 | "title": "Circles - Visual degree planner", 14 | "url": "https://circles360.github.io/", 15 | "image": "../images/showcases/circles-showcase.png" 16 | } 17 | ] 18 | -------------------------------------------------------------------------------- /src/example-flows/EdgeWithButton/index.css: -------------------------------------------------------------------------------- 1 | .edgebutton { 2 | width: 20px; 3 | height: 20px; 4 | background: #eee; 5 | border: 1px solid #fff; 6 | cursor: pointer; 7 | border-radius: 50%; 8 | font-size: 12px; 9 | line-height: 1; 10 | } 11 | 12 | .edgebutton:hover { 13 | box-shadow: 0 0 6px 2px rgba(0, 0, 0, 0.08); 14 | } 15 | 16 | .edgebutton-foreignobject body { 17 | background: transparent; 18 | width: 40px; 19 | height: 40px; 20 | display: flex; 21 | justify-content: center; 22 | align-items: center; 23 | min-height: 40px; 24 | } 25 | -------------------------------------------------------------------------------- /src/assets/icons/menu.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/assets/icons/link.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/hooks/useMenuHeight.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | 3 | const getInnerHeight = () => { 4 | return typeof window !== 'undefined' ? window.innerHeight : 0; 5 | }; 6 | 7 | export default function useMenuHeight() { 8 | const [menuHeight, setMenuHeight] = useState(getInnerHeight()); 9 | 10 | useEffect(() => { 11 | const onResize = () => { 12 | setMenuHeight(getInnerHeight()); 13 | }; 14 | 15 | window.addEventListener('resize', onResize); 16 | 17 | return () => { 18 | window.removeEventListener('resize', onResize); 19 | }; 20 | }, []); 21 | 22 | return menuHeight; 23 | } 24 | -------------------------------------------------------------------------------- /src/components/Link/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link as GatsbyLink } from 'gatsby'; 3 | 4 | const Link = ({ children, to, activeClassName, partiallyActive, ...other }) => { 5 | const internal = /^\/(?!\/)/.test(to); 6 | 7 | if (internal) { 8 | return ( 9 | 15 | {children} 16 | 17 | ); 18 | } 19 | return ( 20 | 21 | {children} 22 | 23 | ); 24 | }; 25 | export default Link; 26 | -------------------------------------------------------------------------------- /src/example-flows/DragHandle/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactFlow from 'react-flow-renderer'; 3 | 4 | import DragHandleNode from './DragHandleNode'; 5 | 6 | const nodeTypes = { 7 | dragHandleNode: DragHandleNode, 8 | }; 9 | 10 | const elements = [ 11 | { 12 | id: '2', 13 | type: 'dragHandleNode', 14 | dragHandle: '.custom-drag-handle', 15 | style: { border: '1px solid #ddd', padding: '20px 40px' }, 16 | position: { x: 200, y: 200 }, 17 | }, 18 | ]; 19 | 20 | const DragHandleFlow = () => ( 21 | 22 | ); 23 | 24 | export default DragHandleFlow; 25 | -------------------------------------------------------------------------------- /src/components/InfoBox/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from '@emotion/styled'; 3 | import { Box } from 'reflexbox'; 4 | 5 | const Wrapper = styled(Box)` 6 | padding: 16px; 7 | background: ${(p) => p.theme.colors.violetLighten45}; 8 | color: white; 9 | border-radius: 5px; 10 | margin: 20px 0; 11 | `; 12 | 13 | const Title = styled(Box)` 14 | font-size: 20px; 15 | margin-bottom: 4px; 16 | font-weight: 900; 17 | `; 18 | 19 | export default ({ title = null, text, ...rest }) => { 20 | return ( 21 | 22 | {title} 23 |
{text}
24 |
25 | ); 26 | }; 27 | -------------------------------------------------------------------------------- /src/hooks/useExamplePages.js: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react'; 2 | import { useStaticQuery, graphql } from 'gatsby'; 3 | 4 | export default function useFeaturedProjects() { 5 | const rawData = useStaticQuery(graphql` 6 | query ExamplePages { 7 | allExamplesJson { 8 | edges { 9 | node { 10 | title 11 | slug 12 | } 13 | } 14 | } 15 | } 16 | `); 17 | 18 | const data = useMemo(() => { 19 | return rawData.allExamplesJson.edges.map(({ node }) => ({ 20 | slug: `/${node.slug}`, 21 | title: node.title, 22 | })); 23 | }, [rawData]); 24 | 25 | return data; 26 | } 27 | -------------------------------------------------------------------------------- /src/example-flows/ContextualZoomFeatures/ZoomNode.js: -------------------------------------------------------------------------------- 1 | import React, { memo } from 'react'; 2 | 3 | import { Handle, useStoreState } from 'react-flow-renderer'; 4 | 5 | const Placeholder = () => ( 6 |
7 |
8 |
9 |
10 |
11 | ); 12 | 13 | export default memo(({ data }) => { 14 | const [, , zoom] = useStoreState((state) => state.transform); 15 | const showContent = zoom >= 1.5; 16 | 17 | return ( 18 | <> 19 | 20 | {showContent ? data.content : } 21 | 22 | 23 | ); 24 | }); 25 | -------------------------------------------------------------------------------- /src/example-flows/CustomConnectionLine/ConnectionLine.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default ({ 4 | sourceX, 5 | sourceY, 6 | sourcePosition, 7 | targetX, 8 | targetY, 9 | targetPosition, 10 | connectionLineType, 11 | connectionLineStyle, 12 | }) => { 13 | return ( 14 | 15 | 22 | 23 | 24 | ); 25 | }; 26 | -------------------------------------------------------------------------------- /src/components/Close/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from '@emotion/styled'; 3 | import { Flex } from 'reflexbox'; 4 | 5 | import { getThemeSpacePx } from 'utils/css-utils'; 6 | import Icon from 'components/Icon'; 7 | 8 | const Close = styled(Flex)` 9 | padding: ${getThemeSpacePx(1)}; 10 | line-height: 1; 11 | width: 50px; 12 | height: 50px; 13 | `; 14 | 15 | export default ({ onClick, ...props }) => { 16 | return ( 17 | 18 | 19 | 20 | 21 | 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /src/example-flows/Validation/validation.css: -------------------------------------------------------------------------------- 1 | .validationflow .react-flow__node { 2 | width: 150px; 3 | border-radius: 5px; 4 | padding: 10px; 5 | color: #555; 6 | border: 1px solid #ddd; 7 | text-align: center; 8 | font-size: 12px; 9 | } 10 | 11 | .validationflow .react-flow__node-customnode { 12 | background: #e6e6e9; 13 | border: 1px solid #ddd; 14 | } 15 | 16 | .react-flow__node-custominput .react-flow__handle { 17 | background: #e6e6e9; 18 | } 19 | 20 | .validationflow .react-flow__node-custominput { 21 | background: #fff; 22 | 23 | } 24 | 25 | .validationflow .react-flow__handle-connecting { 26 | background: #ff6060; 27 | } 28 | 29 | .validationflow .react-flow__handle-valid { 30 | background: #55dd99; 31 | } -------------------------------------------------------------------------------- /src/example-flows/ZoomPanHelper/zoompanhelper.css: -------------------------------------------------------------------------------- 1 | .zoompanflow { 2 | flex-direction: column; 3 | display: flex; 4 | flex-grow: 1; 5 | } 6 | 7 | .zoompanflow aside { 8 | border-left: 1px solid #eee; 9 | padding: 15px 10px; 10 | font-size: 12px; 11 | background: #fff; 12 | } 13 | 14 | .zoompanflow aside .description { 15 | margin-bottom: 10px; 16 | } 17 | 18 | .zoompanflow aside button { 19 | display: block; 20 | margin-bottom: 5px; 21 | } 22 | 23 | .zoompanflow .reactflow-wrapper { 24 | flex-grow: 1; 25 | } 26 | 27 | @media screen and (min-width: 768px) { 28 | .zoompanflow { 29 | flex-direction: row; 30 | } 31 | 32 | .zoompanflow aside { 33 | width: 20%; 34 | max-width: 250px; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/components/Page/Doc.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from '@emotion/styled'; 3 | import { Flex, Box } from 'reflexbox'; 4 | 5 | import Page from 'components/Page'; 6 | import Sidebar from 'components/Sidebar'; 7 | 8 | const Wrapper = styled(Flex)` 9 | border-top: 1px solid ${(p) => p.theme.colors.silverLighten30}; 10 | `; 11 | 12 | const DocWrapper = styled(Box)` 13 | max-width: 620px; 14 | margin: 0 auto; 15 | position: relative; 16 | padding: 0 16px; 17 | `; 18 | 19 | export default ({ children, menu = [], ...rest }) => ( 20 | 21 | 22 | 23 | {children} 24 | 25 | 26 | ); 27 | -------------------------------------------------------------------------------- /src/hooks/useShowcaseImages.js: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react'; 2 | import { useStaticQuery, graphql } from 'gatsby'; 3 | 4 | export default function useFeaturedProjects() { 5 | const rawData = useStaticQuery(graphql` 6 | query ShowcaseImages { 7 | allShowcasesJson { 8 | edges { 9 | node { 10 | title 11 | url 12 | image { 13 | childImageSharp { 14 | gatsbyImageData(layout: CONSTRAINED, width: 600) 15 | } 16 | } 17 | } 18 | } 19 | } 20 | } 21 | `); 22 | 23 | const images = useMemo( 24 | () => rawData.allShowcasesJson.edges.map(({ node }) => node), 25 | [rawData] 26 | ); 27 | 28 | return images; 29 | } 30 | -------------------------------------------------------------------------------- /src/components/ContentSection/index.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | import { Box } from 'reflexbox'; 3 | 4 | import theme from 'themes/index'; 5 | 6 | import CenterContent from 'components/CenterContent'; 7 | 8 | export default ({ 9 | children, 10 | bg = 'transparent', 11 | centered = false, 12 | id = null, 13 | big = false, 14 | ...rest 15 | }) => { 16 | const WrapperComponent = centered ? CenterContent : Fragment; 17 | const wrapperProps = centered ? { big: big } : {}; 18 | 19 | return ( 20 | 26 | {children} 27 | 28 | ); 29 | }; 30 | -------------------------------------------------------------------------------- /src/assets/icons/eye.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/example-flows/DragNDrop/Sidebar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default () => { 4 | const onDragStart = (event, nodeType) => { 5 | event.dataTransfer.setData('application/reactflow', nodeType); 6 | event.dataTransfer.effectAllowed = 'move'; 7 | }; 8 | 9 | return ( 10 | 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /src/example-flows/Provider/provider.css: -------------------------------------------------------------------------------- 1 | .providerflow { 2 | flex-direction: column; 3 | display: flex; 4 | flex-grow: 1; 5 | } 6 | 7 | .providerflow aside { 8 | border-left: 1px solid #eee; 9 | padding: 15px 10px; 10 | font-size: 12px; 11 | background: #fff; 12 | } 13 | 14 | .providerflow aside .description { 15 | margin-bottom: 10px; 16 | } 17 | 18 | .providerflow aside .title { 19 | font-weight: 700; 20 | margin-bottom: 5px; 21 | } 22 | 23 | .providerflow aside .transform { 24 | margin-bottom: 20px; 25 | } 26 | 27 | .providerflow .reactflow-wrapper { 28 | flex-grow: 1; 29 | } 30 | 31 | .providerflow .selectall { 32 | margin-top: 10px; 33 | } 34 | 35 | @media screen and (min-width: 768px) { 36 | .providerflow { 37 | flex-direction: row; 38 | } 39 | 40 | .providerflow aside { 41 | width: 20%; 42 | max-width: 250px; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/example-flows/Edges/CustomEdge.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { getBezierPath, getMarkerEnd } from 'react-flow-renderer'; 3 | 4 | export default function CustomEdge({ 5 | id, 6 | sourceX, 7 | sourceY, 8 | targetX, 9 | targetY, 10 | sourcePosition, 11 | targetPosition, 12 | style = {}, 13 | data, 14 | arrowHeadType, 15 | markerEndId, 16 | }) { 17 | const edgePath = getBezierPath({ sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition }); 18 | const markerEnd = getMarkerEnd(arrowHeadType, markerEndId); 19 | 20 | return ( 21 | <> 22 | 23 | 24 | 25 | {data.text} 26 | 27 | 28 | 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /src/components/Logo/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from '@emotion/styled'; 3 | import { useTheme, jsx } from '@emotion/react'; 4 | 5 | import WbkdLogoWhite from 'assets/images/logo-white.svg'; 6 | import WbkdLogoBlack from 'assets/images/logo.svg'; 7 | 8 | const Image = styled.img` 9 | display: block; 10 | width: 75px; 11 | `; 12 | 13 | const getLogoSrc = (type, inverted, theme) => { 14 | if (type) { 15 | return type === 'white' ? WbkdLogoWhite : WbkdLogoBlack; 16 | } 17 | 18 | if (inverted) { 19 | return theme.name === 'light' ? WbkdLogoWhite : WbkdLogoBlack; 20 | } 21 | 22 | return theme.name === 'light' ? WbkdLogoBlack : WbkdLogoWhite; 23 | }; 24 | 25 | export default ({ type = null, inverted = false, style = {} }) => { 26 | const theme = useTheme(); 27 | const logoSrc = getLogoSrc(type, inverted, theme); 28 | 29 | return webkid logo; 30 | }; 31 | -------------------------------------------------------------------------------- /src/components/SectionIntro/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from '@emotion/styled'; 3 | import { Box } from 'reflexbox'; 4 | 5 | import { H1, H4 } from 'components/Typo'; 6 | import { getThemeSpacePx, getThemeColor } from 'utils/css-utils'; 7 | 8 | const SectionIntroWrapper = styled(Box)` 9 | text-align: center; 10 | max-width: 750px; 11 | margin: 0 auto; 12 | 13 | ${H1} { 14 | margin: 0 0 ${getThemeSpacePx(3)} 0; 15 | } 16 | `; 17 | 18 | const SectionSubtitle = styled(H4)` 19 | font-weight: 400; 20 | line-height: 1.5; 21 | color: ${getThemeColor('silverDarken30')}; 22 | `; 23 | 24 | const SectionIntro = ({ title = '', text = '', ...props }) => { 25 | return ( 26 | 27 |

{title}

28 | {text && {text}} 29 |
30 | ); 31 | }; 32 | 33 | export default SectionIntro; 34 | -------------------------------------------------------------------------------- /src/components/CodeBlock/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from '@emotion/styled'; 3 | import { Box } from 'reflexbox'; 4 | 5 | import { colors } from 'themes'; 6 | import CodeBlock from './Mdx'; 7 | import { H4, AttributionText } from 'components/Typo'; 8 | 9 | const Wrapper = styled(Box)` 10 | margin: 0 auto; 11 | padding: 5px 0; 12 | 13 | h4 { 14 | margin-bottom: 10px; 15 | } 16 | 17 | pre { 18 | margin: 0; 19 | font-size: 14px; 20 | } 21 | 22 | code { 23 | border: 1px solid ${colors.lightGrey}; 24 | border-radius: 3px; 25 | } 26 | `; 27 | 28 | export default ({ 29 | language = 'javascript', 30 | code, 31 | title = '', 32 | subtitle = '', 33 | }) => { 34 | return ( 35 | 36 | {title &&

{title}

} 37 | {code} 38 | {subtitle && {subtitle}} 39 |
40 | ); 41 | }; 42 | -------------------------------------------------------------------------------- /src/example-flows/Stress/utils.js: -------------------------------------------------------------------------------- 1 | export function getElements(xElements = 10, yElements = 10) { 2 | const initialElements = []; 3 | let nodeId = 1; 4 | let recentNodeId = null; 5 | 6 | for (let y = 0; y < yElements; y++) { 7 | for (let x = 0; x < xElements; x++) { 8 | const position = { x: x * 100, y: y * 50 }; 9 | const data = { label: `Node ${nodeId}` }; 10 | const node = { 11 | id: `stress-${nodeId.toString()}`, 12 | style: { width: 50, fontSize: 11 }, 13 | data, 14 | position, 15 | }; 16 | initialElements.push(node); 17 | 18 | if (recentNodeId && nodeId <= xElements * yElements) { 19 | initialElements.push({ 20 | id: `${x}-${y}`, 21 | source: `stress-${recentNodeId.toString()}`, 22 | target: `stress-${nodeId.toString()}`, 23 | }); 24 | } 25 | 26 | recentNodeId = nodeId; 27 | nodeId++; 28 | } 29 | } 30 | 31 | return initialElements; 32 | } 33 | -------------------------------------------------------------------------------- /src/example-flows/ZoomPanHelper/Sidebar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useStore, useZoomPanHelper } from 'react-flow-renderer'; 3 | 4 | export default () => { 5 | const store = useStore(); 6 | const { zoomIn, zoomOut, setCenter } = useZoomPanHelper(); 7 | 8 | const focusNode = () => { 9 | const { nodes } = store.getState(); 10 | 11 | if (nodes.length) { 12 | const node = nodes[0]; 13 | 14 | const x = node.__rf.position.x + node.__rf.width / 2; 15 | const y = node.__rf.position.y + node.__rf.height / 2; 16 | const zoom = 1.85; 17 | 18 | setCenter(x, y, zoom); 19 | } 20 | }; 21 | 22 | return ( 23 | 31 | ); 32 | }; 33 | -------------------------------------------------------------------------------- /src/utils/project-utils.js: -------------------------------------------------------------------------------- 1 | export const parseProjectDate = (dateString) => { 2 | const parts = dateString.split('/'); 3 | return new Date(+parts[0], +parts[1] - 1, +parts[2]); 4 | }; 5 | 6 | export const groupProjectsByYear = (projects) => { 7 | return projects.reduce((grouped, project) => { 8 | const year = project.date.getFullYear(); 9 | grouped[year] = grouped.hasOwnProperty(year) 10 | ? grouped[year].concat([project]) 11 | : [project]; 12 | return grouped; 13 | }, {}); 14 | }; 15 | 16 | export const getMainCategory = (categoryArray = []) => { 17 | const matchingCategory = mainTags.find((mc) => 18 | categoryArray.find((cat) => mc.id === cat) 19 | ); 20 | 21 | return matchingCategory ? matchingCategory.id : null; 22 | }; 23 | 24 | export const shuffleProjects = (projects) => { 25 | return projects.sort((a, b) => Math.random() - 0.5); 26 | }; 27 | 28 | export default { 29 | parseProjectDate, 30 | groupProjectsByYear, 31 | getMainCategory, 32 | shuffleProjects, 33 | }; 34 | -------------------------------------------------------------------------------- /src/example-flows/DragHandle/DragHandleNode.tsx: -------------------------------------------------------------------------------- 1 | import React, { memo, FC } from 'react'; 2 | 3 | import { 4 | Handle, 5 | Position, 6 | NodeProps, 7 | Connection, 8 | Edge, 9 | } from 'react-flow-renderer'; 10 | 11 | const onConnect = (params: Connection | Edge) => 12 | console.log('handle onConnect', params); 13 | 14 | const labelStyle = { 15 | display: 'flex', 16 | alignItems: 'center', 17 | }; 18 | 19 | const dragHandleStyle = { 20 | display: 'inline-block', 21 | width: 25, 22 | height: 25, 23 | backgroundColor: 'teal', 24 | marginLeft: 5, 25 | borderRadius: '50%', 26 | }; 27 | 28 | const ColorSelectorNode: FC = () => { 29 | return ( 30 | <> 31 | 32 |
33 | Only draggable here →{' '} 34 | 35 |
36 | 37 | 38 | ); 39 | }; 40 | 41 | export default memo(ColorSelectorNode); 42 | -------------------------------------------------------------------------------- /src/example-flows/CustomConnectionLine/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import ReactFlow, { 3 | removeElements, 4 | addEdge, 5 | Background, 6 | } from 'react-flow-renderer'; 7 | 8 | import ConnectionLine from './ConnectionLine'; 9 | 10 | const initialElements = [ 11 | { 12 | id: 'connectionline-1', 13 | type: 'input', 14 | data: { label: 'Node 1' }, 15 | position: { x: 250, y: 5 }, 16 | }, 17 | ]; 18 | 19 | const ConnectionLineFlow = () => { 20 | const [elements, setElements] = useState(initialElements); 21 | const onElementsRemove = (elementsToRemove) => 22 | setElements((els) => removeElements(elementsToRemove, els)); 23 | const onConnect = (params) => setElements((els) => addEdge(params, els)); 24 | 25 | return ( 26 | 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default ConnectionLineFlow; 38 | -------------------------------------------------------------------------------- /src/markdown/docs/api/components/background.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Background 3 | --- 4 | 5 | React Flow comes with two background variants: **dots** and **lines**. You can use it by passing it as a children to the `ReactFlow` component: 6 | 7 | ### Usage 8 | 9 | ```jsx 10 | import ReactFlow, { Background } from 'react-flow-renderer'; 11 | 12 | const FlowWithBackground = () => ( 13 | 14 | 19 | 20 | ); 21 | ``` 22 | 23 | 24 | ### Prop Types 25 | 26 | - `variant`: string - has to be 'dots' or 'lines' - default: `dots` 27 | - `gap`: number - the gap between the dots or lines - default: `16` 28 | - `size`: number - the radius of the dots or the stroke width of the lines - default: `0.5` 29 | - `color`: string - the color of the dots or lines - default: `#81818a` for dots, `#eee` for lines 30 | - `style`: css properties 31 | - `className`: additional class name 32 | 33 | **Typescript:** The interface of the Background Prop Types are exported as `BackgroundProps`. -------------------------------------------------------------------------------- /src/example-flows/DragNDrop/dnd.css: -------------------------------------------------------------------------------- 1 | .dndflow { 2 | flex-direction: column; 3 | display: flex; 4 | flex-grow: 1; 5 | } 6 | 7 | .dndflow aside { 8 | border-right: 1px solid #eee; 9 | padding: 15px 10px; 10 | font-size: 12px; 11 | background: #fcfcfc; 12 | } 13 | 14 | .dndflow aside .description { 15 | margin-bottom: 10px; 16 | } 17 | 18 | .dndflow .dndnode { 19 | height: 20px; 20 | padding: 4px; 21 | border: 1px solid #1a192b; 22 | border-radius: 2px; 23 | margin-bottom: 10px; 24 | display: flex; 25 | justify-content: center; 26 | align-items: center; 27 | cursor: grab; 28 | } 29 | 30 | .dndflow .dndnode.input { 31 | border-color: #0041d0; 32 | } 33 | 34 | .dndflow .dndnode.output { 35 | border-color: #ff0072; 36 | } 37 | 38 | .dndflow .reactflow-wrapper { 39 | flex-grow: 1; 40 | height: 100%; 41 | } 42 | 43 | .dndflow .selectall { 44 | margin-top: 10px; 45 | } 46 | 47 | @media screen and (min-width: 768px) { 48 | .dndflow { 49 | flex-direction: row; 50 | } 51 | 52 | .dndflow aside { 53 | width: 20%; 54 | max-width: 250px; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/markdown/docs/getting-started/Basic.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactFlow, { ReactFlowProvider } from 'react-flow-renderer'; 3 | 4 | const elements = [ 5 | // input node 6 | { 7 | id: '1', 8 | type: 'input', 9 | data: { label: 'Input Node' }, 10 | position: { x: 250, y: 25 }, 11 | }, 12 | // default node 13 | { 14 | id: '2', 15 | // you can also pass a React component as a label 16 | data: { label:
Default Node
}, 17 | position: { x: 100, y: 125 }, 18 | }, 19 | // output node 20 | { 21 | id: '3', 22 | type: 'output', 23 | // you can also pass a React component as a label 24 | data: { label: 'Output Node' }, 25 | position: { x: 250, y: 250 }, 26 | }, 27 | { id: 'e1-2', source: '1', target: '2', animated: true }, 28 | { id: 'e2-3', source: '2', target: '3' }, 29 | ]; 30 | 31 | export default () => ( 32 |
33 | 34 | 35 | 36 |
37 | ); 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) webkid GmbH 2019-2022 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/example-flows/FloatingEdges/FloatingConnectionLine.tsx: -------------------------------------------------------------------------------- 1 | import { FC } from 'react'; 2 | import { getBezierPath, ConnectionLineComponentProps, Node } from 'react-flow-renderer'; 3 | 4 | import { getEdgeParams } from './utils'; 5 | 6 | const FloatingConnectionLine: FC = ({ 7 | targetX, 8 | targetY, 9 | sourcePosition, 10 | targetPosition, 11 | sourceNode, 12 | }) => { 13 | if (!sourceNode) { 14 | return null; 15 | } 16 | 17 | const targetNode = { 18 | id: 'connection-target', 19 | __rf: { width: 1, height: 1, position: { x: targetX, y: targetY } }, 20 | } as Node; 21 | 22 | const { sx, sy } = getEdgeParams(sourceNode, targetNode); 23 | const d = getBezierPath({ 24 | sourceX: sx, 25 | sourceY: sy, 26 | sourcePosition, 27 | targetPosition, 28 | targetX, 29 | targetY, 30 | }); 31 | 32 | return ( 33 | 34 | 35 | 36 | 37 | ); 38 | }; 39 | 40 | export default FloatingConnectionLine; 41 | -------------------------------------------------------------------------------- /src/example-flows/EdgeTypes/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Example for checking the different edge types and source and target positions 3 | */ 4 | import React, { useState } from 'react'; 5 | 6 | import ReactFlow, { removeElements, addEdge, MiniMap, Controls, Background } from 'react-flow-renderer'; 7 | import { getElements } from './utils'; 8 | 9 | const onLoad = (reactFlowInstance) => { 10 | reactFlowInstance.fitView(); 11 | console.log(reactFlowInstance.getElements()); 12 | }; 13 | 14 | const initialElements = getElements(); 15 | 16 | const EdgeTypesFlow = () => { 17 | const [elements, setElements] = useState(initialElements); 18 | const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els)); 19 | const onConnect = (params) => setElements((els) => addEdge(params, els)); 20 | 21 | return ( 22 | 29 | 30 | 31 | 32 | 33 | ); 34 | }; 35 | 36 | export default EdgeTypesFlow; 37 | -------------------------------------------------------------------------------- /src/example-flows/CustomNode/ColorSelectorNode.js: -------------------------------------------------------------------------------- 1 | import React, { memo } from 'react'; 2 | 3 | import { Handle } from 'react-flow-renderer'; 4 | 5 | export default memo(({ data, isConnectable }) => { 6 | return ( 7 | <> 8 | console.log('handle onConnect', params)} 13 | isConnectable={isConnectable} 14 | /> 15 |
16 | Custom Color Picker Node: {data.color} 17 |
18 | 24 | 31 | 38 | 39 | ); 40 | }); 41 | -------------------------------------------------------------------------------- /src/markdown/docs/getting-started/BasicFunctions.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import ReactFlow, { 3 | removeElements, 4 | addEdge, 5 | ReactFlowProvider, 6 | } from 'react-flow-renderer'; 7 | 8 | const initialElements = [ 9 | { 10 | id: '1', 11 | type: 'input', 12 | data: { label: 'Input Node' }, 13 | position: { x: 250, y: 25 }, 14 | }, 15 | { 16 | id: '2', 17 | data: { label: 'Another Node' }, 18 | position: { x: 100, y: 125 }, 19 | }, 20 | ]; 21 | 22 | const BasicFlow = () => { 23 | const [elements, setElements] = useState(initialElements); 24 | const onElementsRemove = (elementsToRemove) => 25 | setElements((els) => removeElements(elementsToRemove, els)); 26 | const onConnect = (params) => setElements((els) => addEdge(params, els)); 27 | 28 | return ( 29 |
30 | 31 | 36 | 37 |
38 | ); 39 | }; 40 | 41 | export default BasicFlow; 42 | -------------------------------------------------------------------------------- /src/assets/icons/twitter_circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/themes/global.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useTheme, Global, css, jsx } from '@emotion/react'; 3 | 4 | const GlobalStyle = () => { 5 | const theme = useTheme(); 6 | 7 | const globalStyles = css` 8 | html, 9 | body { 10 | background-color: ${theme.colors.background}; 11 | font-family: ${theme.fonts.sans}; 12 | font-weight: 400; 13 | letter-spacing: 0.5px; 14 | line-height: 1.5; 15 | font-size: 16px; 16 | padding: 0; 17 | margin: 0; 18 | min-height: 100vh; 19 | } 20 | 21 | a { 22 | color: ${theme.colors.red}; 23 | text-decoration: none; 24 | } 25 | 26 | a:visited, 27 | a:focus, 28 | a:active { 29 | color: ${theme.colors.red}; 30 | text-decoration: none; 31 | } 32 | 33 | a:hover { 34 | color: ${theme.colors.red}; 35 | text-decoration: none; 36 | } 37 | 38 | .fullOpacity { 39 | opacity: 1; 40 | } 41 | 42 | code, 43 | pre { 44 | font-family: ${theme.fonts.mono}; 45 | background: rgb(246, 248, 250); 46 | padding: 2px 6px; 47 | border-radius: 5px; 48 | } 49 | `; 50 | 51 | return ; 52 | }; 53 | 54 | export default GlobalStyle; 55 | -------------------------------------------------------------------------------- /src/markdown/docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction 3 | --- 4 | 5 | React Flow is a library for building node-based applications. These can be simple static diagrams or complex node-based editors. You can implement custom node types and edge types and it comes with components like a mini-map and graph controls. Feel free to check out the [examples](https://reactflow.dev/examples/) or read the [blog post](https://webkid.io/blog/react-flow-node-based-graph-library/) to get started. 6 | 7 | ## Key Features 8 | 9 | * **Easy to use:** Seamless zooming & panning behaviour and single and multi-selections of elements 10 | * **Customizable:** Different [node](/docs/api/node-types/) and [edge types](/docs/api/edge-types) and support for custom nodes with multiple handles and custom edges 11 | * **Fast rendering:** Only nodes that have changed are re-rendered and only those that are in the viewport are displayed 12 | * **Utils:** Snap-to-grid and graph [helper functions](/docs/api/helper-functions/) 13 | * **Components:** [Background](/docs/api/components/background/), [Minimap](/docs/api/components/minimap/) and [Controls](/docs/api/components/controls/) 14 | * **Reliable**: Written in [Typescript](https://www.typescriptlang.org/) and tested with [cypress](https://www.cypress.io/) 15 | -------------------------------------------------------------------------------- /src/example-flows/FloatingEdges/FloatingEdge.tsx: -------------------------------------------------------------------------------- 1 | import { FC, useMemo, CSSProperties } from 'react'; 2 | import { EdgeProps, getMarkerEnd, useStoreState, getBezierPath } from 'react-flow-renderer'; 3 | 4 | import { getEdgeParams } from './utils'; 5 | 6 | const FloatingEdge: FC = ({ id, source, target, arrowHeadType, markerEndId, style }) => { 7 | const nodes = useStoreState((state) => state.nodes); 8 | const markerEnd = getMarkerEnd(arrowHeadType, markerEndId); 9 | 10 | const sourceNode = useMemo(() => nodes.find((n) => n.id === source), [source, nodes]); 11 | const targetNode = useMemo(() => nodes.find((n) => n.id === target), [target, nodes]); 12 | 13 | if (!sourceNode || !targetNode) { 14 | return null; 15 | } 16 | 17 | const { sx, sy, tx, ty, sourcePos, targetPos } = getEdgeParams(sourceNode, targetNode); 18 | 19 | const d = getBezierPath({ 20 | sourceX: sx, 21 | sourceY: sy, 22 | sourcePosition: sourcePos, 23 | targetPosition: targetPos, 24 | targetX: tx, 25 | targetY: ty, 26 | }); 27 | 28 | return ( 29 | 30 | 31 | 32 | ); 33 | }; 34 | 35 | export default FloatingEdge; 36 | -------------------------------------------------------------------------------- /src/assets/icons/favicon_stroke.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/example-flows/Provider/Sidebar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useStoreState, useStoreActions } from 'react-flow-renderer'; 3 | 4 | export default () => { 5 | const nodes = useStoreState((store) => store.nodes); 6 | const transform = useStoreState((store) => store.transform); 7 | const setSelectedElements = useStoreActions((actions) => actions.setSelectedElements); 8 | 9 | const selectAll = () => { 10 | setSelectedElements(nodes.map((node) => ({ id: node.id, type: node.type }))); 11 | }; 12 | 13 | return ( 14 | 33 | ); 34 | }; 35 | -------------------------------------------------------------------------------- /src/markdown/docs/api/components/minimap.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Mini Map 3 | --- 4 | 5 | You can use the mini map plugin by passing it as a children to the `ReactFlow` component: 6 | 7 | ### Usage 8 | 9 | ```jsx 10 | import ReactFlow, { MiniMap } from 'react-flow-renderer'; 11 | 12 | const FlowWithMiniMap = () => ( 13 | 14 | { 16 | switch (node.type) { 17 | case 'input': 18 | return 'red'; 19 | case 'default': 20 | return '#00ff00'; 21 | case 'output': 22 | return 'rgb(0,0,255)'; 23 | default: 24 | return '#eee'; 25 | } 26 | }} 27 | nodeStrokeWidth={3} 28 | /> 29 | 30 | ); 31 | ``` 32 | 33 | ### Prop Types 34 | 35 | - `nodeColor`: string or function - If you pass a color as a string all nodes will get that color. If you pass a function you can return a color depending on the passed node. 36 | - `nodeBorderRadius`: number 37 | - `nodeStrokeWidth`: number 38 | - `nodeClassName`: string or function for adding an additional class to the nodes inside the mini map 39 | - `maskColor`: string 40 | - `style`: css properties 41 | - `className`: additional class name 42 | 43 | **Typescript:** The interface of the MiniMap Prop Types are exported as `MiniMapProps`. 44 | -------------------------------------------------------------------------------- /src/components/Page/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from '@emotion/styled'; 3 | import { ThemeProvider, jsx } from '@emotion/react'; 4 | import { Flex, Box } from 'reflexbox'; 5 | 6 | import Header from 'components/Header'; 7 | import Footer from 'components/Footer'; 8 | import themes from 'themes'; 9 | 10 | import NormalizeStyle from 'themes/normalize'; 11 | import GlobalStyle from 'themes/global'; 12 | import MetaTags from './MetaTags'; 13 | import { getThemeColor } from 'utils/css-utils'; 14 | 15 | const PageWrapper = styled(Flex)` 16 | color: ${getThemeColor('text')}; 17 | width: 100%; 18 | position: relative; 19 | flex-direction: column; 20 | height: 100vh; 21 | position: relative; 22 | `; 23 | 24 | const PageContent = styled(Box)` 25 | flex: 1 0 auto; 26 | `; 27 | 28 | const Page = ({ 29 | children, 30 | theme = 'light', 31 | metaTags, 32 | footerBorder = false, 33 | ...rest 34 | }) => { 35 | const pageTheme = themes[theme]; 36 | 37 | return ( 38 | 39 | 40 | 41 | 42 | 43 |
44 | {children} 45 |