feat(onError): add onError prop #2772
This commit is contained in:
@@ -9,7 +9,7 @@ import { EdgeAnchor } from './EdgeAnchor';
|
|||||||
import { getMarkerId } from '../../utils/graph';
|
import { getMarkerId } from '../../utils/graph';
|
||||||
import { getMouseHandler } from './utils';
|
import { getMouseHandler } from './utils';
|
||||||
import { elementSelectionKeys } from '../../utils';
|
import { elementSelectionKeys } from '../../utils';
|
||||||
import type { EdgeProps, WrapEdgeProps, Connection } from '../../types';
|
import type { EdgeProps, WrapEdgeProps, Connection, HandleType } from '../../types';
|
||||||
|
|
||||||
export default (EdgeComponent: ComponentType<EdgeProps>) => {
|
export default (EdgeComponent: ComponentType<EdgeProps>) => {
|
||||||
const EdgeWrapper = ({
|
const EdgeWrapper = ({
|
||||||
@@ -115,7 +115,7 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
|
|||||||
getState: store.getState,
|
getState: store.getState,
|
||||||
setState: store.setState,
|
setState: store.setState,
|
||||||
isValidConnection,
|
isValidConnection,
|
||||||
elementEdgeUpdaterType: handleType,
|
edgeUpdaterType: handleType,
|
||||||
onEdgeUpdateEnd: _onEdgeUpdateEnd,
|
onEdgeUpdateEnd: _onEdgeUpdateEnd,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { shallow } from 'zustand/shallow';
|
|||||||
import { useStore, useStoreApi } from '../../hooks/useStore';
|
import { useStore, useStoreApi } from '../../hooks/useStore';
|
||||||
import { useNodeId } from '../../contexts/NodeIdContext';
|
import { useNodeId } from '../../contexts/NodeIdContext';
|
||||||
import { handlePointerDown } from './handler';
|
import { handlePointerDown } from './handler';
|
||||||
import { devWarn, getHostForElement, isMouseEvent } from '../../utils';
|
import { getHostForElement, isMouseEvent } from '../../utils';
|
||||||
import { addEdge } from '../../utils/graph';
|
import { addEdge } from '../../utils/graph';
|
||||||
import { Position } from '../../types';
|
import { Position } from '../../types';
|
||||||
import type { HandleProps, Connection, ReactFlowState } from '../../types';
|
import type { HandleProps, Connection, ReactFlowState } from '../../types';
|
||||||
@@ -42,7 +42,10 @@ const Handle = forwardRef<HTMLDivElement, HandleComponentProps>(
|
|||||||
const nodeId = useNodeId();
|
const nodeId = useNodeId();
|
||||||
|
|
||||||
if (!nodeId) {
|
if (!nodeId) {
|
||||||
devWarn('Handle: No node id found. Make sure to only use a Handle inside a custom Node.');
|
store
|
||||||
|
.getState()
|
||||||
|
.onError?.('010', 'Handle: No node id found. Make sure to only use a Handle inside a custom Node.');
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ export function isValidHandle(
|
|||||||
const isValid =
|
const isValid =
|
||||||
connectionMode === ConnectionMode.Strict
|
connectionMode === ConnectionMode.Strict
|
||||||
? (isTarget && handleIsSource) || (!isTarget && handleIsTarget)
|
? (isTarget && handleIsSource) || (!isTarget && handleIsTarget)
|
||||||
: handleNodeId !== handle.nodeId || handleId !== handle.id;
|
: handleNodeId !== fromNodeId || handleId !== fromHandleId;
|
||||||
|
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
result.isValid = isValidConnection(connection);
|
result.isValid = isValidConnection(connection);
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ type StoreUpdaterProps = Pick<
|
|||||||
| 'elevateNodesOnSelect'
|
| 'elevateNodesOnSelect'
|
||||||
| 'autoPanOnConnect'
|
| 'autoPanOnConnect'
|
||||||
| 'autoPanOnNodeDrag'
|
| 'autoPanOnNodeDrag'
|
||||||
|
| 'onError'
|
||||||
> & { rfId: string };
|
> & { rfId: string };
|
||||||
|
|
||||||
const selector = (s: ReactFlowState) => ({
|
const selector = (s: ReactFlowState) => ({
|
||||||
@@ -123,6 +124,7 @@ const StoreUpdater = ({
|
|||||||
rfId,
|
rfId,
|
||||||
autoPanOnConnect,
|
autoPanOnConnect,
|
||||||
autoPanOnNodeDrag,
|
autoPanOnNodeDrag,
|
||||||
|
onError,
|
||||||
}: StoreUpdaterProps) => {
|
}: StoreUpdaterProps) => {
|
||||||
const {
|
const {
|
||||||
setNodes,
|
setNodes,
|
||||||
@@ -178,6 +180,7 @@ const StoreUpdater = ({
|
|||||||
useDirectStoreUpdater('rfId', rfId, store.setState);
|
useDirectStoreUpdater('rfId', rfId, store.setState);
|
||||||
useDirectStoreUpdater('autoPanOnConnect', autoPanOnConnect, store.setState);
|
useDirectStoreUpdater('autoPanOnConnect', autoPanOnConnect, store.setState);
|
||||||
useDirectStoreUpdater('autoPanOnNodeDrag', autoPanOnNodeDrag, store.setState);
|
useDirectStoreUpdater('autoPanOnNodeDrag', autoPanOnNodeDrag, store.setState);
|
||||||
|
useDirectStoreUpdater('onError', onError, store.setState);
|
||||||
|
|
||||||
useStoreUpdater<Node[]>(nodes, setNodes);
|
useStoreUpdater<Node[]>(nodes, setNodes);
|
||||||
useStoreUpdater<Edge[]>(edges, setEdges);
|
useStoreUpdater<Edge[]>(edges, setEdges);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import { devWarn } from '../../utils';
|
|
||||||
import { MarkerType } from '../../types';
|
import { MarkerType } from '../../types';
|
||||||
import type { EdgeMarker } from '../../types';
|
import type { EdgeMarker } from '../../types';
|
||||||
|
import { useStoreApi } from '../../hooks/useStore';
|
||||||
|
|
||||||
type SymbolProps = Omit<EdgeMarker, 'type'>;
|
type SymbolProps = Omit<EdgeMarker, 'type'>;
|
||||||
|
|
||||||
@@ -38,11 +38,12 @@ export const MarkerSymbols = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function useMarkerSymbol(type: MarkerType) {
|
export function useMarkerSymbol(type: MarkerType) {
|
||||||
|
const store = useStoreApi();
|
||||||
const symbol = useMemo(() => {
|
const symbol = useMemo(() => {
|
||||||
const symbolExists = Object.prototype.hasOwnProperty.call(MarkerSymbols, type);
|
const symbolExists = Object.prototype.hasOwnProperty.call(MarkerSymbols, type);
|
||||||
|
|
||||||
if (!symbolExists) {
|
if (!symbolExists) {
|
||||||
devWarn(`Marker type "${type}" doesn't exist. Help: https://reactflow.dev/error#900`);
|
store.getState().onError?.('009', `Marker type "${type}" doesn't exist.`);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import EdgeRenderer from '../EdgeRenderer';
|
|||||||
import ViewportWrapper from '../Viewport';
|
import ViewportWrapper from '../Viewport';
|
||||||
import useOnInitHandler from '../../hooks/useOnInitHandler';
|
import useOnInitHandler from '../../hooks/useOnInitHandler';
|
||||||
import type { EdgeTypesWrapped, NodeTypesWrapped, ReactFlowProps } from '../../types';
|
import type { EdgeTypesWrapped, NodeTypesWrapped, ReactFlowProps } from '../../types';
|
||||||
|
import ConnectionLine from '../../components/ConnectionLine';
|
||||||
|
|
||||||
export type GraphViewProps = Omit<ReactFlowProps, 'onSelectionChange' | 'nodes' | 'edges' | 'nodeTypes' | 'edgeTypes'> &
|
export type GraphViewProps = Omit<ReactFlowProps, 'onSelectionChange' | 'nodes' | 'edges' | 'nodeTypes' | 'edgeTypes'> &
|
||||||
Required<
|
Required<
|
||||||
@@ -149,10 +150,6 @@ const GraphView = ({
|
|||||||
edgeTypes={edgeTypes}
|
edgeTypes={edgeTypes}
|
||||||
onEdgeClick={onEdgeClick}
|
onEdgeClick={onEdgeClick}
|
||||||
onEdgeDoubleClick={onEdgeDoubleClick}
|
onEdgeDoubleClick={onEdgeDoubleClick}
|
||||||
connectionLineType={connectionLineType}
|
|
||||||
connectionLineStyle={connectionLineStyle}
|
|
||||||
connectionLineComponent={connectionLineComponent}
|
|
||||||
connectionLineContainerStyle={connectionLineContainerStyle}
|
|
||||||
onEdgeUpdate={onEdgeUpdate}
|
onEdgeUpdate={onEdgeUpdate}
|
||||||
onlyRenderVisibleElements={onlyRenderVisibleElements}
|
onlyRenderVisibleElements={onlyRenderVisibleElements}
|
||||||
onEdgeContextMenu={onEdgeContextMenu}
|
onEdgeContextMenu={onEdgeContextMenu}
|
||||||
@@ -167,7 +164,14 @@ const GraphView = ({
|
|||||||
elevateEdgesOnSelect={!!elevateEdgesOnSelect}
|
elevateEdgesOnSelect={!!elevateEdgesOnSelect}
|
||||||
disableKeyboardA11y={disableKeyboardA11y}
|
disableKeyboardA11y={disableKeyboardA11y}
|
||||||
rfId={rfId}
|
rfId={rfId}
|
||||||
/>
|
>
|
||||||
|
<ConnectionLine
|
||||||
|
style={connectionLineStyle}
|
||||||
|
type={connectionLineType}
|
||||||
|
component={connectionLineComponent}
|
||||||
|
containerStyle={connectionLineContainerStyle}
|
||||||
|
/>
|
||||||
|
</EdgeRenderer>
|
||||||
<div className="react-flow__edgelabel-renderer" />
|
<div className="react-flow__edgelabel-renderer" />
|
||||||
|
|
||||||
<NodeRenderer
|
<NodeRenderer
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { shallow } from 'zustand/shallow';
|
|||||||
|
|
||||||
import useVisibleNodes from '../../hooks/useVisibleNodes';
|
import useVisibleNodes from '../../hooks/useVisibleNodes';
|
||||||
import { useStore } from '../../hooks/useStore';
|
import { useStore } from '../../hooks/useStore';
|
||||||
import { clampPosition, devWarn, internalsSymbol } from '../../utils';
|
import { clampPosition, internalsSymbol } from '../../utils';
|
||||||
import { containerStyle } from '../../styles';
|
import { containerStyle } from '../../styles';
|
||||||
import { GraphViewProps } from '../GraphView';
|
import { GraphViewProps } from '../GraphView';
|
||||||
import { getPositionWithOrigin } from './utils';
|
import { getPositionWithOrigin } from './utils';
|
||||||
@@ -36,13 +36,12 @@ const selector = (s: ReactFlowState) => ({
|
|||||||
nodesFocusable: s.nodesFocusable,
|
nodesFocusable: s.nodesFocusable,
|
||||||
elementsSelectable: s.elementsSelectable,
|
elementsSelectable: s.elementsSelectable,
|
||||||
updateNodeDimensions: s.updateNodeDimensions,
|
updateNodeDimensions: s.updateNodeDimensions,
|
||||||
|
onError: s.onError,
|
||||||
});
|
});
|
||||||
|
|
||||||
const NodeRenderer = (props: NodeRendererProps) => {
|
const NodeRenderer = (props: NodeRendererProps) => {
|
||||||
const { nodesDraggable, nodesConnectable, nodesFocusable, elementsSelectable, updateNodeDimensions } = useStore(
|
const { nodesDraggable, nodesConnectable, nodesFocusable, elementsSelectable, updateNodeDimensions, onError } =
|
||||||
selector,
|
useStore(selector, shallow);
|
||||||
shallow
|
|
||||||
);
|
|
||||||
const nodes = useVisibleNodes(props.onlyRenderVisibleElements);
|
const nodes = useVisibleNodes(props.onlyRenderVisibleElements);
|
||||||
const resizeObserverRef = useRef<ResizeObserver>();
|
const resizeObserverRef = useRef<ResizeObserver>();
|
||||||
|
|
||||||
@@ -78,9 +77,7 @@ const NodeRenderer = (props: NodeRendererProps) => {
|
|||||||
let nodeType = node.type || 'default';
|
let nodeType = node.type || 'default';
|
||||||
|
|
||||||
if (!props.nodeTypes[nodeType]) {
|
if (!props.nodeTypes[nodeType]) {
|
||||||
devWarn(
|
onError?.('003', `Node type "${nodeType}" not found. Using fallback type "default".`);
|
||||||
`Node type "${nodeType}" not found. Using fallback type "default". Help: https://reactflow.dev/error#300`
|
|
||||||
);
|
|
||||||
|
|
||||||
nodeType = 'default';
|
nodeType = 'default';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import InputNode from '../../components/Nodes/InputNode';
|
|||||||
import OutputNode from '../../components/Nodes/OutputNode';
|
import OutputNode from '../../components/Nodes/OutputNode';
|
||||||
import GroupNode from '../../components/Nodes/GroupNode';
|
import GroupNode from '../../components/Nodes/GroupNode';
|
||||||
import wrapNode from '../../components/Nodes/wrapNode';
|
import wrapNode from '../../components/Nodes/wrapNode';
|
||||||
import { devWarn } from '../../utils';
|
|
||||||
import type { NodeTypes, NodeProps, NodeTypesWrapped, NodeOrigin, XYPosition } from '../../types';
|
import type { NodeTypes, NodeProps, NodeTypesWrapped, NodeOrigin, XYPosition } from '../../types';
|
||||||
|
|
||||||
export type CreateNodeTypes = (nodeTypes: NodeTypes) => NodeTypesWrapped;
|
export type CreateNodeTypes = (nodeTypes: NodeTypes) => NodeTypesWrapped;
|
||||||
@@ -51,7 +50,6 @@ export const getPositionWithOrigin = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (origin[0] < 0 || origin[1] < 0 || origin[0] > 1 || origin[1] > 1) {
|
if (origin[0] < 0 || origin[1] < 0 || origin[0] > 1 || origin[1] > 1) {
|
||||||
devWarn('nodeOrigin must be between 0 and 1');
|
|
||||||
return { x, y };
|
return { x, y };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ const ReactFlow = forwardRef<ReactFlowRefType, ReactFlowProps>(
|
|||||||
autoPanOnConnect = true,
|
autoPanOnConnect = true,
|
||||||
autoPanOnNodeDrag = true,
|
autoPanOnNodeDrag = true,
|
||||||
connectionRadius = 20,
|
connectionRadius = 20,
|
||||||
|
onError,
|
||||||
style,
|
style,
|
||||||
id,
|
id,
|
||||||
...rest
|
...rest
|
||||||
@@ -292,6 +293,7 @@ const ReactFlow = forwardRef<ReactFlowRefType, ReactFlowProps>(
|
|||||||
rfId={rfId}
|
rfId={rfId}
|
||||||
autoPanOnConnect={autoPanOnConnect}
|
autoPanOnConnect={autoPanOnConnect}
|
||||||
autoPanOnNodeDrag={autoPanOnNodeDrag}
|
autoPanOnNodeDrag={autoPanOnNodeDrag}
|
||||||
|
onError={onError}
|
||||||
/>
|
/>
|
||||||
<SelectionListener onSelectionChange={onSelectionChange} />
|
<SelectionListener onSelectionChange={onSelectionChange} />
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ export function useNodeOrEdgeTypes(nodeOrEdgeTypes: any, createTypes: any): any
|
|||||||
const typeKeys = Object.keys(nodeOrEdgeTypes);
|
const typeKeys = Object.keys(nodeOrEdgeTypes);
|
||||||
if (shallow(typesKeysRef.current, typeKeys)) {
|
if (shallow(typesKeysRef.current, typeKeys)) {
|
||||||
devWarn(
|
devWarn(
|
||||||
"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"
|
'002',
|
||||||
|
"It looks like you've 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."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ function useDrag({
|
|||||||
snapGrid,
|
snapGrid,
|
||||||
snapToGrid,
|
snapToGrid,
|
||||||
nodeOrigin,
|
nodeOrigin,
|
||||||
|
onError,
|
||||||
} = store.getState();
|
} = store.getState();
|
||||||
|
|
||||||
lastPos.current = { x, y };
|
lastPos.current = { x, y };
|
||||||
@@ -75,7 +76,7 @@ function useDrag({
|
|||||||
nextPosition.y = snapGrid[1] * Math.round(nextPosition.y / snapGrid[1]);
|
nextPosition.y = snapGrid[1] * Math.round(nextPosition.y / snapGrid[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedPos = calcNextPosition(n, nextPosition, nodeInternals, nodeExtent, nodeOrigin);
|
const updatedPos = calcNextPosition(n, nextPosition, nodeInternals, nodeExtent, nodeOrigin, onError);
|
||||||
|
|
||||||
// we want to make sure that we only fire a change event when there is a changes
|
// we want to make sure that we only fire a change event when there is a changes
|
||||||
hasChange = hasChange || n.position.x !== updatedPos.position.x || n.position.y !== updatedPos.position.y;
|
hasChange = hasChange || n.position.x !== updatedPos.position.x || n.position.y !== updatedPos.position.y;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { RefObject } from 'react';
|
import type { RefObject } from 'react';
|
||||||
|
|
||||||
import { clampPosition, devWarn, isNumeric } from '../../utils';
|
import { clampPosition, isNumeric } from '../../utils';
|
||||||
import type { CoordinateExtent, Node, NodeDragItem, NodeInternals, NodeOrigin, XYPosition } from '../../types';
|
import type { CoordinateExtent, Node, NodeDragItem, NodeInternals, NodeOrigin, OnError, XYPosition } from '../../types';
|
||||||
import { getNodePositionWithOrigin } from '../../utils/graph';
|
import { getNodePositionWithOrigin } from '../../utils/graph';
|
||||||
|
|
||||||
export function isParentSelected(node: Node, nodeInternals: NodeInternals): boolean {
|
export function isParentSelected(node: Node, nodeInternals: NodeInternals): boolean {
|
||||||
@@ -62,7 +62,8 @@ export function calcNextPosition(
|
|||||||
nextPosition: XYPosition,
|
nextPosition: XYPosition,
|
||||||
nodeInternals: NodeInternals,
|
nodeInternals: NodeInternals,
|
||||||
nodeExtent?: CoordinateExtent,
|
nodeExtent?: CoordinateExtent,
|
||||||
nodeOrigin: NodeOrigin = [0, 0]
|
nodeOrigin: NodeOrigin = [0, 0],
|
||||||
|
onError?: OnError
|
||||||
): { position: XYPosition; positionAbsolute: XYPosition } {
|
): { position: XYPosition; positionAbsolute: XYPosition } {
|
||||||
let currentExtent = node.extent || nodeExtent;
|
let currentExtent = node.extent || nodeExtent;
|
||||||
|
|
||||||
@@ -81,7 +82,7 @@ export function calcNextPosition(
|
|||||||
]
|
]
|
||||||
: currentExtent;
|
: currentExtent;
|
||||||
} else {
|
} else {
|
||||||
devWarn('Only child nodes can use a parent extent. Help: https://reactflow.dev/error#500');
|
onError?.('005', 'Only child nodes can use a parent extent.');
|
||||||
|
|
||||||
currentExtent = nodeExtent;
|
currentExtent = nodeExtent;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useEffect } from 'react';
|
|||||||
import type { MutableRefObject } from 'react';
|
import type { MutableRefObject } from 'react';
|
||||||
|
|
||||||
import { useStoreApi } from '../hooks/useStore';
|
import { useStoreApi } from '../hooks/useStore';
|
||||||
import { devWarn, getDimensions } from '../utils';
|
import { getDimensions } from '../utils';
|
||||||
|
|
||||||
function useResizeHandler(rendererNode: MutableRefObject<HTMLDivElement | null>): void {
|
function useResizeHandler(rendererNode: MutableRefObject<HTMLDivElement | null>): void {
|
||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
@@ -18,9 +18,9 @@ function useResizeHandler(rendererNode: MutableRefObject<HTMLDivElement | null>)
|
|||||||
const size = getDimensions(rendererNode.current);
|
const size = getDimensions(rendererNode.current);
|
||||||
|
|
||||||
if (size.height === 0 || size.width === 0) {
|
if (size.height === 0 || size.width === 0) {
|
||||||
devWarn(
|
store
|
||||||
'The React Flow parent container needs a width and a height to render the graph. Help: https://reactflow.dev/error#400'
|
.getState()
|
||||||
);
|
.onError?.('004', 'The React Flow parent container needs a width and a height to render the graph.');
|
||||||
}
|
}
|
||||||
|
|
||||||
store.setState({ width: size.width || 500, height: size.height || 500 });
|
store.setState({ width: size.width || 500, height: size.height || 500 });
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ function useUpdateNodePositions() {
|
|||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
|
|
||||||
const updatePositions = useCallback((params: { x: number; y: number; isShiftPressed: boolean }) => {
|
const updatePositions = useCallback((params: { x: number; y: number; isShiftPressed: boolean }) => {
|
||||||
const { nodeInternals, nodeExtent, updateNodePositions, getNodes, snapToGrid, snapGrid } = store.getState();
|
const { nodeInternals, nodeExtent, updateNodePositions, getNodes, snapToGrid, snapGrid, onError } =
|
||||||
|
store.getState();
|
||||||
const selectedNodes = getNodes().filter((n) => n.selected);
|
const selectedNodes = getNodes().filter((n) => n.selected);
|
||||||
// by default a node moves 5px on each key press, or 20px if shift is pressed
|
// by default a node moves 5px on each key press, or 20px if shift is pressed
|
||||||
// if snap grid is enabled, we use that for the velocity.
|
// if snap grid is enabled, we use that for the velocity.
|
||||||
@@ -27,10 +28,17 @@ function useUpdateNodePositions() {
|
|||||||
nextPosition.y = snapGrid[1] * Math.round(nextPosition.y / snapGrid[1]);
|
nextPosition.y = snapGrid[1] * Math.round(nextPosition.y / snapGrid[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedPos = calcNextPosition(n, nextPosition, nodeInternals, nodeExtent);
|
const { positionAbsolute, position } = calcNextPosition(
|
||||||
|
n,
|
||||||
|
nextPosition,
|
||||||
|
nodeInternals,
|
||||||
|
nodeExtent,
|
||||||
|
undefined,
|
||||||
|
onError
|
||||||
|
);
|
||||||
|
|
||||||
n.position = updatedPos.position;
|
n.position = position;
|
||||||
n.positionAbsolute = updatedPos.positionAbsolute;
|
n.positionAbsolute = positionAbsolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { devWarn } from '../utils';
|
||||||
import { ConnectionMode } from '../types';
|
import { ConnectionMode } from '../types';
|
||||||
import type { CoordinateExtent, ReactFlowStore } from '../types';
|
import type { CoordinateExtent, ReactFlowStore } from '../types';
|
||||||
|
|
||||||
@@ -59,6 +60,7 @@ const initialState: ReactFlowStore = {
|
|||||||
autoPanOnConnect: true,
|
autoPanOnConnect: true,
|
||||||
autoPanOnNodeDrag: true,
|
autoPanOnNodeDrag: true,
|
||||||
connectionRadius: 20,
|
connectionRadius: 20,
|
||||||
|
onError: devWarn,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default initialState;
|
export default initialState;
|
||||||
|
|||||||
@@ -98,7 +98,7 @@
|
|||||||
.react-flow__connection {
|
.react-flow__connection {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
||||||
&.animated {
|
.animated {
|
||||||
stroke-dasharray: 5;
|
stroke-dasharray: 5;
|
||||||
animation: dashdraw 0.5s linear infinite;
|
animation: dashdraw 0.5s linear infinite;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import type {
|
|||||||
EdgeMouseHandler,
|
EdgeMouseHandler,
|
||||||
HandleType,
|
HandleType,
|
||||||
SelectionMode,
|
SelectionMode,
|
||||||
|
OnError,
|
||||||
} from '.';
|
} from '.';
|
||||||
|
|
||||||
export type ReactFlowProps = HTMLAttributes<HTMLDivElement> & {
|
export type ReactFlowProps = HTMLAttributes<HTMLDivElement> & {
|
||||||
@@ -142,6 +143,7 @@ export type ReactFlowProps = HTMLAttributes<HTMLDivElement> & {
|
|||||||
autoPanOnNodeDrag?: boolean;
|
autoPanOnNodeDrag?: boolean;
|
||||||
autoPanOnConnect?: boolean;
|
autoPanOnConnect?: boolean;
|
||||||
connectionRadius?: number;
|
connectionRadius?: number;
|
||||||
|
onError?: OnError;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ReactFlowRefType = HTMLDivElement;
|
export type ReactFlowRefType = HTMLDivElement;
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ export type ReactFlowStore = {
|
|||||||
|
|
||||||
onNodesDelete?: OnNodesDelete;
|
onNodesDelete?: OnNodesDelete;
|
||||||
onEdgesDelete?: OnEdgesDelete;
|
onEdgesDelete?: OnEdgesDelete;
|
||||||
|
onError?: OnError;
|
||||||
|
|
||||||
// event handlers
|
// event handlers
|
||||||
onViewportChangeStart?: OnViewportChange;
|
onViewportChangeStart?: OnViewportChange;
|
||||||
@@ -270,3 +271,5 @@ export type SelectionRect = Rect & {
|
|||||||
startX: number;
|
startX: number;
|
||||||
startY: number;
|
startY: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type OnError = (id: string, message: string) => void;
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ const connectionExists = (edge: Edge, edges: Edge[]) => {
|
|||||||
|
|
||||||
export const addEdge = (edgeParams: Edge | Connection, edges: Edge[]): Edge[] => {
|
export const addEdge = (edgeParams: Edge | Connection, edges: Edge[]): Edge[] => {
|
||||||
if (!edgeParams.source || !edgeParams.target) {
|
if (!edgeParams.source || !edgeParams.target) {
|
||||||
devWarn("Can't create edge. An edge needs a source and a target. Help: https://reactflow.dev/error#600");
|
devWarn('006', "Can't create edge. An edge needs a source and a target.");
|
||||||
|
|
||||||
return edges;
|
return edges;
|
||||||
}
|
}
|
||||||
@@ -94,7 +94,7 @@ export const addEdge = (edgeParams: Edge | Connection, edges: Edge[]): Edge[] =>
|
|||||||
|
|
||||||
export const updateEdge = (oldEdge: Edge, newConnection: Connection, edges: Edge[]): Edge[] => {
|
export const updateEdge = (oldEdge: Edge, newConnection: Connection, edges: Edge[]): Edge[] => {
|
||||||
if (!newConnection.source || !newConnection.target) {
|
if (!newConnection.source || !newConnection.target) {
|
||||||
devWarn("Can't create a new edge. An edge needs a source and a target. Help: https://reactflow.dev/error#600");
|
devWarn('006', "Can't create a new edge. An edge needs a source and a target.");
|
||||||
|
|
||||||
return edges;
|
return edges;
|
||||||
}
|
}
|
||||||
@@ -102,7 +102,7 @@ export const updateEdge = (oldEdge: Edge, newConnection: Connection, edges: Edge
|
|||||||
const foundEdge = edges.find((e) => e.id === oldEdge.id) as Edge;
|
const foundEdge = edges.find((e) => e.id === oldEdge.id) as Edge;
|
||||||
|
|
||||||
if (!foundEdge) {
|
if (!foundEdge) {
|
||||||
devWarn(`The old edge with id=${oldEdge.id} does not exist. Help: https://reactflow.dev/error#700`);
|
devWarn('007', `The old edge with id=${oldEdge.id} does not exist.`);
|
||||||
|
|
||||||
return edges;
|
return edges;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,9 +89,9 @@ export const internalsSymbol = Symbol.for('internals');
|
|||||||
// used for a11y key board controls for nodes and edges
|
// used for a11y key board controls for nodes and edges
|
||||||
export const elementSelectionKeys = ['Enter', ' ', 'Escape'];
|
export const elementSelectionKeys = ['Enter', ' ', 'Escape'];
|
||||||
|
|
||||||
export const devWarn = (message: string) => {
|
export const devWarn = (id: string, message: string) => {
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
console.warn(`[React Flow]: ${message}`);
|
console.warn(`[React Flow]: ${message} Help: https://reactflow.dev/error#${id}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user