Merge branch 'main' into refactor/d3-drag

This commit is contained in:
moklick
2022-05-08 18:57:52 +02:00
39 changed files with 7275 additions and 8383 deletions
+26 -14
View File
@@ -1,4 +1,4 @@
import React, { memo, useMemo, FC } from 'react';
import React, { memo, FC, useEffect, useState, useRef } from 'react';
import cc from 'classcat';
import { useStore } from '../../store';
@@ -20,9 +20,16 @@ const Background: FC<BackgroundProps> = ({
style,
className,
}) => {
const ref = useRef<SVGSVGElement>(null);
const [patternId, setPatternId] = useState<string | null>(null);
const [x, y, scale] = useStore(transformSelector);
// when there are multiple flows on a page we need to make sure that every background gets its own pattern.
const patternId = useMemo(() => `pattern-${Math.floor(Math.random() * 100000)}`, []);
useEffect(() => {
// when there are multiple flows on a page we need to make sure that every background gets its own pattern.
const bgs = document.querySelectorAll('.react-flow__background');
const index = Array.from(bgs).findIndex((bg) => bg === ref.current);
setPatternId(`pattern-${index}`);
}, []);
const bgClasses = cc(['react-flow__background', 'react-flow__container', className]);
const scaledGap = gap * scale;
@@ -41,18 +48,23 @@ const Background: FC<BackgroundProps> = ({
width: '100%',
height: '100%',
}}
ref={ref}
>
<pattern
id={patternId}
x={xOffset}
y={yOffset}
width={scaledGap}
height={scaledGap}
patternUnits="userSpaceOnUse"
>
{path}
</pattern>
<rect x="0" y="0" width="100%" height="100%" fill={`url(#${patternId})`} />
{patternId && (
<>
<pattern
id={patternId}
x={xOffset}
y={yOffset}
width={scaledGap}
height={scaledGap}
patternUnits="userSpaceOnUse"
>
{path}
</pattern>
<rect x="0" y="0" width="100%" height="100%" fill={`url(#${patternId})`} />
</>
)}
</svg>
);
};
+3 -3
View File
@@ -1,4 +1,4 @@
import React, { memo, useCallback, FC, useEffect, useState } from 'react';
import React, { memo, useCallback, FC, useEffect, useState, PropsWithChildren } from 'react';
import cc from 'classcat';
import { useStore, useStoreApi } from '../../store';
@@ -12,7 +12,7 @@ import UnlockIcon from './Icons/Unlock';
import { ControlProps, ControlButtonProps, ReactFlowState } from '../../types';
export const ControlButton: FC<ControlButtonProps> = ({ children, className, ...rest }) => (
export const ControlButton: FC<PropsWithChildren<ControlButtonProps>> = ({ children, className, ...rest }) => (
<button type="button" className={cc(['react-flow__controls-button', className])} {...rest}>
{children}
</button>
@@ -20,7 +20,7 @@ export const ControlButton: FC<ControlButtonProps> = ({ children, className, ...
const isInteractiveSelector = (s: ReactFlowState) => s.nodesDraggable && s.nodesConnectable && s.elementsSelectable;
const Controls: FC<ControlProps> = ({
const Controls: FC<PropsWithChildren<ControlProps>> = ({
style,
showZoom = true,
showFitView = true,
@@ -2,7 +2,9 @@ import React, { FC, PropsWithChildren } from 'react';
import { Provider, createStore } from '../../store';
const ReactFlowProvider: FC<PropsWithChildren<{}>> = ({ children }) => <Provider createStore={createStore}>{children}</Provider>;
const ReactFlowProvider: FC<PropsWithChildren<{}>> = ({ children }) => (
<Provider createStore={createStore}>{children}</Provider>
);
ReactFlowProvider.displayName = 'ReactFlowProvider';
+2 -1
View File
@@ -10,7 +10,8 @@ type AttributionProps = {
function Attribution({ proOptions, position = 'bottom-right' }: AttributionProps) {
if (
(proOptions?.account === 'paid-sponsor' ||
(proOptions?.account === 'paid-pro' ||
proOptions?.account === 'paid-sponsor' ||
proOptions?.account === 'paid-enterprise' ||
proOptions?.account === 'paid-custom') &&
proOptions?.hideAttribution
+2 -2
View File
@@ -1,9 +1,9 @@
import React, { memo, useRef, useState, useEffect, FC } from 'react';
import React, { memo, useRef, useState, useEffect, FC, PropsWithChildren } from 'react';
import cc from 'classcat';
import { EdgeTextProps, Rect } from '../../types';
const EdgeText: FC<EdgeTextProps> = ({
const EdgeText: FC<PropsWithChildren<EdgeTextProps>> = ({
x,
y,
label,
+1 -1
View File
@@ -140,7 +140,7 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
const handleEdgeUpdater = useCallback(
(event: React.MouseEvent<SVGGElement, MouseEvent>, isSourceHandle: boolean) => {
const nodeId = isSourceHandle ? target : source;
const handleId = isSourceHandle ? targetHandleId : sourceHandleId;
const handleId = (isSourceHandle ? targetHandleId : sourceHandleId) || null;
const handleType = isSourceHandle ? 'target' : 'source';
const isValidConnection = () => true;
const isTarget = isSourceHandle;
+1 -3
View File
@@ -24,9 +24,7 @@ const selector = (s: ReactFlowState) => ({
transform: s.transform,
selectedNodesBbox: s.selectedNodesBbox,
userSelectionActive: s.userSelectionActive,
selectedNodes: Array.from(s.nodeInternals)
.filter(([_, n]) => n.selected)
.map(([_, n]) => n),
selectedNodes: Array.from(s.nodeInternals.values()).filter((n) => n.selected),
updateNodePosition: s.updateNodePosition,
});
+4 -1
View File
@@ -39,7 +39,10 @@ export function useMarkerSymbol(type: MarkerType) {
const symbolExists = MarkerSymbols.hasOwnProperty(type);
if (!symbolExists) {
console.warn(`marker type "${type}" doesn't exist.`);
// @ts-ignore
if (process.env.NODE_ENV === 'development') {
console.warn(`[React Flow]: Marker type "${type}" doesn't exist. Help: https://reactflow.dev/error#900`);
}
return () => null;
}
+16 -4
View File
@@ -15,11 +15,12 @@ import {
OnEdgeUpdateFunc,
HandleType,
ReactFlowState,
EdgeTypesWrapped,
} from '../../types';
import useVisibleEdges from '../../hooks/useVisibleEdges';
interface EdgeRendererProps {
edgeTypes: any;
edgeTypes: EdgeTypesWrapped;
connectionLineType: ConnectionLineType;
connectionLineStyle?: CSSProperties;
connectionLineComponent?: ConnectionLineComponent;
@@ -36,6 +37,7 @@ interface EdgeRendererProps {
onEdgeUpdateEnd?: (event: MouseEvent, edge: Edge, handleType: HandleType) => void;
edgeUpdaterRadius?: number;
noPanClassName?: string;
elevateEdgesOnSelect: boolean;
}
const selector = (s: ReactFlowState) => ({
@@ -64,7 +66,7 @@ const EdgeRenderer = (props: EdgeRendererProps) => {
connectionMode,
nodeInternals,
} = useStore(selector, shallow);
const edgeTree = useVisibleEdges(props.onlyRenderVisibleElements, nodeInternals);
const edgeTree = useVisibleEdges(props.onlyRenderVisibleElements, nodeInternals, props.elevateEdgesOnSelect);
if (!width) {
return null;
@@ -106,12 +108,22 @@ const EdgeRenderer = (props: EdgeRendererProps) => {
const targetPosition = targetHandle?.position || Position.Top;
if (!sourceHandle) {
console.warn(`couldn't create edge for source handle id: ${edge.sourceHandle}; edge id: ${edge.id}`);
// @ts-ignore
if (process.env.NODE_ENV === 'development') {
console.warn(
`[React Flow]: Couldn't create edge for source handle id: ${edge.sourceHandle}; edge id: ${edge.id}. Help: https://reactflow.dev/error#800`
);
}
return null;
}
if (!targetHandle) {
console.warn(`couldn't create edge for target handle id: ${edge.targetHandle}; edge id: ${edge.id}`);
// @ts-ignore
if (process.env.NODE_ENV === 'development') {
console.warn(
`[React Flow]: Couldn't create edge for target handle id: ${edge.targetHandle}; edge id: ${edge.id}. Help: https://reactflow.dev/error#800`
);
}
return null;
}
+6 -5
View File
@@ -4,6 +4,7 @@ import wrapEdge from '../../components/Edges/wrapEdge';
import {
EdgeProps,
EdgeTypes,
EdgeTypesWrapped,
HandleElement,
NodeHandleBounds,
NodeInternals,
@@ -14,10 +15,10 @@ import {
} from '../../types';
import { rectToBox } from '../../utils';
export type CreateEdgeTypes = (edgeTypes: EdgeTypes) => EdgeTypes;
export type CreateEdgeTypes = (edgeTypes: EdgeTypes) => EdgeTypesWrapped;
export function createEdgeTypes(edgeTypes: EdgeTypes): EdgeTypes {
const standardTypes: EdgeTypes = {
export function createEdgeTypes(edgeTypes: EdgeTypes): EdgeTypesWrapped {
const standardTypes: EdgeTypesWrapped = {
default: wrapEdge((edgeTypes.default || BezierEdge) as ComponentType<EdgeProps>),
straight: wrapEdge((edgeTypes.bezier || StraightEdge) as ComponentType<EdgeProps>),
step: wrapEdge((edgeTypes.step || StepEdge) as ComponentType<EdgeProps>),
@@ -25,8 +26,8 @@ export function createEdgeTypes(edgeTypes: EdgeTypes): EdgeTypes {
simplebezier: wrapEdge((edgeTypes.simplebezier || SimpleBezierEdge) as ComponentType<EdgeProps>),
};
const wrappedTypes = {} as EdgeTypes;
const specialTypes: EdgeTypes = Object.keys(edgeTypes)
const wrappedTypes = {} as EdgeTypesWrapped;
const specialTypes: EdgeTypesWrapped = Object.keys(edgeTypes)
.filter((k) => !['default', 'bezier'].includes(k))
.reduce((res, key) => {
res[key] = wrapEdge((edgeTypes[key] || BezierEdge) as ComponentType<EdgeProps>);
+7 -4
View File
@@ -5,11 +5,12 @@ import NodeRenderer from '../NodeRenderer';
import EdgeRenderer from '../EdgeRenderer';
import Viewport from '../Viewport';
import useOnInitHandler from '../../hooks/useOnInitHandler';
import { NodeTypes, EdgeTypes, ConnectionLineType, KeyCode, ReactFlowProps } from '../../types';
import { NodeTypesWrapped, EdgeTypesWrapped, ConnectionLineType, KeyCode, ReactFlowProps } from '../../types';
export interface GraphViewProps extends Omit<ReactFlowProps, 'onSelectionChange' | 'nodes' | 'edges'> {
nodeTypes: NodeTypes;
edgeTypes: EdgeTypes;
export interface GraphViewProps
extends Omit<ReactFlowProps, 'onSelectionChange' | 'nodes' | 'edges' | 'nodeTypes' | 'edgeTypes'> {
nodeTypes: NodeTypesWrapped;
edgeTypes: EdgeTypesWrapped;
selectionKeyCode: KeyCode | null;
deleteKeyCode: KeyCode | null;
multiSelectionKeyCode: KeyCode | null;
@@ -81,6 +82,7 @@ const GraphView = ({
noDragClassName,
noWheelClassName,
noPanClassName,
elevateEdgesOnSelect,
}: GraphViewProps) => {
useOnInitHandler(onInit);
@@ -134,6 +136,7 @@ const GraphView = ({
edgeUpdaterRadius={edgeUpdaterRadius}
defaultMarkerColor={defaultMarkerColor}
noPanClassName={noPanClassName}
elevateEdgesOnSelect={!!elevateEdgesOnSelect}
/>
<NodeRenderer
nodeTypes={nodeTypes}
+9 -4
View File
@@ -3,10 +3,10 @@ import shallow from 'zustand/shallow';
import useVisibleNodes from '../../hooks/useVisibleNodes';
import { useStore } from '../../store';
import { Node, NodeTypes, Position, ReactFlowState, WrapNodeProps } from '../../types';
import { Node, NodeTypesWrapped, Position, ReactFlowState, WrapNodeProps } from '../../types';
interface NodeRendererProps {
nodeTypes: NodeTypes;
nodeTypes: NodeTypesWrapped;
selectNodesOnDrag: boolean;
onNodeClick?: (event: MouseEvent, element: Node) => void;
onNodeDoubleClick?: (event: MouseEvent, element: Node) => void;
@@ -66,8 +66,13 @@ const NodeRenderer = (props: NodeRendererProps) => {
{nodes.map((node) => {
const nodeType = node.type || 'default';
if (!props.nodeTypes[nodeType]) {
console.warn(`Node type "${nodeType}" not found. Using fallback type "default".`);
// @ts-ignore
if (process.env.NODE_ENV === 'development') {
if (!props.nodeTypes[nodeType]) {
console.warn(
`[React Flow]: Node type "${nodeType}" not found. Using fallback type "default". Help: https://reactflow.dev/error#300`
);
}
}
const NodeComponent = (props.nodeTypes[nodeType] || props.nodeTypes.default) as ComponentType<WrapNodeProps>;
+6 -6
View File
@@ -5,20 +5,20 @@ import InputNode from '../../components/Nodes/InputNode';
import OutputNode from '../../components/Nodes/OutputNode';
import GroupNode from '../../components/Nodes/GroupNode';
import wrapNode from '../../components/Nodes/wrapNode';
import { NodeTypes, NodeProps } from '../../types';
import { NodeTypes, NodeProps, NodeTypesWrapped } from '../../types';
export type CreateNodeTypes = (nodeTypes: NodeTypes) => NodeTypes;
export type CreateNodeTypes = (nodeTypes: NodeTypes) => NodeTypesWrapped;
export function createNodeTypes(nodeTypes: NodeTypes): NodeTypes {
const standardTypes: NodeTypes = {
export function createNodeTypes(nodeTypes: NodeTypes): NodeTypesWrapped {
const standardTypes: NodeTypesWrapped = {
input: wrapNode((nodeTypes.input || InputNode) as ComponentType<NodeProps>),
default: wrapNode((nodeTypes.default || DefaultNode) as ComponentType<NodeProps>),
output: wrapNode((nodeTypes.output || OutputNode) as ComponentType<NodeProps>),
group: wrapNode((nodeTypes.group || GroupNode) as ComponentType<NodeProps>),
};
const wrappedTypes = {} as NodeTypes;
const specialTypes: NodeTypes = Object.keys(nodeTypes)
const wrappedTypes = {} as NodeTypesWrapped;
const specialTypes: NodeTypesWrapped = Object.keys(nodeTypes)
.filter((k) => !['input', 'default', 'output', 'group'].includes(k))
.reduce((res, key) => {
res[key] = wrapNode((nodeTypes[key] || DefaultNode) as ComponentType<NodeProps>);
+11 -7
View File
@@ -13,7 +13,9 @@ import {
ConnectionLineType,
ConnectionMode,
EdgeTypes,
EdgeTypesWrapped,
NodeTypes,
NodeTypesWrapped,
PanOnScrollMode,
ReactFlowProps,
ReactFlowRefType,
@@ -21,7 +23,7 @@ import {
import { createEdgeTypes } from '../EdgeRenderer/utils';
import GraphView from '../GraphView';
import { createNodeTypes } from '../NodeRenderer/utils';
import injectStyle, { useNodeOrEdgeTypes } from './utils';
import { injectStyle, useNodeOrEdgeTypes } from './utils';
import Wrapper from './Wrapper';
if (__INJECT_STYLES__) {
@@ -29,13 +31,13 @@ if (__INJECT_STYLES__) {
injectStyle(theme as unknown as string);
}
const defaultNodeTypes = {
const defaultNodeTypes: NodeTypes = {
input: InputNode,
default: DefaultNode,
output: OutputNode,
};
const defaultEdgeTypes = {
const defaultEdgeTypes: EdgeTypes = {
default: BezierEdge,
straight: StraightEdge,
step: StepEdge,
@@ -135,12 +137,13 @@ const ReactFlow = forwardRef<ReactFlowRefType, ReactFlowProps>(
attributionPosition,
proOptions,
defaultEdgeOptions,
elevateEdgesOnSelect = false,
...rest
},
ref
) => {
const nodeTypesParsed = useNodeOrEdgeTypes(nodeTypes, createNodeTypes) as NodeTypes;
const edgeTypesParsed = useNodeOrEdgeTypes(edgeTypes, createEdgeTypes) as EdgeTypes;
const nodeTypesWrapped = useNodeOrEdgeTypes(nodeTypes, createNodeTypes) as NodeTypesWrapped;
const edgeTypesWrapped = useNodeOrEdgeTypes(edgeTypes, createEdgeTypes) as EdgeTypesWrapped;
const reactFlowClasses = cc(['react-flow', className]);
return (
@@ -161,8 +164,8 @@ const ReactFlow = forwardRef<ReactFlowRefType, ReactFlowProps>(
onNodeDragStart={onNodeDragStart}
onNodeDrag={onNodeDrag}
onNodeDragStop={onNodeDragStop}
nodeTypes={nodeTypesParsed}
edgeTypes={edgeTypesParsed}
nodeTypes={nodeTypesWrapped}
edgeTypes={edgeTypesWrapped}
connectionLineType={connectionLineType}
connectionLineStyle={connectionLineStyle}
connectionLineComponent={connectionLineComponent}
@@ -202,6 +205,7 @@ const ReactFlow = forwardRef<ReactFlowRefType, ReactFlowProps>(
noDragClassName={noDragClassName}
noWheelClassName={noWheelClassName}
noPanClassName={noPanClassName}
elevateEdgesOnSelect={elevateEdgesOnSelect}
/>
<StoreUpdater
nodes={nodes}
+5 -5
View File
@@ -1,12 +1,12 @@
import { useMemo, useRef } from 'react';
import shallow from 'zustand/shallow';
import { EdgeTypes, NodeTypes } from '../../types';
import { EdgeTypes, EdgeTypesWrapped, NodeTypes, NodeTypesWrapped } from '../../types';
import { CreateEdgeTypes } from '../EdgeRenderer/utils';
import { CreateNodeTypes } from '../NodeRenderer/utils';
export function useNodeOrEdgeTypes(nodeOrEdgeTypes: NodeTypes, createTypes: CreateNodeTypes): NodeTypes;
export function useNodeOrEdgeTypes(nodeOrEdgeTypes: EdgeTypes, createTypes: CreateEdgeTypes): EdgeTypes;
export function useNodeOrEdgeTypes(nodeOrEdgeTypes: NodeTypes, createTypes: CreateNodeTypes): NodeTypesWrapped;
export function useNodeOrEdgeTypes(nodeOrEdgeTypes: EdgeTypes, createTypes: CreateEdgeTypes): EdgeTypesWrapped;
export function useNodeOrEdgeTypes(nodeOrEdgeTypes: any, createTypes: any): any {
const typesKeysRef = useRef<string[] | null>(null);
@@ -16,7 +16,7 @@ export function useNodeOrEdgeTypes(nodeOrEdgeTypes: any, createTypes: any): any
const typeKeys = Object.keys(nodeOrEdgeTypes);
if (shallow(typesKeysRef.current, typeKeys)) {
console.warn(
"React Flow: It looks like that you created a new nodeTypes or edgeTypes object. If this wasn't on purpose please define the nodeTypes/edgeTypes outside of the component or memoize them."
"[React Flow]: It looks like you have created a new nodeTypes or edgeTypes object. If this wasn't on purpose please define the nodeTypes/edgeTypes outside of the component or memoize them. Help: https://reactflow.dev/error#200"
);
}
@@ -28,7 +28,7 @@ export function useNodeOrEdgeTypes(nodeOrEdgeTypes: any, createTypes: any): any
return typesParsed;
}
export default function injectStyle(css: string): void {
export function injectStyle(css: string): void {
if (!css || typeof document === 'undefined') return;
const head = document.head || document.getElementsByTagName('head')[0];
+7 -2
View File
@@ -16,8 +16,13 @@ function useResizeHandler(rendererNode: MutableRefObject<HTMLDivElement | null>)
const size = getDimensions(rendererNode.current);
if (size.height === 0 || size.width === 0) {
console.warn('The React Flow parent container needs a width and a height to render the graph.');
// @ts-ignore
if (process.env.NODE_ENV === 'development') {
if (size.height === 0 || size.width === 0) {
console.warn(
'[React Flow]: The React Flow parent container needs a width and a height to render the graph. Help: https://reactflow.dev/error#400'
);
}
}
store.setState({ width: size.width || 500, height: size.height || 500 });
+12 -6
View File
@@ -7,13 +7,19 @@ import { isNumeric } from '../utils';
const defaultEdgeTree = [{ level: 0, isMaxLevel: true, edges: [] }];
function groupEdgesByZLevel(edges: Edge[], nodeInternals: NodeInternals) {
function groupEdgesByZLevel(edges: Edge[], nodeInternals: NodeInternals, elevateEdgesOnSelect: boolean = false) {
let maxLevel = -1;
const levelLookup = edges.reduce<Record<string, Edge[]>>((tree, edge) => {
const z = isNumeric(edge.zIndex)
? edge.zIndex
: Math.max(nodeInternals.get(edge.source)?.z || 0, nodeInternals.get(edge.target)?.z || 0);
const hasZIndex = isNumeric(edge.zIndex);
let z = hasZIndex ? edge.zIndex! : 0;
if (elevateEdgesOnSelect) {
z = hasZIndex
? edge.zIndex!
: Math.max(nodeInternals.get(edge.source)?.z || 0, nodeInternals.get(edge.target)?.z || 0);
}
if (tree[z]) {
tree[z].push(edge);
} else {
@@ -42,7 +48,7 @@ function groupEdgesByZLevel(edges: Edge[], nodeInternals: NodeInternals) {
return edgeTree;
}
function useVisibleEdges(onlyRenderVisible: boolean, nodeInternals: NodeInternals) {
function useVisibleEdges(onlyRenderVisible: boolean, nodeInternals: NodeInternals, elevateEdgesOnSelect: boolean) {
const edges = useStore(
useCallback(
(s: ReactFlowState) => {
@@ -77,7 +83,7 @@ function useVisibleEdges(onlyRenderVisible: boolean, nodeInternals: NodeInternal
)
);
return groupEdgesByZLevel(edges, nodeInternals);
return groupEdgesByZLevel(edges, nodeInternals, elevateEdgesOnSelect);
}
export default useVisibleEdges;
+8 -2
View File
@@ -45,9 +45,12 @@ export function createNodeInternals(nodes: Node[], nodeInternals: NodeInternals)
nodes.forEach((node) => {
const z = isNumeric(node.zIndex) ? node.zIndex : node.dragging || node.selected ? 1000 : 0;
const currInternals = nodeInternals.get(node.id);
const internals: Node = {
...nodeInternals.get(node.id),
width: currInternals?.width,
height: currInternals?.height,
handleBounds: currInternals?.handleBounds,
...node,
positionAbsolute: {
x: node.position.x,
@@ -148,7 +151,10 @@ export function createPositionChange({
]
: currentExtent;
} else {
console.warn('Only child nodes can use parent extent');
// @ts-ignore
if (process.env.NODE_ENV === 'development') {
console.warn('[React Flow]: Only child nodes can use a parent extent. Help: https://reactflow.dev/error#500');
}
currentExtent = nodeExtent;
}
}
+9 -2
View File
@@ -1,4 +1,10 @@
import React, { CSSProperties, HTMLAttributes, MouseEvent as ReactMouseEvent, WheelEvent } from 'react';
import React, {
ButtonHTMLAttributes,
CSSProperties,
HTMLAttributes,
MouseEvent as ReactMouseEvent,
WheelEvent,
} from 'react';
import {
OnSelectionChangeFunc,
@@ -118,6 +124,7 @@ export interface ReactFlowProps extends HTMLAttributes<HTMLDivElement> {
connectOnClick?: boolean;
attributionPosition?: AttributionPosition;
proOptions?: ProOptions;
elevateEdgesOnSelect?: boolean;
}
export type ReactFlowRefType = HTMLDivElement;
@@ -144,7 +151,7 @@ export interface ControlProps extends HTMLAttributes<HTMLDivElement> {
onInteractiveChange?: (interactiveStatus: boolean) => void;
}
export interface ControlButtonProps extends HTMLAttributes<HTMLButtonElement> {}
export interface ControlButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {}
export interface BackgroundProps extends HTMLAttributes<SVGElement> {
variant?: BackgroundVariant;
+5 -5
View File
@@ -1,4 +1,4 @@
import React, { CSSProperties, HTMLAttributes, ReactNode } from 'react';
import React, { CSSProperties, ComponentType, HTMLAttributes, ReactNode } from 'react';
import { Connection } from './general';
import { HandleElement, HandleType } from './handles';
import { Node } from './nodes';
@@ -101,8 +101,8 @@ export interface WrapEdgeProps<T = any> {
style?: CSSProperties;
source: string;
target: string;
sourceHandleId: string | null;
targetHandleId: string | null;
sourceHandleId?: string | null;
targetHandleId?: string | null;
sourceX: number;
sourceY: number;
targetX: number;
@@ -111,7 +111,7 @@ export interface WrapEdgeProps<T = any> {
targetPosition: Position;
elementsSelectable?: boolean;
hidden?: boolean;
onEdgeUpdate: OnEdgeUpdateFunc;
onEdgeUpdate?: OnEdgeUpdateFunc;
onContextMenu?: EdgeMouseHandler;
onMouseEnter?: EdgeMouseHandler;
onMouseMove?: EdgeMouseHandler;
@@ -162,7 +162,7 @@ export type ConnectionLineComponentProps = {
sourceHandle?: HandleElement;
};
export type ConnectionLineComponent = React.ComponentType<ConnectionLineComponentProps>;
export type ConnectionLineComponent = ComponentType<ConnectionLineComponentProps>;
export type OnEdgeUpdateFunc<T = any> = (oldEdge: Edge<T>, newConnection: Connection) => void;
+7 -5
View File
@@ -1,16 +1,18 @@
import { MouseEvent as ReactMouseEvent, ReactNode } from 'react';
import { MouseEvent as ReactMouseEvent, ComponentType, MemoExoticComponent } from 'react';
import { Selection as D3Selection, ZoomBehavior } from 'd3';
import { XYPosition, Rect, Transform, CoordinateExtent } from './utils';
import { NodeChange, EdgeChange } from './changes';
import { Node, NodeInternals, NodeDimensionUpdate, NodeDiffUpdate } from './nodes';
import { Edge } from './edges';
import { Node, NodeInternals, NodeDimensionUpdate, NodeDiffUpdate, NodeProps, WrapNodeProps } from './nodes';
import { Edge, EdgeProps, WrapEdgeProps } from './edges';
import { HandleType, StartHandle } from './handles';
import { DefaultEdgeOptions } from '.';
import { ReactFlowInstance } from './instance';
export type NodeTypes = { [key: string]: ReactNode };
export type EdgeTypes = NodeTypes;
export type NodeTypes = { [key: string]: ComponentType<NodeProps> };
export type NodeTypesWrapped = { [key: string]: MemoExoticComponent<ComponentType<WrapNodeProps>> };
export type EdgeTypes = { [key: string]: ComponentType<EdgeProps> };
export type EdgeTypesWrapped = { [key: string]: MemoExoticComponent<ComponentType<WrapEdgeProps>> };
export type FitView = (fitViewOptions?: FitViewOptions) => void;
+18 -3
View File
@@ -57,7 +57,12 @@ const connectionExists = (edge: Edge, edges: Edge[]) => {
export const addEdge = (edgeParams: Edge | Connection, edges: Edge[]): Edge[] => {
if (!edgeParams.source || !edgeParams.target) {
console.warn("Can't create edge. An edge needs a source and a target.");
// @ts-ignore
if (process.env.NODE_ENV === 'development') {
console.warn(
"[React Flow]: Can't create edge. An edge needs a source and a target. Help: https://reactflow.dev/error#600"
);
}
return edges;
}
@@ -80,14 +85,24 @@ export const addEdge = (edgeParams: Edge | Connection, edges: Edge[]): Edge[] =>
export const updateEdge = (oldEdge: Edge, newConnection: Connection, edges: Edge[]): Edge[] => {
if (!newConnection.source || !newConnection.target) {
console.warn("Can't create new edge. An edge needs a source and a target.");
// @ts-ignore
if (process.env.NODE_ENV === 'development') {
console.warn(
"[React Flow]: Can't create a new edge. An edge needs a source and a target. Help: https://reactflow.dev/error#600"
);
}
return edges;
}
const foundEdge = edges.find((e) => e.id === oldEdge.id) as Edge;
if (!foundEdge) {
console.warn(`The old edge with id=${oldEdge.id} does not exist.`);
// @ts-ignore
if (process.env.NODE_ENV === 'development') {
console.warn(
`[React Flow]: The old edge with id=${oldEdge.id} does not exist. Help: https://reactflow.dev/error#700`
);
}
return edges;
}