refactor(react): cleanup useReactFlow
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import {
|
import {
|
||||||
evaluateAbsolutePosition,
|
evaluateAbsolutePosition,
|
||||||
getElementsToRemove,
|
getElementsToRemove,
|
||||||
@@ -9,10 +9,12 @@ import {
|
|||||||
} from '@xyflow/system';
|
} from '@xyflow/system';
|
||||||
|
|
||||||
import useViewportHelper from './useViewportHelper';
|
import useViewportHelper from './useViewportHelper';
|
||||||
import { useStoreApi } from './useStore';
|
import { useStore, useStoreApi } from './useStore';
|
||||||
import { useBatchContext } from '../components/BatchProvider';
|
import { useBatchContext } from '../components/BatchProvider';
|
||||||
import { isNode } from '../utils';
|
import { isNode } from '../utils';
|
||||||
import type { ReactFlowInstance, Instance, Node, Edge, InternalNode } from '../types';
|
import type { ReactFlowInstance, Node, Edge, InternalNode, ReactFlowState, GeneralHelpers } from '../types';
|
||||||
|
|
||||||
|
const selector = (s: ReactFlowState) => !!s.panZoom;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook for accessing the ReactFlow instance.
|
* Hook for accessing the ReactFlow instance.
|
||||||
@@ -27,185 +29,40 @@ export function useReactFlow<NodeType extends Node = Node, EdgeType extends Edge
|
|||||||
const viewportHelper = useViewportHelper();
|
const viewportHelper = useViewportHelper();
|
||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
const batchContext = useBatchContext();
|
const batchContext = useBatchContext();
|
||||||
|
const viewportInitialized = useStore(selector);
|
||||||
|
|
||||||
const getNodes = useCallback<Instance.GetNodes<NodeType>>(
|
const generalHelper = useMemo<GeneralHelpers<NodeType, EdgeType>>(() => {
|
||||||
() => store.getState().nodes.map((n) => ({ ...n })) as NodeType[],
|
const getInternalNode: GeneralHelpers<NodeType, EdgeType>['getInternalNode'] = (id) =>
|
||||||
[]
|
store.getState().nodeLookup.get(id) as InternalNode<NodeType>;
|
||||||
);
|
|
||||||
|
|
||||||
const getInternalNode = useCallback<Instance.GetInternalNode<NodeType>>(
|
const setNodes: GeneralHelpers<NodeType, EdgeType>['setNodes'] = (payload) => {
|
||||||
(id) => store.getState().nodeLookup.get(id) as InternalNode<NodeType>,
|
batchContext.nodeQueue.push(payload as NodeType[]);
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const getNode = useCallback<Instance.GetNode<NodeType>>(
|
|
||||||
(id) => getInternalNode(id)?.internals.userNode as NodeType,
|
|
||||||
[getInternalNode]
|
|
||||||
);
|
|
||||||
|
|
||||||
const getEdges = useCallback<Instance.GetEdges<EdgeType>>(() => {
|
|
||||||
const { edges = [] } = store.getState();
|
|
||||||
return edges.map((e) => ({ ...e })) as EdgeType[];
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const getEdge = useCallback<Instance.GetEdge<EdgeType>>((id) => store.getState().edgeLookup.get(id) as EdgeType, []);
|
|
||||||
|
|
||||||
const setNodes = useCallback<Instance.SetNodes<NodeType>>((payload) => {
|
|
||||||
batchContext.nodeQueue.push(payload as NodeType[]);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const setEdges = useCallback<Instance.SetEdges<EdgeType>>((payload) => {
|
|
||||||
batchContext.edgeQueue.push(payload as EdgeType[]);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const addNodes = useCallback<Instance.AddNodes<NodeType>>((payload) => {
|
|
||||||
const newNodes = Array.isArray(payload) ? payload : [payload];
|
|
||||||
batchContext.nodeQueue.push((nodes) => [...nodes, ...newNodes]);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const addEdges = useCallback<Instance.AddEdges<EdgeType>>((payload) => {
|
|
||||||
const newEdges = Array.isArray(payload) ? payload : [payload];
|
|
||||||
batchContext.edgeQueue.push((edges) => [...edges, ...newEdges]);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const toObject = useCallback<Instance.ToObject<NodeType, EdgeType>>(() => {
|
|
||||||
const { nodes = [], edges = [], transform } = store.getState();
|
|
||||||
const [x, y, zoom] = transform;
|
|
||||||
return {
|
|
||||||
nodes: nodes.map((n) => ({ ...n })) as NodeType[],
|
|
||||||
edges: edges.map((e) => ({ ...e })) as EdgeType[],
|
|
||||||
viewport: {
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
zoom,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const deleteElements = useCallback<Instance.DeleteElements>(
|
|
||||||
async ({ nodes: nodesToRemove = [], edges: edgesToRemove = [] }) => {
|
|
||||||
const {
|
|
||||||
nodes,
|
|
||||||
edges,
|
|
||||||
hasDefaultNodes,
|
|
||||||
hasDefaultEdges,
|
|
||||||
onNodesDelete,
|
|
||||||
onEdgesDelete,
|
|
||||||
onNodesChange,
|
|
||||||
onEdgesChange,
|
|
||||||
onDelete,
|
|
||||||
onBeforeDelete,
|
|
||||||
} = store.getState();
|
|
||||||
const { nodes: matchingNodes, edges: matchingEdges } = await getElementsToRemove({
|
|
||||||
nodesToRemove,
|
|
||||||
edgesToRemove,
|
|
||||||
nodes,
|
|
||||||
edges,
|
|
||||||
onBeforeDelete,
|
|
||||||
});
|
|
||||||
|
|
||||||
const hasMatchingEdges = matchingEdges.length > 0;
|
|
||||||
const hasMatchingNodes = matchingNodes.length > 0;
|
|
||||||
|
|
||||||
if (hasMatchingEdges) {
|
|
||||||
if (hasDefaultEdges) {
|
|
||||||
const nextEdges = edges.filter((e) => !matchingEdges.some((mE) => mE.id === e.id));
|
|
||||||
store.getState().setEdges(nextEdges);
|
|
||||||
}
|
|
||||||
|
|
||||||
onEdgesDelete?.(matchingEdges);
|
|
||||||
onEdgesChange?.(
|
|
||||||
matchingEdges.map((edge) => ({
|
|
||||||
id: edge.id,
|
|
||||||
type: 'remove',
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasMatchingNodes) {
|
|
||||||
if (hasDefaultNodes) {
|
|
||||||
const nextNodes = nodes.filter((n) => !matchingNodes.some((mN) => mN.id === n.id));
|
|
||||||
store.getState().setNodes(nextNodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
onNodesDelete?.(matchingNodes);
|
|
||||||
onNodesChange?.(matchingNodes.map((node) => ({ id: node.id, type: 'remove' })));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasMatchingNodes || hasMatchingEdges) {
|
|
||||||
onDelete?.({ nodes: matchingNodes, edges: matchingEdges });
|
|
||||||
}
|
|
||||||
|
|
||||||
return { deletedNodes: matchingNodes, deletedEdges: matchingEdges };
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const getNodeRect = useCallback((node: NodeType | { id: string }): Rect | null => {
|
|
||||||
const { nodeLookup, nodeOrigin } = store.getState();
|
|
||||||
|
|
||||||
const nodeToUse = isNode<NodeType>(node) ? node : nodeLookup.get(node.id)!;
|
|
||||||
const position = nodeToUse.parentId
|
|
||||||
? evaluateAbsolutePosition(nodeToUse.position, nodeToUse.parentId, nodeLookup, nodeOrigin)
|
|
||||||
: nodeToUse.position;
|
|
||||||
|
|
||||||
const nodeWithPosition = {
|
|
||||||
id: nodeToUse.id,
|
|
||||||
position,
|
|
||||||
width: nodeToUse.measured?.width ?? nodeToUse.width,
|
|
||||||
height: nodeToUse.measured?.height ?? nodeToUse.height,
|
|
||||||
data: nodeToUse.data,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return nodeToRect(nodeWithPosition);
|
const getNodeRect = (node: NodeType | { id: string }): Rect | null => {
|
||||||
}, []);
|
const { nodeLookup, nodeOrigin } = store.getState();
|
||||||
|
|
||||||
const getIntersectingNodes = useCallback<Instance.GetIntersectingNodes<NodeType>>(
|
const nodeToUse = isNode<NodeType>(node) ? node : nodeLookup.get(node.id)!;
|
||||||
(nodeOrRect, partially = true, nodes) => {
|
const position = nodeToUse.parentId
|
||||||
const isRect = isRectObject(nodeOrRect);
|
? evaluateAbsolutePosition(nodeToUse.position, nodeToUse.parentId, nodeLookup, nodeOrigin)
|
||||||
const nodeRect = isRect ? nodeOrRect : getNodeRect(nodeOrRect);
|
: nodeToUse.position;
|
||||||
const hasNodesOption = nodes !== undefined;
|
|
||||||
|
|
||||||
if (!nodeRect) {
|
const nodeWithPosition = {
|
||||||
return [];
|
id: nodeToUse.id,
|
||||||
}
|
position,
|
||||||
|
width: nodeToUse.measured?.width ?? nodeToUse.width,
|
||||||
|
height: nodeToUse.measured?.height ?? nodeToUse.height,
|
||||||
|
data: nodeToUse.data,
|
||||||
|
};
|
||||||
|
|
||||||
return (nodes || store.getState().nodes).filter((n) => {
|
return nodeToRect(nodeWithPosition);
|
||||||
const internalNode = store.getState().nodeLookup.get(n.id);
|
};
|
||||||
|
|
||||||
if (internalNode && !isRect && (n.id === nodeOrRect!.id || !internalNode.internals.positionAbsolute)) {
|
const updateNode: GeneralHelpers<NodeType, EdgeType>['updateNode'] = (
|
||||||
return false;
|
id,
|
||||||
}
|
nodeUpdate,
|
||||||
|
options = { replace: false }
|
||||||
const currNodeRect = nodeToRect(hasNodesOption ? n : internalNode!);
|
) => {
|
||||||
const overlappingArea = getOverlappingArea(currNodeRect, nodeRect);
|
|
||||||
const partiallyVisible = partially && overlappingArea > 0;
|
|
||||||
|
|
||||||
return partiallyVisible || overlappingArea >= nodeRect.width * nodeRect.height;
|
|
||||||
}) as NodeType[];
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const isNodeIntersecting = useCallback<Instance.IsNodeIntersecting<NodeType>>(
|
|
||||||
(nodeOrRect, area, partially = true) => {
|
|
||||||
const isRect = isRectObject(nodeOrRect);
|
|
||||||
const nodeRect = isRect ? nodeOrRect : getNodeRect(nodeOrRect);
|
|
||||||
|
|
||||||
if (!nodeRect) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const overlappingArea = getOverlappingArea(nodeRect, area);
|
|
||||||
const partiallyVisible = partially && overlappingArea > 0;
|
|
||||||
|
|
||||||
return partiallyVisible || overlappingArea >= nodeRect.width * nodeRect.height;
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const updateNode = useCallback<Instance.UpdateNode<NodeType>>(
|
|
||||||
(id, nodeUpdate, options = { replace: false }) => {
|
|
||||||
setNodes((prevNodes) =>
|
setNodes((prevNodes) =>
|
||||||
prevNodes.map((node) => {
|
prevNodes.map((node) => {
|
||||||
if (node.id === id) {
|
if (node.id === id) {
|
||||||
@@ -216,59 +73,152 @@ export function useReactFlow<NodeType extends Node = Node, EdgeType extends Edge
|
|||||||
return node;
|
return node;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
};
|
||||||
[setNodes]
|
|
||||||
);
|
|
||||||
|
|
||||||
const updateNodeData = useCallback<Instance.UpdateNodeData<NodeType>>(
|
return {
|
||||||
(id, dataUpdate, options = { replace: false }) => {
|
getNodes: () => store.getState().nodes.map((n) => ({ ...n })) as NodeType[],
|
||||||
updateNode(
|
getNode: (id) => getInternalNode(id)?.internals.userNode as NodeType,
|
||||||
id,
|
getInternalNode,
|
||||||
(node) => {
|
getEdges: () => {
|
||||||
const nextData = typeof dataUpdate === 'function' ? dataUpdate(node) : dataUpdate;
|
const { edges = [] } = store.getState();
|
||||||
return options.replace ? { ...node, data: nextData } : { ...node, data: { ...node.data, ...nextData } };
|
return edges.map((e) => ({ ...e })) as EdgeType[];
|
||||||
},
|
},
|
||||||
options
|
getEdge: (id) => store.getState().edgeLookup.get(id) as EdgeType,
|
||||||
);
|
setNodes,
|
||||||
},
|
setEdges: (payload) => {
|
||||||
[updateNode]
|
batchContext.edgeQueue.push(payload as EdgeType[]);
|
||||||
);
|
},
|
||||||
|
addNodes: (payload) => {
|
||||||
|
const newNodes = Array.isArray(payload) ? payload : [payload];
|
||||||
|
batchContext.nodeQueue.push((nodes) => [...nodes, ...newNodes]);
|
||||||
|
},
|
||||||
|
addEdges: (payload) => {
|
||||||
|
const newEdges = Array.isArray(payload) ? payload : [payload];
|
||||||
|
batchContext.edgeQueue.push((edges) => [...edges, ...newEdges]);
|
||||||
|
},
|
||||||
|
toObject: () => {
|
||||||
|
const { nodes = [], edges = [], transform } = store.getState();
|
||||||
|
const [x, y, zoom] = transform;
|
||||||
|
return {
|
||||||
|
nodes: nodes.map((n) => ({ ...n })) as NodeType[],
|
||||||
|
edges: edges.map((e) => ({ ...e })) as EdgeType[],
|
||||||
|
viewport: {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
zoom,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
deleteElements: async ({ nodes: nodesToRemove = [], edges: edgesToRemove = [] }) => {
|
||||||
|
const {
|
||||||
|
nodes,
|
||||||
|
edges,
|
||||||
|
hasDefaultNodes,
|
||||||
|
hasDefaultEdges,
|
||||||
|
onNodesDelete,
|
||||||
|
onEdgesDelete,
|
||||||
|
onNodesChange,
|
||||||
|
onEdgesChange,
|
||||||
|
onDelete,
|
||||||
|
onBeforeDelete,
|
||||||
|
} = store.getState();
|
||||||
|
const { nodes: matchingNodes, edges: matchingEdges } = await getElementsToRemove({
|
||||||
|
nodesToRemove,
|
||||||
|
edgesToRemove,
|
||||||
|
nodes,
|
||||||
|
edges,
|
||||||
|
onBeforeDelete,
|
||||||
|
});
|
||||||
|
|
||||||
|
const hasMatchingEdges = matchingEdges.length > 0;
|
||||||
|
const hasMatchingNodes = matchingNodes.length > 0;
|
||||||
|
|
||||||
|
if (hasMatchingEdges) {
|
||||||
|
if (hasDefaultEdges) {
|
||||||
|
const nextEdges = edges.filter((e) => !matchingEdges.some((mE) => mE.id === e.id));
|
||||||
|
store.getState().setEdges(nextEdges);
|
||||||
|
}
|
||||||
|
|
||||||
|
onEdgesDelete?.(matchingEdges);
|
||||||
|
onEdgesChange?.(
|
||||||
|
matchingEdges.map((edge) => ({
|
||||||
|
id: edge.id,
|
||||||
|
type: 'remove',
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasMatchingNodes) {
|
||||||
|
if (hasDefaultNodes) {
|
||||||
|
const nextNodes = nodes.filter((n) => !matchingNodes.some((mN) => mN.id === n.id));
|
||||||
|
store.getState().setNodes(nextNodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
onNodesDelete?.(matchingNodes);
|
||||||
|
onNodesChange?.(matchingNodes.map((node) => ({ id: node.id, type: 'remove' })));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasMatchingNodes || hasMatchingEdges) {
|
||||||
|
onDelete?.({ nodes: matchingNodes, edges: matchingEdges });
|
||||||
|
}
|
||||||
|
|
||||||
|
return { deletedNodes: matchingNodes, deletedEdges: matchingEdges };
|
||||||
|
},
|
||||||
|
getIntersectingNodes: (nodeOrRect, partially = true, nodes) => {
|
||||||
|
const isRect = isRectObject(nodeOrRect);
|
||||||
|
const nodeRect = isRect ? nodeOrRect : getNodeRect(nodeOrRect);
|
||||||
|
const hasNodesOption = nodes !== undefined;
|
||||||
|
|
||||||
|
if (!nodeRect) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (nodes || store.getState().nodes).filter((n) => {
|
||||||
|
const internalNode = store.getState().nodeLookup.get(n.id);
|
||||||
|
|
||||||
|
if (internalNode && !isRect && (n.id === nodeOrRect!.id || !internalNode.internals.positionAbsolute)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currNodeRect = nodeToRect(hasNodesOption ? n : internalNode!);
|
||||||
|
const overlappingArea = getOverlappingArea(currNodeRect, nodeRect);
|
||||||
|
const partiallyVisible = partially && overlappingArea > 0;
|
||||||
|
|
||||||
|
return partiallyVisible || overlappingArea >= nodeRect.width * nodeRect.height;
|
||||||
|
}) as NodeType[];
|
||||||
|
},
|
||||||
|
isNodeIntersecting: (nodeOrRect, area, partially = true) => {
|
||||||
|
const isRect = isRectObject(nodeOrRect);
|
||||||
|
const nodeRect = isRect ? nodeOrRect : getNodeRect(nodeOrRect);
|
||||||
|
|
||||||
|
if (!nodeRect) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const overlappingArea = getOverlappingArea(nodeRect, area);
|
||||||
|
const partiallyVisible = partially && overlappingArea > 0;
|
||||||
|
|
||||||
|
return partiallyVisible || overlappingArea >= nodeRect.width * nodeRect.height;
|
||||||
|
},
|
||||||
|
updateNode,
|
||||||
|
updateNodeData: (id, dataUpdate, options = { replace: false }) => {
|
||||||
|
updateNode(
|
||||||
|
id,
|
||||||
|
(node) => {
|
||||||
|
const nextData = typeof dataUpdate === 'function' ? dataUpdate(node) : dataUpdate;
|
||||||
|
return options.replace ? { ...node, data: nextData } : { ...node, data: { ...node.data, ...nextData } };
|
||||||
|
},
|
||||||
|
options
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
return {
|
return {
|
||||||
|
...generalHelper,
|
||||||
...viewportHelper,
|
...viewportHelper,
|
||||||
getNodes,
|
viewportInitialized,
|
||||||
getNode,
|
|
||||||
getInternalNode,
|
|
||||||
getEdges,
|
|
||||||
getEdge,
|
|
||||||
setNodes,
|
|
||||||
setEdges,
|
|
||||||
addNodes,
|
|
||||||
addEdges,
|
|
||||||
toObject,
|
|
||||||
deleteElements,
|
|
||||||
getIntersectingNodes,
|
|
||||||
isNodeIntersecting,
|
|
||||||
updateNode,
|
|
||||||
updateNodeData,
|
|
||||||
};
|
};
|
||||||
}, [
|
}, [viewportInitialized]);
|
||||||
viewportHelper,
|
|
||||||
getNodes,
|
|
||||||
getNode,
|
|
||||||
getInternalNode,
|
|
||||||
getEdges,
|
|
||||||
getEdge,
|
|
||||||
setNodes,
|
|
||||||
setEdges,
|
|
||||||
addNodes,
|
|
||||||
addEdges,
|
|
||||||
toObject,
|
|
||||||
deleteElements,
|
|
||||||
getIntersectingNodes,
|
|
||||||
isNodeIntersecting,
|
|
||||||
updateNode,
|
|
||||||
updateNodeData,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,8 @@ import {
|
|||||||
rendererPointToPoint,
|
rendererPointToPoint,
|
||||||
} from '@xyflow/system';
|
} from '@xyflow/system';
|
||||||
|
|
||||||
import { useStoreApi, useStore } from '../hooks/useStore';
|
import { useStoreApi } from '../hooks/useStore';
|
||||||
import type { ViewportHelperFunctions, ReactFlowState } from '../types';
|
import type { ViewportHelperFunctions } from '../types';
|
||||||
|
|
||||||
const selector = (s: ReactFlowState) => !!s.panZoom;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook for getting viewport helper functions.
|
* Hook for getting viewport helper functions.
|
||||||
@@ -20,9 +18,8 @@ const selector = (s: ReactFlowState) => !!s.panZoom;
|
|||||||
*/
|
*/
|
||||||
const useViewportHelper = (): ViewportHelperFunctions => {
|
const useViewportHelper = (): ViewportHelperFunctions => {
|
||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
const panZoomInitialized = useStore(selector);
|
|
||||||
|
|
||||||
const viewportHelperFunctions = useMemo<ViewportHelperFunctions>(() => {
|
return useMemo<ViewportHelperFunctions>(() => {
|
||||||
return {
|
return {
|
||||||
zoomIn: (options) => store.getState().panZoom?.scaleBy(1.2, { duration: options?.duration }),
|
zoomIn: (options) => store.getState().panZoom?.scaleBy(1.2, { duration: options?.duration }),
|
||||||
zoomOut: (options) => store.getState().panZoom?.scaleBy(1 / 1.2, { duration: options?.duration }),
|
zoomOut: (options) => store.getState().panZoom?.scaleBy(1 / 1.2, { duration: options?.duration }),
|
||||||
@@ -117,11 +114,8 @@ const useViewportHelper = (): ViewportHelperFunctions => {
|
|||||||
y: rendererPosition.y + domY,
|
y: rendererPosition.y + domY,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
viewportInitialized: panZoomInitialized,
|
|
||||||
};
|
};
|
||||||
}, [panZoomInitialized]);
|
}, []);
|
||||||
|
|
||||||
return viewportHelperFunctions;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useViewportHelper;
|
export default useViewportHelper;
|
||||||
|
|||||||
@@ -156,7 +156,6 @@ export type ViewportHelperFunctions = {
|
|||||||
* const clientPosition = flowToScreenPosition({ x: node.position.x, y: node.position.y })
|
* const clientPosition = flowToScreenPosition({ x: node.position.x, y: node.position.y })
|
||||||
*/
|
*/
|
||||||
flowToScreenPosition: (flowPosition: XYPosition) => XYPosition;
|
flowToScreenPosition: (flowPosition: XYPosition) => XYPosition;
|
||||||
viewportInitialized: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type OnBeforeDelete<NodeType extends Node = Node, EdgeType extends Edge = Edge> = OnBeforeDeleteBase<
|
export type OnBeforeDelete<NodeType extends Node = Node, EdgeType extends Edge = Edge> = OnBeforeDeleteBase<
|
||||||
|
|||||||
@@ -13,115 +13,70 @@ export type DeleteElementsOptions = {
|
|||||||
edges?: (Edge | { id: Edge['id'] })[];
|
edges?: (Edge | { id: Edge['id'] })[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export namespace Instance {
|
export type GeneralHelpers<NodeType extends Node = Node, EdgeType extends Edge = Edge> = {
|
||||||
export type GetNodes<NodeType extends Node = Node> = () => NodeType[];
|
|
||||||
export type SetNodes<NodeType extends Node = Node> = (
|
|
||||||
payload: NodeType[] | ((nodes: NodeType[]) => NodeType[])
|
|
||||||
) => void;
|
|
||||||
export type AddNodes<NodeType extends Node = Node> = (payload: NodeType[] | NodeType) => void;
|
|
||||||
export type GetNode<NodeType extends Node = Node> = (id: string) => NodeType | undefined;
|
|
||||||
export type GetInternalNode<NodeType extends Node = Node> = (id: string) => InternalNode<NodeType> | undefined;
|
|
||||||
export type GetEdges<EdgeType extends Edge = Edge> = () => EdgeType[];
|
|
||||||
export type SetEdges<EdgeType extends Edge = Edge> = (
|
|
||||||
payload: EdgeType[] | ((edges: EdgeType[]) => EdgeType[])
|
|
||||||
) => void;
|
|
||||||
export type GetEdge<EdgeType extends Edge = Edge> = (id: string) => EdgeType | undefined;
|
|
||||||
export type AddEdges<EdgeType extends Edge = Edge> = (payload: EdgeType[] | EdgeType) => void;
|
|
||||||
export type ToObject<NodeType extends Node = Node, EdgeType extends Edge = Edge> = () => ReactFlowJsonObject<
|
|
||||||
NodeType,
|
|
||||||
EdgeType
|
|
||||||
>;
|
|
||||||
export type DeleteElements = (params: DeleteElementsOptions) => Promise<{
|
|
||||||
deletedNodes: Node[];
|
|
||||||
deletedEdges: Edge[];
|
|
||||||
}>;
|
|
||||||
export type GetIntersectingNodes<NodeType extends Node = Node> = (
|
|
||||||
node: NodeType | { id: Node['id'] } | Rect,
|
|
||||||
partially?: boolean,
|
|
||||||
nodes?: NodeType[]
|
|
||||||
) => NodeType[];
|
|
||||||
export type IsNodeIntersecting<NodeType extends Node = Node> = (
|
|
||||||
node: NodeType | { id: Node['id'] } | Rect,
|
|
||||||
area: Rect,
|
|
||||||
partially?: boolean
|
|
||||||
) => boolean;
|
|
||||||
|
|
||||||
export type UpdateNode<NodeType extends Node = Node> = (
|
|
||||||
id: string,
|
|
||||||
nodeUpdate: Partial<NodeType> | ((node: NodeType) => Partial<NodeType>),
|
|
||||||
options?: { replace: boolean }
|
|
||||||
) => void;
|
|
||||||
export type UpdateNodeData<NodeType extends Node = Node> = (
|
|
||||||
id: string,
|
|
||||||
dataUpdate: object | ((node: NodeType) => object),
|
|
||||||
options?: { replace: boolean }
|
|
||||||
) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ReactFlowInstance<NodeType extends Node = Node, EdgeType extends Edge = Edge> = {
|
|
||||||
/**
|
/**
|
||||||
* Returns nodes.
|
* Returns nodes.
|
||||||
*
|
*
|
||||||
* @returns nodes array
|
* @returns nodes array
|
||||||
*/
|
*/
|
||||||
getNodes: Instance.GetNodes<NodeType>;
|
getNodes: () => NodeType[];
|
||||||
/**
|
/**
|
||||||
* Sets nodes.
|
* Sets nodes.
|
||||||
*
|
*
|
||||||
* @param payload - the nodes to set or a function that receives the current nodes and returns the new nodes
|
* @param payload - the nodes to set or a function that receives the current nodes and returns the new nodes
|
||||||
*/
|
*/
|
||||||
setNodes: Instance.SetNodes<NodeType>;
|
setNodes: (payload: NodeType[] | ((nodes: NodeType[]) => NodeType[])) => void;
|
||||||
/**
|
/**
|
||||||
* Adds nodes.
|
* Adds nodes.
|
||||||
*
|
*
|
||||||
* @param payload - the nodes to add
|
* @param payload - the nodes to add
|
||||||
*/
|
*/
|
||||||
addNodes: Instance.AddNodes<NodeType>;
|
addNodes: (payload: NodeType[] | NodeType) => void;
|
||||||
/**
|
/**
|
||||||
* Returns a node by id.
|
* Returns a node by id.
|
||||||
*
|
*
|
||||||
* @param id - the node id
|
* @param id - the node id
|
||||||
* @returns the node or undefined if no node was found
|
* @returns the node or undefined if no node was found
|
||||||
*/
|
*/
|
||||||
getNode: Instance.GetNode<NodeType>;
|
getNode: (id: string) => NodeType | undefined;
|
||||||
/**
|
/**
|
||||||
* Returns an internal node by id.
|
* Returns an internal node by id.
|
||||||
*
|
*
|
||||||
* @param id - the node id
|
* @param id - the node id
|
||||||
* @returns the internal node or undefined if no node was found
|
* @returns the internal node or undefined if no node was found
|
||||||
*/
|
*/
|
||||||
getInternalNode: Instance.GetInternalNode<NodeType>;
|
getInternalNode: (id: string) => InternalNode<NodeType> | undefined;
|
||||||
/**
|
/**
|
||||||
* Returns edges.
|
* Returns edges.
|
||||||
*
|
*
|
||||||
* @returns edges array
|
* @returns edges array
|
||||||
*/
|
*/
|
||||||
getEdges: Instance.GetEdges<EdgeType>;
|
getEdges: () => EdgeType[];
|
||||||
/**
|
/**
|
||||||
* Sets edges.
|
* Sets edges.
|
||||||
*
|
*
|
||||||
* @param payload - the edges to set or a function that receives the current edges and returns the new edges
|
* @param payload - the edges to set or a function that receives the current edges and returns the new edges
|
||||||
*/
|
*/
|
||||||
setEdges: Instance.SetEdges<EdgeType>;
|
setEdges: (payload: EdgeType[] | ((edges: EdgeType[]) => EdgeType[])) => void;
|
||||||
/**
|
/**
|
||||||
* Adds edges.
|
* Adds edges.
|
||||||
*
|
*
|
||||||
* @param payload - the edges to add
|
* @param payload - the edges to add
|
||||||
*/
|
*/
|
||||||
addEdges: Instance.AddEdges<EdgeType>;
|
addEdges: (payload: EdgeType[] | EdgeType) => void;
|
||||||
/**
|
/**
|
||||||
* Returns an edge by id.
|
* Returns an edge by id.
|
||||||
*
|
*
|
||||||
* @param id - the edge id
|
* @param id - the edge id
|
||||||
* @returns the edge or undefined if no edge was found
|
* @returns the edge or undefined if no edge was found
|
||||||
*/
|
*/
|
||||||
getEdge: Instance.GetEdge<EdgeType>;
|
getEdge: (id: string) => EdgeType | undefined;
|
||||||
/**
|
/**
|
||||||
* Returns the nodes, edges and the viewport as a JSON object.
|
* Returns the nodes, edges and the viewport as a JSON object.
|
||||||
*
|
*
|
||||||
* @returns the nodes, edges and the viewport as a JSON object
|
* @returns the nodes, edges and the viewport as a JSON object
|
||||||
*/
|
*/
|
||||||
toObject: Instance.ToObject<NodeType, EdgeType>;
|
toObject: () => ReactFlowJsonObject<NodeType, EdgeType>;
|
||||||
/**
|
/**
|
||||||
* Deletes nodes and edges.
|
* Deletes nodes and edges.
|
||||||
*
|
*
|
||||||
@@ -130,7 +85,10 @@ export type ReactFlowInstance<NodeType extends Node = Node, EdgeType extends Edg
|
|||||||
*
|
*
|
||||||
* @returns a promise that resolves with the deleted nodes and edges
|
* @returns a promise that resolves with the deleted nodes and edges
|
||||||
*/
|
*/
|
||||||
deleteElements: Instance.DeleteElements;
|
deleteElements: (params: DeleteElementsOptions) => Promise<{
|
||||||
|
deletedNodes: Node[];
|
||||||
|
deletedEdges: Edge[];
|
||||||
|
}>;
|
||||||
/**
|
/**
|
||||||
* Returns all nodes that intersect with the given node or rect.
|
* Returns all nodes that intersect with the given node or rect.
|
||||||
*
|
*
|
||||||
@@ -140,7 +98,11 @@ export type ReactFlowInstance<NodeType extends Node = Node, EdgeType extends Edg
|
|||||||
*
|
*
|
||||||
* @returns an array of intersecting nodes
|
* @returns an array of intersecting nodes
|
||||||
*/
|
*/
|
||||||
getIntersectingNodes: Instance.GetIntersectingNodes<NodeType>;
|
getIntersectingNodes: (
|
||||||
|
node: NodeType | { id: Node['id'] } | Rect,
|
||||||
|
partially?: boolean,
|
||||||
|
nodes?: NodeType[]
|
||||||
|
) => NodeType[];
|
||||||
/**
|
/**
|
||||||
* Checks if the given node or rect intersects with the passed rect.
|
* Checks if the given node or rect intersects with the passed rect.
|
||||||
*
|
*
|
||||||
@@ -150,7 +112,7 @@ export type ReactFlowInstance<NodeType extends Node = Node, EdgeType extends Edg
|
|||||||
*
|
*
|
||||||
* @returns true if the node or rect intersects with the given area
|
* @returns true if the node or rect intersects with the given area
|
||||||
*/
|
*/
|
||||||
isNodeIntersecting: Instance.IsNodeIntersecting<NodeType>;
|
isNodeIntersecting: (node: NodeType | { id: Node['id'] } | Rect, area: Rect, partially?: boolean) => boolean;
|
||||||
/**
|
/**
|
||||||
* Updates a node.
|
* Updates a node.
|
||||||
*
|
*
|
||||||
@@ -161,7 +123,11 @@ export type ReactFlowInstance<NodeType extends Node = Node, EdgeType extends Edg
|
|||||||
* @example
|
* @example
|
||||||
* updateNode('node-1', (node) => ({ position: { x: node.position.x + 10, y: node.position.y } }));
|
* updateNode('node-1', (node) => ({ position: { x: node.position.x + 10, y: node.position.y } }));
|
||||||
*/
|
*/
|
||||||
updateNode: Instance.UpdateNode<NodeType>;
|
updateNode: (
|
||||||
|
id: string,
|
||||||
|
nodeUpdate: Partial<NodeType> | ((node: NodeType) => Partial<NodeType>),
|
||||||
|
options?: { replace: boolean }
|
||||||
|
) => void;
|
||||||
/**
|
/**
|
||||||
* Updates the data attribute of a node.
|
* Updates the data attribute of a node.
|
||||||
*
|
*
|
||||||
@@ -172,6 +138,17 @@ export type ReactFlowInstance<NodeType extends Node = Node, EdgeType extends Edg
|
|||||||
* @example
|
* @example
|
||||||
* updateNodeData('node-1', { label: 'A new label' });
|
* updateNodeData('node-1', { label: 'A new label' });
|
||||||
*/
|
*/
|
||||||
updateNodeData: Instance.UpdateNodeData<NodeType>;
|
updateNodeData: (
|
||||||
viewportInitialized: boolean;
|
id: string,
|
||||||
} & Omit<ViewportHelperFunctions, 'initialized'>;
|
dataUpdate: object | ((node: NodeType) => object),
|
||||||
|
options?: { replace: boolean }
|
||||||
|
) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ReactFlowInstance<NodeType extends Node = Node, EdgeType extends Edge = Edge> = GeneralHelpers<
|
||||||
|
NodeType,
|
||||||
|
EdgeType
|
||||||
|
> &
|
||||||
|
Omit<ViewportHelperFunctions, 'initialized'> & {
|
||||||
|
viewportInitialized: boolean;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user