Files
xyflow/src/hooks/useElementUpdater.ts
T

125 lines
4.0 KiB
TypeScript

import { useEffect } from 'react';
import isEqual from 'fast-deep-equal';
import { useStoreState, useStoreActions } from '../store/hooks';
import { parseElement, isNode, isEdge } from '../utils/graph';
import { Elements, Node, Edge, FlowElement } from '../types';
const useElementUpdater = (propElements: Elements): void => {
const stateElements = useStoreState((state) => state.elements);
const setElements = useStoreActions((actions) => actions.setElements);
useEffect(() => {
const nextElements: Elements = propElements.map((propElement) => {
const existingElement = stateElements.find((el) => el.id === propElement.id);
if (existingElement) {
const data = !isEqual(existingElement.data, propElement.data)
? { ...existingElement.data, ...propElement.data }
: existingElement.data;
const style = !isEqual(existingElement.style, propElement.style)
? { ...existingElement.style, ...propElement.style }
: existingElement.style;
const elementProps = {
...existingElement,
};
if (typeof data !== 'undefined') {
elementProps.data = data;
}
if (typeof style !== 'undefined') {
elementProps.style = style;
}
if (typeof propElement.className !== 'undefined') {
elementProps.className = propElement.className;
}
if (typeof propElement.isHidden !== 'undefined') {
elementProps.isHidden = propElement.isHidden;
}
if (isNode(existingElement)) {
const propNode = propElement as Node;
const nodeProps = elementProps as Node;
const positionChanged =
existingElement.position.x !== propNode.position.x || existingElement.position.y !== propNode.position.y;
if (positionChanged) {
nodeProps.__rf = {
...existingElement.__rf,
position: propNode.position,
};
nodeProps.position = propNode.position;
}
if (typeof propNode.draggable !== 'undefined') {
nodeProps.draggable = propNode.draggable;
}
if (typeof propNode.selectable !== 'undefined') {
nodeProps.selectable = propNode.selectable;
}
if (typeof propNode.connectable !== 'undefined') {
nodeProps.connectable = propNode.connectable;
}
return nodeProps;
} else if (isEdge(existingElement)) {
const propEdge = propElement as Edge;
const edgeProps = elementProps as Edge;
const labelStyle = !isEqual(existingElement.labelStyle, propEdge.labelStyle)
? { ...existingElement.labelStyle, ...propEdge.labelStyle }
: existingElement.labelStyle;
const labelBgStyle = !isEqual(existingElement.labelBgStyle, propEdge.labelBgStyle)
? { ...existingElement.labelBgStyle, ...propEdge.labelBgStyle }
: existingElement.labelBgStyle;
if (typeof propEdge.label !== 'undefined') {
edgeProps.label = propEdge.label;
}
if (typeof labelStyle !== 'undefined') {
edgeProps.labelStyle = labelStyle;
}
if (typeof propEdge.labelShowBg !== 'undefined') {
edgeProps.labelShowBg = propEdge.labelShowBg;
}
if (typeof labelBgStyle !== 'undefined') {
edgeProps.labelBgStyle = labelBgStyle;
}
if (typeof propEdge.animated !== 'undefined') {
edgeProps.animated = propEdge.animated;
}
if (typeof propEdge.arrowHeadType !== 'undefined') {
edgeProps.arrowHeadType = propEdge.arrowHeadType;
}
return edgeProps;
}
}
return parseElement(propElement) as FlowElement;
});
const elementsChanged: boolean = !isEqual(stateElements, nextElements);
if (elementsChanged) {
setElements(nextElements);
}
}, [propElements, stateElements]);
};
export default useElementUpdater;