* fix(ts): use strict mode strictNullChecks etc

* chore: Use extended React.HTMLAttributes<> (#41)

* refactor(code-format): add prettier closes #42

* feat(renderer): add snap to grid option closes #20

* chore(dependabot): use develop as target branch
This commit is contained in:
Moritz
2019-10-21 20:58:28 +02:00
committed by GitHub
parent ce210eb5dc
commit a793f8c2ff
80 changed files with 2634 additions and 1247 deletions
+156 -92
View File
@@ -3,7 +3,15 @@ import React, { memo, SVGAttributes } from 'react';
import { useStoreState } from '../../store/hooks';
import ConnectionLine from '../../components/ConnectionLine/index';
import { isEdge } from '../../utils/graph';
import { XYPosition, Position, Edge, Node, ElementId, Transform, HandleElement } from '../../types';
import {
XYPosition,
Position,
Edge,
Node,
ElementId,
Transform,
HandleElement,
} from '../../types';
interface EdgeRendererProps {
width: number;
@@ -12,69 +20,82 @@ interface EdgeRendererProps {
connectionLineStyle?: SVGAttributes<{}>;
connectionLineType?: string;
onElementClick?: () => void;
};
}
interface EdgeRendererState {
nodes: Node[];
edges: Edge[];
transform: Transform;
selectedElements: any;
connectionSourceId: ElementId | null;
connectionSourceId: ElementId | null;
position: XYPosition;
};
}
interface EdgePositions {
sourceX: number;
sourceY: number;
targetX: number;
targetY: number;
};
}
function getHandlePosition(position: Position, node: Node, handle: any | null = null): XYPosition {
function getHandlePosition(
position: Position,
node: Node,
handle: any | null = null
): XYPosition {
if (!handle) {
switch (position) {
case 'top': return {
x: node.__rg.width / 2,
y: 0
};
case 'right': return {
x: node.__rg.width,
y: node.__rg.height / 2
};
case 'bottom': return {
x: node.__rg.width / 2,
y: node.__rg.height
};
case 'left': return {
x: 0,
y: node.__rg.height / 2
};
case 'top':
return {
x: node.__rg.width / 2,
y: 0,
};
case 'right':
return {
x: node.__rg.width,
y: node.__rg.height / 2,
};
case 'bottom':
return {
x: node.__rg.width / 2,
y: node.__rg.height,
};
case 'left':
return {
x: 0,
y: node.__rg.height / 2,
};
}
return null;
}
switch (position) {
case 'top': return {
x: handle.x + (handle.width / 2),
y: handle.y
};
case 'right': return {
x: handle.x + handle.width,
y: handle.y + (handle.height / 2)
};
case 'bottom': return {
x: handle.x + (handle.width / 2),
y: handle.y + handle.height
};
case 'left': return {
x: handle.x,
y: handle.y + (handle.height / 2)
};
case 'top':
return {
x: handle.x + handle.width / 2,
y: handle.y,
};
case 'right':
return {
x: handle.x + handle.width,
y: handle.y + handle.height / 2,
};
case 'bottom':
return {
x: handle.x + handle.width / 2,
y: handle.y + handle.height,
};
case 'left':
return {
x: handle.x,
y: handle.y + handle.height / 2,
};
}
}
function getHandle(bounds: HandleElement[], handleId: ElementId): HandleElement | null {
function getHandle(
bounds: HandleElement[],
handleId: ElementId | null
): HandleElement | null | undefined {
let handle = null;
if (!bounds) {
@@ -83,7 +104,7 @@ function getHandle(bounds: HandleElement[], handleId: ElementId): HandleElement
// there is no handleId when there are no multiple handles/ handles with ids
// so we just pick the first one
if (bounds.length === 1 || !handleId) {
if (bounds.length === 1 || !handleId) {
handle = bounds[0];
} else if (handleId) {
handle = bounds.find(d => d.id === handleId);
@@ -93,23 +114,42 @@ function getHandle(bounds: HandleElement[], handleId: ElementId): HandleElement
}
function getEdgePositions(
sourceNode: Node, sourceHandle: HandleElement, sourcePosition: Position,
targetNode: Node, targetHandle: HandleElement, targetPosition: Position
sourceNode: Node,
sourceHandle: HandleElement | unknown,
sourcePosition: Position,
targetNode: Node,
targetHandle: HandleElement | unknown,
targetPosition: Position
): EdgePositions {
const sourceHandlePos = getHandlePosition(sourcePosition, sourceNode, sourceHandle)
const sourceHandlePos = getHandlePosition(
sourcePosition,
sourceNode,
sourceHandle
);
const sourceX = sourceNode.__rg.position.x + sourceHandlePos.x;
const sourceY = sourceNode.__rg.position.y + sourceHandlePos.y;
const targetHandlePos = getHandlePosition(targetPosition, targetNode, targetHandle);
const targetHandlePos = getHandlePosition(
targetPosition,
targetNode,
targetHandle
);
const targetX = targetNode.__rg.position.x + targetHandlePos.x;
const targetY = targetNode.__rg.position.y + targetHandlePos.y;
return {
sourceX, sourceY, targetX, targetY
sourceX,
sourceY,
targetX,
targetY,
};
}
function renderEdge(edge: Edge, props: EdgeRendererProps, state: EdgeRendererState) {
function renderEdge(
edge: Edge,
props: EdgeRendererProps,
state: EdgeRendererState
) {
const edgeType = edge.type || 'default';
const hasSourceHandleId = edge.source.includes('__');
@@ -133,14 +173,24 @@ function renderEdge(edge: Edge, props: EdgeRendererProps, state: EdgeRendererSta
}
const EdgeComponent = props.edgeTypes[edgeType] || props.edgeTypes.default;
const sourceHandle = getHandle(sourceNode.__rg.handleBounds.source, sourceHandleId);
const targetHandle = getHandle(targetNode.__rg.handleBounds.target, targetHandleId);
const sourceHandle = getHandle(
sourceNode.__rg.handleBounds.source,
sourceHandleId
);
const targetHandle = getHandle(
targetNode.__rg.handleBounds.target,
targetHandleId
);
const sourcePosition = sourceHandle ? sourceHandle.position : 'bottom';
const targetPosition = targetHandle ? targetHandle.position : 'top';
const { sourceX, sourceY, targetX, targetY } = getEdgePositions(
sourceNode, sourceHandle, sourcePosition,
targetNode, targetHandle, targetPosition
sourceNode,
sourceHandle,
sourcePosition,
targetNode,
targetHandle,
targetPosition
);
const selected = state.selectedElements
.filter(isEdge)
@@ -169,47 +219,61 @@ function renderEdge(edge: Edge, props: EdgeRendererProps, state: EdgeRendererSta
);
}
const EdgeRenderer = memo(({
width, height, connectionLineStyle, connectionLineType, ...rest
}: EdgeRendererProps) => {
const state: EdgeRendererState = useStoreState(s => ({
nodes: s.nodes,
edges: s.edges,
transform: s.transform,
selectedElements: s.selectedElements,
connectionSourceId: s.connectionSourceId,
position: s.connectionPosition
}));
if (!width) {
return null;
const EdgeRenderer = memo(
({
width,
height,
connectionLineStyle,
connectionLineType,
...rest
}: EdgeRendererProps) => {
const state: EdgeRendererState = useStoreState(s => ({
nodes: s.nodes,
edges: s.edges,
transform: s.transform,
selectedElements: s.selectedElements,
connectionSourceId: s.connectionSourceId,
position: s.connectionPosition,
}));
if (!width) {
return null;
}
const { transform, edges, nodes, connectionSourceId, position } = state;
const transformStyle = `translate(${transform[0]},${transform[1]}) scale(${transform[2]})`;
return (
<svg width={width} height={height} className="react-flow__edges">
<g transform={transformStyle}>
{edges.map((e: Edge) =>
renderEdge(
e,
{
width,
height,
connectionLineStyle,
connectionLineType,
...rest,
},
state
)
)}
{connectionSourceId && (
<ConnectionLine
nodes={nodes}
connectionSourceId={connectionSourceId}
connectionPositionX={position.x}
connectionPositionY={position.y}
transform={transform}
connectionLineStyle={connectionLineStyle}
connectionLineType={connectionLineType}
/>
)}
</g>
</svg>
);
}
const { transform, edges, nodes, connectionSourceId, position } = state;
const transformStyle = `translate(${transform[0]},${transform[1]}) scale(${transform[2]})`;
return (
<svg
width={width}
height={height}
className="react-flow__edges"
>
<g transform={transformStyle}>
{edges.map((e: Edge) => renderEdge(e, { width, height, connectionLineStyle, connectionLineType, ...rest }, state))}
{connectionSourceId && (
<ConnectionLine
nodes={nodes}
connectionSourceId={connectionSourceId}
connectionPositionX={position.x}
connectionPositionY={position.y}
transform={transform}
connectionLineStyle={connectionLineStyle}
connectionLineType={connectionLineType}
/>
)}
</g>
</svg>
);
});
);
EdgeRenderer.displayName = 'EdgeRenderer';
+15 -9
View File
@@ -4,25 +4,31 @@ import StraightEdge from '../../components/Edges/StraightEdge';
import BezierEdge from '../../components/Edges/BezierEdge';
import wrapEdge from '../../components/Edges/wrapEdge';
import { EdgeTypesType, EdgeWrapperProps } from '../../types';
import { EdgeTypesType, EdgeCompProps } from '../../types';
export function createEdgeTypes(edgeTypes: EdgeTypesType): EdgeTypesType{
export function createEdgeTypes(edgeTypes: EdgeTypesType): EdgeTypesType {
const standardTypes: EdgeTypesType = {
default: wrapEdge((edgeTypes.default || BezierEdge) as ComponentType<EdgeWrapperProps>),
straight: wrapEdge((edgeTypes.bezier || StraightEdge) as ComponentType<EdgeWrapperProps>)
default: wrapEdge((edgeTypes.default || BezierEdge) as ComponentType<
EdgeCompProps
>),
straight: wrapEdge((edgeTypes.bezier || StraightEdge) as ComponentType<
EdgeCompProps
>),
};
const specialTypes: EdgeTypesType = Object
.keys(edgeTypes)
const wrappedTypes = {} as EdgeTypesType;
const specialTypes: EdgeTypesType = Object.keys(edgeTypes)
.filter(k => !['default', 'bezier'].includes(k))
.reduce((res, key) => {
res[key] = wrapEdge((edgeTypes[key] || BezierEdge) as ComponentType<EdgeWrapperProps>);
res[key] = wrapEdge((edgeTypes[key] || BezierEdge) as ComponentType<
EdgeCompProps
>);
return res;
}, {});
}, wrappedTypes);
return {
...standardTypes,
...specialTypes
...specialTypes,
};
}
+132 -96
View File
@@ -9,117 +9,153 @@ import BackgroundGrid from '../../components/BackgroundGrid';
import useKeyPress from '../../hooks/useKeyPress';
import useD3Zoom from '../../hooks/useD3Zoom';
import useGlobalKeyHandler from '../../hooks/useGlobalKeyHandler';
import useElementUpdater from '../../hooks/useElementUpdater'
import useElementUpdater from '../../hooks/useElementUpdater';
import { getDimensions } from '../../utils';
import { fitView, zoomIn, zoomOut } from '../../utils/graph';
import { Elements, NodeTypesType, EdgeTypesType, GridType, OnLoadFunc } from '../../types'
import {
Elements,
NodeTypesType,
EdgeTypesType,
GridType,
OnLoadFunc,
} from '../../types';
export interface GraphViewProps {
elements: Elements,
onElementClick: () => void,
onElementsRemove: (elements: Elements) => void,
onNodeDragStop: () => void,
onConnect: () => void,
onLoad: OnLoadFunc,
onMove: () => void,
selectionKeyCode: number,
nodeTypes: NodeTypesType,
edgeTypes: EdgeTypesType,
connectionLineType: string,
connectionLineStyle: SVGAttributes<{}>,
deleteKeyCode: number,
showBackground: boolean,
backgroundGap: number,
backgroundColor: string,
backgroundType: GridType,
};
elements: Elements;
onElementClick: () => void;
onElementsRemove: (elements: Elements) => void;
onNodeDragStop: () => void;
onConnect: () => void;
onLoad: OnLoadFunc;
onMove: () => void;
selectionKeyCode: number;
nodeTypes: NodeTypesType;
edgeTypes: EdgeTypesType;
connectionLineType: string;
connectionLineStyle: SVGAttributes<{}>;
deleteKeyCode: number;
showBackground: boolean;
backgroundGap: number;
backgroundColor: string;
backgroundType: GridType;
snapToGrid: boolean;
snapGrid: [number, number];
}
const GraphView = memo(({
nodeTypes, edgeTypes, onMove, onLoad,
onElementClick, onNodeDragStop, connectionLineType, connectionLineStyle,
selectionKeyCode, onElementsRemove, deleteKeyCode, elements,
showBackground, backgroundGap, backgroundColor, backgroundType,
onConnect
}: GraphViewProps) => {
const zoomPane = useRef<HTMLDivElement>(null);
const rendererNode = useRef<HTMLDivElement>(null);
const state = useStoreState(s => ({
width: s.width,
height: s.height,
nodes: s.nodes,
edges: s.edges,
d3Initialised: s.d3Initialised,
nodesSelectionActive: s.nodesSelectionActive
}));
const updateSize = useStoreActions(actions => actions.updateSize);
const setNodesSelection = useStoreActions(actions => actions.setNodesSelection);
const setOnConnect = useStoreActions(a => a.setOnConnect);
const selectionKeyPressed = useKeyPress(selectionKeyCode);
const GraphView = memo(
({
nodeTypes,
edgeTypes,
onMove,
onLoad,
onElementClick,
onNodeDragStop,
connectionLineType,
connectionLineStyle,
selectionKeyCode,
onElementsRemove,
deleteKeyCode,
elements,
showBackground,
backgroundGap,
backgroundColor,
backgroundType,
onConnect,
snapToGrid,
snapGrid,
}: GraphViewProps) => {
const zoomPane = useRef<HTMLDivElement>(null);
const rendererNode = useRef<HTMLDivElement>(null);
const state = useStoreState(s => ({
width: s.width,
height: s.height,
nodes: s.nodes,
edges: s.edges,
d3Initialised: s.d3Initialised,
nodesSelectionActive: s.nodesSelectionActive,
}));
const updateSize = useStoreActions(actions => actions.updateSize);
const setNodesSelection = useStoreActions(
actions => actions.setNodesSelection
);
const setOnConnect = useStoreActions(a => a.setOnConnect);
const setSnapGrid = useStoreActions(actions => actions.setSnapGrid);
const onZoomPaneClick = () => setNodesSelection({ isActive: false });
const selectionKeyPressed = useKeyPress(selectionKeyCode);
const updateDimensions = () => {
const size = getDimensions(rendererNode.current);
updateSize(size);
};
const onZoomPaneClick = () => setNodesSelection({ isActive: false });
useEffect(() => {
updateDimensions();
setOnConnect(onConnect);
window.onresize = updateDimensions;
const updateDimensions = () => {
if (!rendererNode.current) {
return;
}
return () => {
window.onresize = null;
const size = getDimensions(rendererNode.current);
updateSize(size);
};
}, []);
useD3Zoom(zoomPane, onMove, selectionKeyPressed);
useEffect(() => {
updateDimensions();
setOnConnect(onConnect);
window.onresize = updateDimensions;
useEffect(() => {
if (state.d3Initialised) {
onLoad({
fitView,
zoomIn,
zoomOut
});
}
}, [state.d3Initialised]);
return () => {
window.onresize = null;
};
}, []);
useGlobalKeyHandler({ onElementsRemove, deleteKeyCode });
useElementUpdater(elements);
useD3Zoom(zoomPane, onMove, selectionKeyPressed);
return (
<div className="react-flow__renderer" ref={rendererNode}>
{showBackground && (
<BackgroundGrid
gap={backgroundGap}
color={backgroundColor}
backgroundType={backgroundType}
useEffect(() => {
if (state.d3Initialised) {
onLoad({
fitView,
zoomIn,
zoomOut,
});
}
}, [state.d3Initialised]);
useEffect(() => {
setSnapGrid({ snapToGrid, snapGrid });
}, [snapToGrid]);
useGlobalKeyHandler({ onElementsRemove, deleteKeyCode });
useElementUpdater(elements);
return (
<div className="react-flow__renderer" ref={rendererNode}>
{showBackground && (
<BackgroundGrid
gap={backgroundGap}
color={backgroundColor}
backgroundType={backgroundType}
/>
)}
<NodeRenderer
nodeTypes={nodeTypes}
onElementClick={onElementClick}
onNodeDragStop={onNodeDragStop}
/>
)}
<NodeRenderer
nodeTypes={nodeTypes}
onElementClick={onElementClick}
onNodeDragStop={onNodeDragStop}
/>
<EdgeRenderer
width={state.width}
height={state.height}
edgeTypes={edgeTypes}
onElementClick={onElementClick}
connectionLineType={connectionLineType}
connectionLineStyle={connectionLineStyle}
/>
{selectionKeyPressed && <UserSelection />}
{state.nodesSelectionActive && <NodesSelection />}
<div
className="react-flow__zoompane"
onClick={onZoomPaneClick}
ref={zoomPane}
/>
</div>
);
});
<EdgeRenderer
width={state.width}
height={state.height}
edgeTypes={edgeTypes}
onElementClick={onElementClick}
connectionLineType={connectionLineType}
connectionLineStyle={connectionLineStyle}
/>
{selectionKeyPressed && <UserSelection />}
{state.nodesSelectionActive && <NodesSelection />}
<div
className="react-flow__zoompane"
onClick={onZoomPaneClick}
ref={zoomPane}
/>
</div>
);
}
);
GraphView.displayName = 'GraphView';
+24 -13
View File
@@ -2,28 +2,40 @@ import React, { memo, ComponentType } from 'react';
import { useStoreState } from '../../store/hooks';
import { isNode } from '../../utils/graph';
import { Node, Transform, NodeTypesType, NodeComponentProps, } from '../../types';
import {
Node,
Transform,
NodeTypesType,
NodeComponentProps,
} from '../../types';
interface NodeRendererProps {
nodeTypes: NodeTypesType;
onElementClick: () => void;
onNodeDragStop: () => void;
};
}
interface NodeRendererState {
nodes: Node[];
transform: Transform;
selectedElements: any;
};
}
function renderNode(node: Node, props: NodeRendererProps, state: NodeRendererState) {
function renderNode(
node: Node,
props: NodeRendererProps,
state: NodeRendererState
) {
const nodeType = node.type || 'default';
if (!props.nodeTypes[nodeType]) {
console.warn(`No node type found for type "${nodeType}". Using fallback type "default".`);
console.warn(
`No node type found for type "${nodeType}". Using fallback type "default".`
);
}
const NodeComponent = (props.nodeTypes[nodeType] || props.nodeTypes.default) as ComponentType<NodeComponentProps>;
const NodeComponent = (props.nodeTypes[nodeType] ||
props.nodeTypes.default) as ComponentType<NodeComponentProps>;
const selected = state.selectedElements
.filter(isNode)
.map((e: Node) => e.id)
@@ -33,7 +45,7 @@ function renderNode(node: Node, props: NodeRendererProps, state: NodeRendererSta
<NodeComponent
key={node.id}
id={node.id}
type={node.type}
type={nodeType}
data={node.data}
xPos={node.__rg.position.x}
yPos={node.__rg.position.y}
@@ -50,17 +62,16 @@ const NodeRenderer = memo((props: NodeRendererProps) => {
const state: NodeRendererState = useStoreState(s => ({
nodes: s.nodes,
transform: s.transform,
selectedElements: s.selectedElements
selectedElements: s.selectedElements,
}));
const { transform, nodes } = state;
const transformStyle = { transform : `translate(${transform[0]}px,${transform[1]}px) scale(${transform[2]})` };
const transformStyle = {
transform: `translate(${transform[0]}px,${transform[1]}px) scale(${transform[2]})`,
};
return (
<div
className="react-flow__nodes"
style={transformStyle}
>
<div className="react-flow__nodes" style={transformStyle}>
{nodes.map(node => renderNode(node, props, state))}
</div>
);
+17 -9
View File
@@ -6,24 +6,32 @@ import OutputNode from '../../components/Nodes/OutputNode';
import wrapNode from '../../components/Nodes/wrapNode';
import { NodeTypesType, NodeComponentProps } from '../../types';
export function createNodeTypes(nodeTypes: NodeTypesType): NodeTypesType {
export function createNodeTypes(nodeTypes: NodeTypesType): NodeTypesType {
const standardTypes: NodeTypesType = {
input: wrapNode((nodeTypes.input || InputNode) as ComponentType<NodeComponentProps>),
default: wrapNode((nodeTypes.default || DefaultNode) as ComponentType<NodeComponentProps>),
output: wrapNode((nodeTypes.output || OutputNode) as ComponentType<NodeComponentProps>)
input: wrapNode((nodeTypes.input || InputNode) as ComponentType<
NodeComponentProps
>),
default: wrapNode((nodeTypes.default || DefaultNode) as ComponentType<
NodeComponentProps
>),
output: wrapNode((nodeTypes.output || OutputNode) as ComponentType<
NodeComponentProps
>),
};
const specialTypes: NodeTypesType = Object
.keys(nodeTypes)
const wrappedTypes = {} as NodeTypesType;
const specialTypes: NodeTypesType = Object.keys(nodeTypes)
.filter(k => !['input', 'default', 'output'].includes(k))
.reduce((res, key) => {
res[key] = wrapNode((nodeTypes[key] || DefaultNode) as ComponentType<NodeComponentProps>);
res[key] = wrapNode((nodeTypes[key] || DefaultNode) as ComponentType<
NodeComponentProps
>);
return res;
}, {});
}, wrappedTypes);
return {
...standardTypes,
...specialTypes
...specialTypes,
};
}
+60 -34
View File
@@ -1,7 +1,7 @@
import React, { useMemo, CSSProperties, ReactNode, SVGAttributes } from 'react';
import React, { useMemo, SVGAttributes, HTMLAttributes } from 'react';
import { StoreProvider } from 'easy-peasy';
const nodeEnv: string = (process.env.NODE_ENV as string);
const nodeEnv: string = process.env.NODE_ENV as string;
if (nodeEnv !== 'production') {
const whyDidYouRender = require('@welldone-software/why-did-you-render');
@@ -18,39 +18,61 @@ import StraightEdge from '../../components/Edges/StraightEdge';
import StepEdge from '../../components/Edges/StepEdge';
import { createEdgeTypes } from '../EdgeRenderer/utils';
import store from '../../store';
import { Elements, NodeTypesType, EdgeTypesType, GridType, OnLoadFunc } from '../../types';
import {
Elements,
NodeTypesType,
EdgeTypesType,
GridType,
OnLoadFunc,
} from '../../types';
import '../../style.css';
export interface ReactFlowProps {
elements: Elements,
style?: CSSProperties,
className?: string,
children?: ReactNode[],
onElementClick: () => void,
onElementsRemove: (elements: Elements) => void,
onNodeDragStop: () => void,
onConnect: () => void,
onLoad: OnLoadFunc,
onMove: () => void,
nodeTypes: NodeTypesType,
edgeTypes: EdgeTypesType,
connectionLineType: string,
connectionLineStyle: SVGAttributes<{}>,
deleteKeyCode: number,
selectionKeyCode: number,
showBackground: boolean,
backgroundGap: number,
backgroundColor: string,
backgroundType: GridType
};
export interface ReactFlowProps
extends Omit<HTMLAttributes<HTMLDivElement>, 'onLoad'> {
elements: Elements;
onElementClick: () => void;
onElementsRemove: (elements: Elements) => void;
onNodeDragStop: () => void;
onConnect: () => void;
onLoad: OnLoadFunc;
onMove: () => void;
nodeTypes: NodeTypesType;
edgeTypes: EdgeTypesType;
connectionLineType: string;
connectionLineStyle: SVGAttributes<{}>;
deleteKeyCode: number;
selectionKeyCode: number;
showBackground: boolean;
backgroundGap: number;
backgroundColor: string;
backgroundType: GridType;
snapToGrid: boolean;
snapGrid: [16, 16];
}
const ReactFlow = ({
style, onElementClick, elements, children,
nodeTypes, edgeTypes, onLoad, onMove,
onElementsRemove, onConnect, onNodeDragStop, connectionLineType,
connectionLineStyle, deleteKeyCode, selectionKeyCode,
showBackground, backgroundGap, backgroundType, backgroundColor
style,
onElementClick,
elements,
children,
nodeTypes,
edgeTypes,
onLoad,
onMove,
onElementsRemove,
onConnect,
onNodeDragStop,
connectionLineType,
connectionLineStyle,
deleteKeyCode,
selectionKeyCode,
showBackground,
backgroundGap,
backgroundType,
backgroundColor,
snapToGrid,
snapGrid,
}: ReactFlowProps) => {
const nodeTypesParsed = useMemo(() => createNodeTypes(nodeTypes), []);
const edgeTypesParsed = useMemo(() => createEdgeTypes(edgeTypes), []);
@@ -76,6 +98,8 @@ const ReactFlow = ({
backgroundGap={backgroundGap}
showBackground={showBackground}
backgroundType={backgroundType}
snapToGrid={snapToGrid}
snapGrid={snapGrid}
/>
{children}
</StoreProvider>
@@ -90,17 +114,17 @@ ReactFlow.defaultProps = {
onElementsRemove: () => {},
onNodeDragStop: () => {},
onConnect: () => {},
onLoad: () => {},
onLoad: () => {},
onMove: () => {},
nodeTypes: {
input: InputNode,
default: DefaultNode,
output: OutputNode
output: OutputNode,
},
edgeTypes: {
default: BezierEdge,
straight: StraightEdge,
step: StepEdge
step: StepEdge,
},
connectionLineType: 'bezier',
connectionLineStyle: {},
@@ -109,7 +133,9 @@ ReactFlow.defaultProps = {
backgroundColor: '#eee',
backgroundGap: 24,
showBackground: true,
backgroundType: GridType.Dots
backgroundType: GridType.Dots,
snapToGrid: false,
snapGrid: [16, 16],
};
export default ReactFlow;