develop (#43)
* 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:
@@ -1,9 +1,10 @@
|
|||||||
version: 1
|
version: 1
|
||||||
update_configs:
|
update_configs:
|
||||||
- package_manager: "javascript"
|
- package_manager: 'javascript'
|
||||||
directory: "/"
|
directory: '/'
|
||||||
update_schedule: "weekly"
|
update_schedule: 'weekly'
|
||||||
|
target_branch: 'develop'
|
||||||
automerged_updates:
|
automerged_updates:
|
||||||
- match:
|
- match:
|
||||||
dependency_type: "all"
|
dependency_type: 'all'
|
||||||
update_type: "semver:minor"
|
update_type: 'semver:minor'
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
example/src
|
||||||
Vendored
+306
-175
@@ -5756,6 +5756,8 @@ var storeModel = {
|
|||||||
selection: null,
|
selection: null,
|
||||||
connectionSourceId: null,
|
connectionSourceId: null,
|
||||||
connectionPosition: { x: 0, y: 0 },
|
connectionPosition: { x: 0, y: 0 },
|
||||||
|
snapGrid: [16, 16],
|
||||||
|
snapToGrid: true,
|
||||||
onConnect: function () { },
|
onConnect: function () { },
|
||||||
setOnConnect: action(function (state, onConnect) {
|
setOnConnect: action(function (state, onConnect) {
|
||||||
state.onConnect = onConnect;
|
state.onConnect = onConnect;
|
||||||
@@ -5776,9 +5778,18 @@ var storeModel = {
|
|||||||
}),
|
}),
|
||||||
updateNodePos: action(function (state, _a) {
|
updateNodePos: action(function (state, _a) {
|
||||||
var id = _a.id, pos = _a.pos;
|
var id = _a.id, pos = _a.pos;
|
||||||
|
var position = pos;
|
||||||
|
if (state.snapToGrid) {
|
||||||
|
var transformedGridSizeX = state.snapGrid[0] * state.transform[2];
|
||||||
|
var transformedGridSizeY = state.snapGrid[1] * state.transform[2];
|
||||||
|
position = {
|
||||||
|
x: transformedGridSizeX * Math.round(pos.x / transformedGridSizeX),
|
||||||
|
y: transformedGridSizeY * Math.round(pos.y / transformedGridSizeY),
|
||||||
|
};
|
||||||
|
}
|
||||||
state.nodes.forEach(function (n) {
|
state.nodes.forEach(function (n) {
|
||||||
if (n.id === id) {
|
if (n.id === id) {
|
||||||
n.__rg = __assign(__assign({}, n.__rg), { position: pos });
|
n.__rg = __assign(__assign({}, n.__rg), { position: position });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
@@ -5787,7 +5798,7 @@ var storeModel = {
|
|||||||
}),
|
}),
|
||||||
setNodesSelection: action(function (state, _a) {
|
setNodesSelection: action(function (state, _a) {
|
||||||
var isActive = _a.isActive, selection = _a.selection;
|
var isActive = _a.isActive, selection = _a.selection;
|
||||||
if (!isActive) {
|
if (!isActive || typeof selection === 'undefined') {
|
||||||
state.nodesSelectionActive = false;
|
state.nodesSelectionActive = false;
|
||||||
state.selectedElements = [];
|
state.selectedElements = [];
|
||||||
return;
|
return;
|
||||||
@@ -5802,7 +5813,9 @@ var storeModel = {
|
|||||||
setSelectedElements: action(function (state, elements) {
|
setSelectedElements: action(function (state, elements) {
|
||||||
var selectedElementsArr = Array.isArray(elements) ? elements : [elements];
|
var selectedElementsArr = Array.isArray(elements) ? elements : [elements];
|
||||||
var selectedElementsUpdated = !fastDeepEqual(selectedElementsArr, state.selectedElements);
|
var selectedElementsUpdated = !fastDeepEqual(selectedElementsArr, state.selectedElements);
|
||||||
var selectedElements = selectedElementsUpdated ? selectedElementsArr : state.selectedElements;
|
var selectedElements = selectedElementsUpdated
|
||||||
|
? selectedElementsArr
|
||||||
|
: state.selectedElements;
|
||||||
state.selectedElements = selectedElements;
|
state.selectedElements = selectedElements;
|
||||||
}),
|
}),
|
||||||
updateSelection: action(function (state, selection) {
|
updateSelection: action(function (state, selection) {
|
||||||
@@ -5811,7 +5824,9 @@ var storeModel = {
|
|||||||
var nextSelectedElements = __spreadArrays(selectedNodes, selectedEdges);
|
var nextSelectedElements = __spreadArrays(selectedNodes, selectedEdges);
|
||||||
var selectedElementsUpdated = !fastDeepEqual(nextSelectedElements, state.selectedElements);
|
var selectedElementsUpdated = !fastDeepEqual(nextSelectedElements, state.selectedElements);
|
||||||
state.selection = selection;
|
state.selection = selection;
|
||||||
state.selectedElements = selectedElementsUpdated ? nextSelectedElements : state.selectedElements;
|
state.selectedElements = selectedElementsUpdated
|
||||||
|
? nextSelectedElements
|
||||||
|
: state.selectedElements;
|
||||||
}),
|
}),
|
||||||
updateTransform: action(function (state, transform) {
|
updateTransform: action(function (state, transform) {
|
||||||
state.transform = [transform.x, transform.y, transform.k];
|
state.transform = [transform.x, transform.y, transform.k];
|
||||||
@@ -5831,7 +5846,12 @@ var storeModel = {
|
|||||||
}),
|
}),
|
||||||
setConnectionSourceId: action(function (state, sourceId) {
|
setConnectionSourceId: action(function (state, sourceId) {
|
||||||
state.connectionSourceId = sourceId;
|
state.connectionSourceId = sourceId;
|
||||||
})
|
}),
|
||||||
|
setSnapGrid: action(function (state, _a) {
|
||||||
|
var snapToGrid = _a.snapToGrid, snapGrid = _a.snapGrid;
|
||||||
|
state.snapToGrid = snapToGrid;
|
||||||
|
state.snapGrid = snapGrid;
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
var store = createStore$1(storeModel);
|
var store = createStore$1(storeModel);
|
||||||
|
|
||||||
@@ -5845,7 +5865,9 @@ var getOutgoers = function (node, elements) {
|
|||||||
if (!isNode(node)) {
|
if (!isNode(node)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
var outgoerIds = elements.filter(function (e) { return e.source === node.id; }).map(function (e) { return e.target; });
|
var outgoerIds = elements
|
||||||
|
.filter(function (e) { return e.source === node.id; })
|
||||||
|
.map(function (e) { return e.target; });
|
||||||
return elements.filter(function (e) { return outgoerIds.includes(e.id); });
|
return elements.filter(function (e) { return outgoerIds.includes(e.id); });
|
||||||
};
|
};
|
||||||
var removeElements = function (elementsToRemove, elements) {
|
var removeElements = function (elementsToRemove, elements) {
|
||||||
@@ -5864,7 +5886,9 @@ var addEdge = function (edgeParams, elements) {
|
|||||||
if (!edgeParams.source || !edgeParams.target) {
|
if (!edgeParams.source || !edgeParams.target) {
|
||||||
throw new Error('Can not create edge. An edge needs a source and a target');
|
throw new Error('Can not create edge. An edge needs a source and a target');
|
||||||
}
|
}
|
||||||
return elements.concat(__assign(__assign({}, edgeParams), { id: typeof edgeParams.id !== 'undefined' ? edgeParams.id : getEdgeId(edgeParams) }));
|
return elements.concat(__assign(__assign({}, edgeParams), { id: typeof edgeParams.id !== 'undefined'
|
||||||
|
? edgeParams.id
|
||||||
|
: getEdgeId(edgeParams) }));
|
||||||
};
|
};
|
||||||
var pointToRendererPoint = function (_a, transform) {
|
var pointToRendererPoint = function (_a, transform) {
|
||||||
var x = _a.x, y = _a.y;
|
var x = _a.x, y = _a.y;
|
||||||
@@ -5872,10 +5896,11 @@ var pointToRendererPoint = function (_a, transform) {
|
|||||||
var rendererY = (y - transform[1]) * (1 / transform[2]);
|
var rendererY = (y - transform[1]) * (1 / transform[2]);
|
||||||
return {
|
return {
|
||||||
x: rendererX,
|
x: rendererX,
|
||||||
y: rendererY
|
y: rendererY,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
var parseElement = function (element, transform) {
|
var parseElement = function (element, transform) {
|
||||||
|
if (transform === void 0) { transform = [0, 0, 1]; }
|
||||||
if (!element.id) {
|
if (!element.id) {
|
||||||
throw new Error('All elements (nodes and edges) need to have an id.');
|
throw new Error('All elements (nodes and edges) need to have an id.');
|
||||||
}
|
}
|
||||||
@@ -5887,7 +5912,7 @@ var parseElement = function (element, transform) {
|
|||||||
position: pointToRendererPoint(nodeElement.position, transform),
|
position: pointToRendererPoint(nodeElement.position, transform),
|
||||||
width: null,
|
width: null,
|
||||||
height: null,
|
height: null,
|
||||||
handleBounds: {}
|
handleBounds: {},
|
||||||
} });
|
} });
|
||||||
};
|
};
|
||||||
var getBoundingBox = function (nodes) {
|
var getBoundingBox = function (nodes) {
|
||||||
@@ -5912,23 +5937,22 @@ var getBoundingBox = function (nodes) {
|
|||||||
minX: Number.MAX_VALUE,
|
minX: Number.MAX_VALUE,
|
||||||
minY: Number.MAX_VALUE,
|
minY: Number.MAX_VALUE,
|
||||||
maxX: 0,
|
maxX: 0,
|
||||||
maxY: 0
|
maxY: 0,
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
x: bbox.minX,
|
x: bbox.minX,
|
||||||
y: bbox.minY,
|
y: bbox.minY,
|
||||||
width: bbox.maxX - bbox.minX,
|
width: bbox.maxX - bbox.minX,
|
||||||
height: bbox.maxY - bbox.minY
|
height: bbox.maxY - bbox.minY,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
var getNodesInside = function (nodes, bbox, transform, partially) {
|
var getNodesInside = function (nodes, bbox, transform, partially) {
|
||||||
if (transform === void 0) { transform = [0, 0, 1]; }
|
if (transform === void 0) { transform = [0, 0, 1]; }
|
||||||
if (partially === void 0) { partially = false; }
|
if (partially === void 0) { partially = false; }
|
||||||
return nodes
|
return nodes.filter(function (n) {
|
||||||
.filter(function (n) {
|
|
||||||
var bboxPos = {
|
var bboxPos = {
|
||||||
x: (bbox.x - transform[0]) * (1 / transform[2]),
|
x: (bbox.x - transform[0]) * (1 / transform[2]),
|
||||||
y: (bbox.y - transform[1]) * (1 / transform[2])
|
y: (bbox.y - transform[1]) * (1 / transform[2]),
|
||||||
};
|
};
|
||||||
var bboxWidth = bbox.width * (1 / transform[2]);
|
var bboxWidth = bbox.width * (1 / transform[2]);
|
||||||
var bboxHeight = bbox.height * (1 / transform[2]);
|
var bboxHeight = bbox.height * (1 / transform[2]);
|
||||||
@@ -5937,8 +5961,10 @@ var getNodesInside = function (nodes, bbox, transform, partially) {
|
|||||||
var nodeHeight = partially ? 0 : height;
|
var nodeHeight = partially ? 0 : height;
|
||||||
var offsetX = partially ? width : 0;
|
var offsetX = partially ? width : 0;
|
||||||
var offsetY = partially ? height : 0;
|
var offsetY = partially ? height : 0;
|
||||||
return ((position.x + offsetX > bboxPos.x && (position.x + nodeWidth) < (bboxPos.x + bboxWidth)) &&
|
return (position.x + offsetX > bboxPos.x &&
|
||||||
(position.y + offsetY > bboxPos.y && (position.y + nodeHeight) < (bboxPos.y + bboxHeight)));
|
position.x + nodeWidth < bboxPos.x + bboxWidth &&
|
||||||
|
(position.y + offsetY > bboxPos.y &&
|
||||||
|
position.y + nodeHeight < bboxPos.y + bboxHeight));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
var getConnectedEdges = function (nodes, edges) {
|
var getConnectedEdges = function (nodes, edges) {
|
||||||
@@ -5954,21 +5980,36 @@ var getConnectedEdges = function (nodes, edges) {
|
|||||||
var fitView = function (_a) {
|
var fitView = function (_a) {
|
||||||
var padding = (_a === void 0 ? { padding: 0 } : _a).padding;
|
var padding = (_a === void 0 ? { padding: 0 } : _a).padding;
|
||||||
var state = store.getState();
|
var state = store.getState();
|
||||||
|
if (!state.d3Selection || !state.d3Zoom) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var bounds = getBoundingBox(state.nodes);
|
var bounds = getBoundingBox(state.nodes);
|
||||||
var maxBoundsSize = Math.max(bounds.width, bounds.height);
|
var maxBoundsSize = Math.max(bounds.width, bounds.height);
|
||||||
var k = Math.min(state.width, state.height) / (maxBoundsSize + (maxBoundsSize * padding));
|
var k = Math.min(state.width, state.height) /
|
||||||
var boundsCenterX = bounds.x + (bounds.width / 2);
|
(maxBoundsSize + maxBoundsSize * padding);
|
||||||
var boundsCenterY = bounds.y + (bounds.height / 2);
|
var boundsCenterX = bounds.x + bounds.width / 2;
|
||||||
var transform = [(state.width / 2) - (boundsCenterX * k), (state.height / 2) - (boundsCenterY * k)];
|
var boundsCenterY = bounds.y + bounds.height / 2;
|
||||||
var fittedTransform = identity$1.translate(transform[0], transform[1]).scale(k);
|
var transform = [
|
||||||
|
state.width / 2 - boundsCenterX * k,
|
||||||
|
state.height / 2 - boundsCenterY * k,
|
||||||
|
];
|
||||||
|
var fittedTransform = identity$1
|
||||||
|
.translate(transform[0], transform[1])
|
||||||
|
.scale(k);
|
||||||
state.d3Selection.call(state.d3Zoom.transform, fittedTransform);
|
state.d3Selection.call(state.d3Zoom.transform, fittedTransform);
|
||||||
};
|
};
|
||||||
var zoomIn = function () {
|
var zoomIn = function () {
|
||||||
var state = store.getState();
|
var state = store.getState();
|
||||||
|
if (!state.d3Zoom || !state.d3Selection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
state.d3Zoom.scaleTo(state.d3Selection, state.transform[2] + 0.2);
|
state.d3Zoom.scaleTo(state.d3Selection, state.transform[2] + 0.2);
|
||||||
};
|
};
|
||||||
var zoomOut = function () {
|
var zoomOut = function () {
|
||||||
var state = store.getState();
|
var state = store.getState();
|
||||||
|
if (!state.d3Zoom || !state.d3Selection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
state.d3Zoom.scaleTo(state.d3Selection, state.transform[2] - 0.2);
|
state.d3Zoom.scaleTo(state.d3Selection, state.transform[2] - 0.2);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -5977,21 +6018,24 @@ function renderNode(node, props, state) {
|
|||||||
if (!props.nodeTypes[nodeType]) {
|
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\".");
|
||||||
}
|
}
|
||||||
var NodeComponent = (props.nodeTypes[nodeType] || props.nodeTypes.default);
|
var NodeComponent = (props.nodeTypes[nodeType] ||
|
||||||
|
props.nodeTypes.default);
|
||||||
var selected = state.selectedElements
|
var selected = state.selectedElements
|
||||||
.filter(isNode)
|
.filter(isNode)
|
||||||
.map(function (e) { return e.id; })
|
.map(function (e) { return e.id; })
|
||||||
.includes(node.id);
|
.includes(node.id);
|
||||||
return (React.createElement(NodeComponent, { key: node.id, id: node.id, type: node.type, data: node.data, xPos: node.__rg.position.x, yPos: node.__rg.position.y, onClick: props.onElementClick, onNodeDragStop: props.onNodeDragStop, transform: state.transform, selected: selected, style: node.style }));
|
return (React.createElement(NodeComponent, { key: node.id, id: node.id, type: nodeType, data: node.data, xPos: node.__rg.position.x, yPos: node.__rg.position.y, onClick: props.onElementClick, onNodeDragStop: props.onNodeDragStop, transform: state.transform, selected: selected, style: node.style }));
|
||||||
}
|
}
|
||||||
var NodeRenderer = memo(function (props) {
|
var NodeRenderer = memo(function (props) {
|
||||||
var state = useStoreState$1(function (s) { return ({
|
var state = useStoreState$1(function (s) { return ({
|
||||||
nodes: s.nodes,
|
nodes: s.nodes,
|
||||||
transform: s.transform,
|
transform: s.transform,
|
||||||
selectedElements: s.selectedElements
|
selectedElements: s.selectedElements,
|
||||||
}); });
|
}); });
|
||||||
var transform = state.transform, nodes = state.nodes;
|
var transform = state.transform, nodes = state.nodes;
|
||||||
var transformStyle = { transform: "translate(" + transform[0] + "px," + transform[1] + "px) scale(" + transform[2] + ")" };
|
var transformStyle = {
|
||||||
|
transform: "translate(" + transform[0] + "px," + transform[1] + "px) scale(" + transform[2] + ")",
|
||||||
|
};
|
||||||
return (React.createElement("div", { className: "react-flow__nodes", style: transformStyle }, nodes.map(function (node) { return renderNode(node, props, state); })));
|
return (React.createElement("div", { className: "react-flow__nodes", style: transformStyle }, nodes.map(function (node) { return renderNode(node, props, state); })));
|
||||||
});
|
});
|
||||||
NodeRenderer.displayName = 'NodeRenderer';
|
NodeRenderer.displayName = 'NodeRenderer';
|
||||||
@@ -6068,11 +6112,15 @@ var ConnectionLine = (function (_a) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var edgeClasses = classnames('react-flow__edge', 'connection', className);
|
var edgeClasses = classnames('react-flow__edge', 'connection', className);
|
||||||
var sourceHandle = handleId ?
|
var sourceHandle = handleId
|
||||||
sourceNode.__rg.handleBounds.source.find(function (d) { return d.id === handleId; }) :
|
? sourceNode.__rg.handleBounds.source.find(function (d) { return d.id === handleId; })
|
||||||
sourceNode.__rg.handleBounds.source[0];
|
: sourceNode.__rg.handleBounds.source[0];
|
||||||
var sourceHandleX = sourceHandle ? sourceHandle.x + (sourceHandle.width / 2) : sourceNode.__rg.width / 2;
|
var sourceHandleX = sourceHandle
|
||||||
var sourceHandleY = sourceHandle ? sourceHandle.y + (sourceHandle.height / 2) : sourceNode.__rg.height;
|
? sourceHandle.x + sourceHandle.width / 2
|
||||||
|
: sourceNode.__rg.width / 2;
|
||||||
|
var sourceHandleY = sourceHandle
|
||||||
|
? sourceHandle.y + sourceHandle.height / 2
|
||||||
|
: sourceNode.__rg.height;
|
||||||
var sourceX = sourceNode.__rg.position.x + sourceHandleX;
|
var sourceX = sourceNode.__rg.position.x + sourceHandleX;
|
||||||
var sourceY = sourceNode.__rg.position.y + sourceHandleY;
|
var sourceY = sourceNode.__rg.position.y + sourceHandleY;
|
||||||
var targetX = (connectionPositionX - transform[0]) * (1 / transform[2]);
|
var targetX = (connectionPositionX - transform[0]) * (1 / transform[2]);
|
||||||
@@ -6094,42 +6142,49 @@ function getHandlePosition(position, node, handle) {
|
|||||||
if (handle === void 0) { handle = null; }
|
if (handle === void 0) { handle = null; }
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
switch (position) {
|
switch (position) {
|
||||||
case 'top': return {
|
case 'top':
|
||||||
x: node.__rg.width / 2,
|
return {
|
||||||
y: 0
|
x: node.__rg.width / 2,
|
||||||
};
|
y: 0,
|
||||||
case 'right': return {
|
};
|
||||||
x: node.__rg.width,
|
case 'right':
|
||||||
y: node.__rg.height / 2
|
return {
|
||||||
};
|
x: node.__rg.width,
|
||||||
case 'bottom': return {
|
y: node.__rg.height / 2,
|
||||||
x: node.__rg.width / 2,
|
};
|
||||||
y: node.__rg.height
|
case 'bottom':
|
||||||
};
|
return {
|
||||||
case 'left': return {
|
x: node.__rg.width / 2,
|
||||||
x: 0,
|
y: node.__rg.height,
|
||||||
y: node.__rg.height / 2
|
};
|
||||||
};
|
case 'left':
|
||||||
|
return {
|
||||||
|
x: 0,
|
||||||
|
y: node.__rg.height / 2,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
switch (position) {
|
switch (position) {
|
||||||
case 'top': return {
|
case 'top':
|
||||||
x: handle.x + (handle.width / 2),
|
return {
|
||||||
y: handle.y
|
x: handle.x + handle.width / 2,
|
||||||
};
|
y: handle.y,
|
||||||
case 'right': return {
|
};
|
||||||
x: handle.x + handle.width,
|
case 'right':
|
||||||
y: handle.y + (handle.height / 2)
|
return {
|
||||||
};
|
x: handle.x + handle.width,
|
||||||
case 'bottom': return {
|
y: handle.y + handle.height / 2,
|
||||||
x: handle.x + (handle.width / 2),
|
};
|
||||||
y: handle.y + handle.height
|
case 'bottom':
|
||||||
};
|
return {
|
||||||
case 'left': return {
|
x: handle.x + handle.width / 2,
|
||||||
x: handle.x,
|
y: handle.y + handle.height,
|
||||||
y: handle.y + (handle.height / 2)
|
};
|
||||||
};
|
case 'left':
|
||||||
|
return {
|
||||||
|
x: handle.x,
|
||||||
|
y: handle.y + handle.height / 2,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function getHandle(bounds, handleId) {
|
function getHandle(bounds, handleId) {
|
||||||
@@ -6155,7 +6210,10 @@ function getEdgePositions(sourceNode, sourceHandle, sourcePosition, targetNode,
|
|||||||
var targetX = targetNode.__rg.position.x + targetHandlePos.x;
|
var targetX = targetNode.__rg.position.x + targetHandlePos.x;
|
||||||
var targetY = targetNode.__rg.position.y + targetHandlePos.y;
|
var targetY = targetNode.__rg.position.y + targetHandlePos.y;
|
||||||
return {
|
return {
|
||||||
sourceX: sourceX, sourceY: sourceY, targetX: targetX, targetY: targetY
|
sourceX: sourceX,
|
||||||
|
sourceY: sourceY,
|
||||||
|
targetX: targetX,
|
||||||
|
targetY: targetY,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
function renderEdge(edge, props, state) {
|
function renderEdge(edge, props, state) {
|
||||||
@@ -6193,7 +6251,7 @@ var EdgeRenderer = memo(function (_a) {
|
|||||||
transform: s.transform,
|
transform: s.transform,
|
||||||
selectedElements: s.selectedElements,
|
selectedElements: s.selectedElements,
|
||||||
connectionSourceId: s.connectionSourceId,
|
connectionSourceId: s.connectionSourceId,
|
||||||
position: s.connectionPosition
|
position: s.connectionPosition,
|
||||||
}); });
|
}); });
|
||||||
if (!width) {
|
if (!width) {
|
||||||
return null;
|
return null;
|
||||||
@@ -6202,7 +6260,12 @@ var EdgeRenderer = memo(function (_a) {
|
|||||||
var transformStyle = "translate(" + transform[0] + "," + transform[1] + ") scale(" + transform[2] + ")";
|
var transformStyle = "translate(" + transform[0] + "," + transform[1] + ") scale(" + transform[2] + ")";
|
||||||
return (React.createElement("svg", { width: width, height: height, className: "react-flow__edges" },
|
return (React.createElement("svg", { width: width, height: height, className: "react-flow__edges" },
|
||||||
React.createElement("g", { transform: transformStyle },
|
React.createElement("g", { transform: transformStyle },
|
||||||
edges.map(function (e) { return renderEdge(e, __assign({ width: width, height: height, connectionLineStyle: connectionLineStyle, connectionLineType: connectionLineType }, rest), state); }),
|
edges.map(function (e) {
|
||||||
|
return renderEdge(e, __assign({ width: width,
|
||||||
|
height: height,
|
||||||
|
connectionLineStyle: connectionLineStyle,
|
||||||
|
connectionLineType: connectionLineType }, rest), state);
|
||||||
|
}),
|
||||||
connectionSourceId && (React.createElement(ConnectionLine, { nodes: nodes, connectionSourceId: connectionSourceId, connectionPositionX: position.x, connectionPositionY: position.y, transform: transform, connectionLineStyle: connectionLineStyle, connectionLineType: connectionLineType })))));
|
connectionSourceId && (React.createElement(ConnectionLine, { nodes: nodes, connectionSourceId: connectionSourceId, connectionPositionX: position.x, connectionPositionY: position.y, transform: transform, connectionLineStyle: connectionLineStyle, connectionLineType: connectionLineType })))));
|
||||||
});
|
});
|
||||||
EdgeRenderer.displayName = 'EdgeRenderer';
|
EdgeRenderer.displayName = 'EdgeRenderer';
|
||||||
@@ -6214,7 +6277,7 @@ var initialRect = {
|
|||||||
y: 0,
|
y: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
draw: false
|
draw: false,
|
||||||
};
|
};
|
||||||
function getMousePosition(evt) {
|
function getMousePosition(evt) {
|
||||||
var reactFlowNode = document.querySelector('.react-flow');
|
var reactFlowNode = document.querySelector('.react-flow');
|
||||||
@@ -6237,7 +6300,7 @@ var UserSelection = memo(function () {
|
|||||||
function onMouseDown(evt) {
|
function onMouseDown(evt) {
|
||||||
var mousePos = getMousePosition(evt);
|
var mousePos = getMousePosition(evt);
|
||||||
if (!mousePos) {
|
if (!mousePos) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
setRect(function (currentRect) { return (__assign(__assign({}, currentRect), { startX: mousePos.x, startY: mousePos.y, x: mousePos.x, y: mousePos.y, draw: true })); });
|
setRect(function (currentRect) { return (__assign(__assign({}, currentRect), { startX: mousePos.x, startY: mousePos.y, x: mousePos.x, y: mousePos.y, draw: true })); });
|
||||||
setSelection(true);
|
setSelection(true);
|
||||||
@@ -6253,7 +6316,11 @@ var UserSelection = memo(function () {
|
|||||||
}
|
}
|
||||||
var negativeX = mousePos.x < currentRect.startX;
|
var negativeX = mousePos.x < currentRect.startX;
|
||||||
var negativeY = mousePos.y < currentRect.startY;
|
var negativeY = mousePos.y < currentRect.startY;
|
||||||
var nextRect = __assign(__assign({}, currentRect), { x: negativeX ? mousePos.x : currentRect.x, y: negativeY ? mousePos.y : currentRect.y, width: negativeX ? currentRect.startX - mousePos.x : mousePos.x - currentRect.startX, height: negativeY ? currentRect.startY - mousePos.y : mousePos.y - currentRect.startY });
|
var nextRect = __assign(__assign({}, currentRect), { x: negativeX ? mousePos.x : currentRect.x, y: negativeY ? mousePos.y : currentRect.y, width: negativeX
|
||||||
|
? currentRect.startX - mousePos.x
|
||||||
|
: mousePos.x - currentRect.startX, height: negativeY
|
||||||
|
? currentRect.startY - mousePos.y
|
||||||
|
: mousePos.y - currentRect.startY });
|
||||||
updateSelection(nextRect);
|
updateSelection(nextRect);
|
||||||
return nextRect;
|
return nextRect;
|
||||||
});
|
});
|
||||||
@@ -6265,19 +6332,25 @@ var UserSelection = memo(function () {
|
|||||||
return __assign(__assign({}, currentRect), { draw: false });
|
return __assign(__assign({}, currentRect), { draw: false });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
selectionPane.current.addEventListener('mousedown', onMouseDown);
|
if (selectionPane.current) {
|
||||||
selectionPane.current.addEventListener('mousemove', onMouseMove);
|
selectionPane.current.addEventListener('mousedown', onMouseDown);
|
||||||
selectionPane.current.addEventListener('mouseup', onMouseUp);
|
selectionPane.current.addEventListener('mousemove', onMouseMove);
|
||||||
return function () {
|
selectionPane.current.addEventListener('mouseup', onMouseUp);
|
||||||
selectionPane.current.removeEventListener('mousedown', onMouseDown);
|
return function () {
|
||||||
selectionPane.current.removeEventListener('mousemove', onMouseMove);
|
if (!selectionPane.current) {
|
||||||
selectionPane.current.removeEventListener('mouseup', onMouseUp);
|
return;
|
||||||
};
|
}
|
||||||
}, []);
|
selectionPane.current.removeEventListener('mousedown', onMouseDown);
|
||||||
|
selectionPane.current.removeEventListener('mousemove', onMouseMove);
|
||||||
|
selectionPane.current.removeEventListener('mouseup', onMouseUp);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}, [selectionPane.current]);
|
||||||
return (React.createElement("div", { className: "react-flow__selectionpane", ref: selectionPane }, rect.draw && (React.createElement("div", { className: "react-flow__selection", style: {
|
return (React.createElement("div", { className: "react-flow__selectionpane", ref: selectionPane }, rect.draw && (React.createElement("div", { className: "react-flow__selection", style: {
|
||||||
width: rect.width,
|
width: rect.width,
|
||||||
height: rect.height,
|
height: rect.height,
|
||||||
transform: "translate(" + rect.x + "px, " + rect.y + "px)"
|
transform: "translate(" + rect.x + "px, " + rect.y + "px)",
|
||||||
} }))));
|
} }))));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -7948,16 +8021,15 @@ reactDraggable.default = default_1;
|
|||||||
reactDraggable.DraggableCore = DraggableCore;
|
reactDraggable.DraggableCore = DraggableCore;
|
||||||
|
|
||||||
function getStartPositions(elements) {
|
function getStartPositions(elements) {
|
||||||
return elements
|
var startPositions = {};
|
||||||
.filter(isNode)
|
return elements.filter(isNode).reduce(function (res, node) {
|
||||||
.reduce(function (res, node) {
|
|
||||||
var startPosition = {
|
var startPosition = {
|
||||||
x: node.__rg.position.x || node.position.x,
|
x: node.__rg.position.x || node.position.x,
|
||||||
y: node.__rg.position.y || node.position.x
|
y: node.__rg.position.y || node.position.x,
|
||||||
};
|
};
|
||||||
res[node.id] = startPosition;
|
res[node.id] = startPosition;
|
||||||
return res;
|
return res;
|
||||||
}, {});
|
}, startPositions);
|
||||||
}
|
}
|
||||||
var NodesSelection = memo(function () {
|
var NodesSelection = memo(function () {
|
||||||
var _a = useState({ x: 0, y: 0 }), offset = _a[0], setOffset = _a[1];
|
var _a = useState({ x: 0, y: 0 }), offset = _a[0], setOffset = _a[1];
|
||||||
@@ -7965,7 +8037,7 @@ var NodesSelection = memo(function () {
|
|||||||
var state = useStoreState$1(function (s) { return ({
|
var state = useStoreState$1(function (s) { return ({
|
||||||
transform: s.transform,
|
transform: s.transform,
|
||||||
selectedNodesBbox: s.selectedNodesBbox,
|
selectedNodesBbox: s.selectedNodesBbox,
|
||||||
selectedElements: s.selectedElements
|
selectedElements: s.selectedElements,
|
||||||
}); });
|
}); });
|
||||||
var updateNodePos = useStoreActions$1(function (a) { return a.updateNodePos; });
|
var updateNodePos = useStoreActions$1(function (a) { return a.updateNodePos; });
|
||||||
var _c = state.transform, x = _c[0], y = _c[1], k = _c[2];
|
var _c = state.transform, x = _c[0], y = _c[1], k = _c[2];
|
||||||
@@ -7973,37 +8045,46 @@ var NodesSelection = memo(function () {
|
|||||||
var onStart = function (evt) {
|
var onStart = function (evt) {
|
||||||
var scaledClient = {
|
var scaledClient = {
|
||||||
x: evt.clientX * (1 / k),
|
x: evt.clientX * (1 / k),
|
||||||
y: evt.clientY * (1 / k)
|
y: evt.clientY * (1 / k),
|
||||||
};
|
};
|
||||||
var offsetX = scaledClient.x - position.x - x;
|
var offsetX = scaledClient.x - position.x - x;
|
||||||
var offsetY = scaledClient.y - position.y - y;
|
var offsetY = scaledClient.y - position.y - y;
|
||||||
var startPositions = getStartPositions(state.selectedElements);
|
var nextStartPositions = getStartPositions(state.selectedElements);
|
||||||
setOffset({ x: offsetX, y: offsetY });
|
if (nextStartPositions) {
|
||||||
setStartPositions(startPositions);
|
setOffset({ x: offsetX, y: offsetY });
|
||||||
|
setStartPositions(nextStartPositions);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
var onDrag = function (evt) {
|
var onDrag = function (evt) {
|
||||||
var scaledClient = {
|
var scaledClient = {
|
||||||
x: evt.clientX * (1 / k),
|
x: evt.clientX * (1 / k),
|
||||||
y: evt.clientY * (1 / k)
|
y: evt.clientY * (1 / k),
|
||||||
};
|
};
|
||||||
state.selectedElements
|
state.selectedElements.filter(isNode).forEach(function (node) {
|
||||||
.filter(isNode)
|
var pos = {
|
||||||
.forEach(function (node) {
|
x: startPositions[node.id].x +
|
||||||
updateNodePos({ id: node.id, pos: {
|
scaledClient.x -
|
||||||
x: startPositions[node.id].x + scaledClient.x - position.x - offset.x - x,
|
position.x -
|
||||||
y: startPositions[node.id].y + scaledClient.y - position.y - offset.y - y
|
offset.x -
|
||||||
} });
|
x,
|
||||||
|
y: startPositions[node.id].y +
|
||||||
|
scaledClient.y -
|
||||||
|
position.y -
|
||||||
|
offset.y -
|
||||||
|
y,
|
||||||
|
};
|
||||||
|
updateNodePos({ id: node.id, pos: pos });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
return (React.createElement("div", { className: "react-flow__nodesselection", style: {
|
return (React.createElement("div", { className: "react-flow__nodesselection", style: {
|
||||||
transform: "translate(" + x + "px," + y + "px) scale(" + k + ")"
|
transform: "translate(" + x + "px," + y + "px) scale(" + k + ")",
|
||||||
} },
|
} },
|
||||||
React.createElement(reactDraggable, { scale: k, onStart: function (evt) { return onStart(evt); }, onDrag: function (evt) { return onDrag(evt); } },
|
React.createElement(reactDraggable, { scale: k, onStart: function (evt) { return onStart(evt); }, onDrag: function (evt) { return onDrag(evt); } },
|
||||||
React.createElement("div", { className: "react-flow__nodesselection-rect", style: {
|
React.createElement("div", { className: "react-flow__nodesselection-rect", style: {
|
||||||
width: state.selectedNodesBbox.width,
|
width: state.selectedNodesBbox.width,
|
||||||
height: state.selectedNodesBbox.height,
|
height: state.selectedNodesBbox.height,
|
||||||
top: state.selectedNodesBbox.y,
|
top: state.selectedNodesBbox.y,
|
||||||
left: state.selectedNodesBbox.x
|
left: state.selectedNodesBbox.x,
|
||||||
} }))));
|
} }))));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -8032,13 +8113,14 @@ var createGridDots = function (width, height, xOffset, yOffset, gap, size) {
|
|||||||
var x = col * gap + xOffset;
|
var x = col * gap + xOffset;
|
||||||
return Array.from({ length: lineCountY }, function (_, row) {
|
return Array.from({ length: lineCountY }, function (_, row) {
|
||||||
var y = row * gap + yOffset;
|
var y = row * gap + yOffset;
|
||||||
return "M" + x + " " + (y - size) + " l" + size + " " + size + " l" + -size + " " + size + " l" + -size + " " + -size + "z";
|
return "M" + x + " " + (y -
|
||||||
|
size) + " l" + size + " " + size + " l" + -size + " " + size + " l" + -size + " " + -size + "z";
|
||||||
}).join(' ');
|
}).join(' ');
|
||||||
});
|
});
|
||||||
return values.join(' ');
|
return values.join(' ');
|
||||||
};
|
};
|
||||||
var Grid = memo(function (_a) {
|
var Grid = memo(function (_a) {
|
||||||
var _b = _a.gap, gap = _b === void 0 ? 24 : _b, _c = _a.color, color = _c === void 0 ? '#aaa' : _c, _d = _a.size, size = _d === void 0 ? 0.5 : _d, _e = _a.style, style = _e === void 0 ? {} : _e, _f = _a.className, className = _f === void 0 ? null : _f, _g = _a.backgroundType, backgroundType = _g === void 0 ? GridType.Dots : _g;
|
var _b = _a.gap, gap = _b === void 0 ? 24 : _b, _c = _a.color, color = _c === void 0 ? '#aaa' : _c, _d = _a.size, size = _d === void 0 ? 0.5 : _d, _e = _a.style, style = _e === void 0 ? {} : _e, _f = _a.className, className = _f === void 0 ? '' : _f, _g = _a.backgroundType, backgroundType = _g === void 0 ? GridType.Dots : _g;
|
||||||
var _h = useStoreState$1(function (s) { return s; }), width = _h.width, height = _h.height, _j = _h.transform, x = _j[0], y = _j[1], scale = _j[2];
|
var _h = useStoreState$1(function (s) { return s; }), width = _h.width, height = _h.height, _j = _h.transform, x = _j[0], y = _j[1], scale = _j[2];
|
||||||
var gridClasses = classnames('react-flow__grid', className);
|
var gridClasses = classnames('react-flow__grid', className);
|
||||||
var scaledGap = gap * scale;
|
var scaledGap = gap * scale;
|
||||||
@@ -8057,11 +8139,11 @@ Grid.displayName = 'Grid';
|
|||||||
|
|
||||||
var isInputDOMNode = function (e) {
|
var isInputDOMNode = function (e) {
|
||||||
var target = e.target;
|
var target = e.target;
|
||||||
return e && target && ['INPUT', 'SELECT', 'TEXTAREA'].includes(target.nodeName);
|
return (e && target && ['INPUT', 'SELECT', 'TEXTAREA'].includes(target.nodeName));
|
||||||
};
|
};
|
||||||
var getDimensions = function (node) { return ({
|
var getDimensions = function (node) { return ({
|
||||||
width: node.offsetWidth,
|
width: node.offsetWidth,
|
||||||
height: node.offsetHeight
|
height: node.offsetHeight,
|
||||||
}); };
|
}); };
|
||||||
|
|
||||||
var useKeyPress = (function (keyCode) {
|
var useKeyPress = (function (keyCode) {
|
||||||
@@ -8099,8 +8181,10 @@ var useD3Zoom = (function (zoomPane, onMove, shiftPressed) {
|
|||||||
var initD3 = useStoreActions$1(function (actions) { return actions.initD3; });
|
var initD3 = useStoreActions$1(function (actions) { return actions.initD3; });
|
||||||
var updateTransform = useStoreActions$1(function (actions) { return actions.updateTransform; });
|
var updateTransform = useStoreActions$1(function (actions) { return actions.updateTransform; });
|
||||||
useEffect(function () {
|
useEffect(function () {
|
||||||
var selection = select(zoomPane.current).call(d3ZoomInstance);
|
if (zoomPane.current) {
|
||||||
initD3({ zoom: d3ZoomInstance, selection: selection });
|
var selection = select(zoomPane.current).call(d3ZoomInstance);
|
||||||
|
initD3({ zoom: d3ZoomInstance, selection: selection });
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
useEffect(function () {
|
useEffect(function () {
|
||||||
if (shiftPressed) {
|
if (shiftPressed) {
|
||||||
@@ -8108,13 +8192,14 @@ var useD3Zoom = (function (zoomPane, onMove, shiftPressed) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
d3ZoomInstance.on('zoom', function () {
|
d3ZoomInstance.on('zoom', function () {
|
||||||
if (event.sourceEvent && event.sourceEvent.target !== zoomPane.current) {
|
if (event.sourceEvent &&
|
||||||
return false;
|
event.sourceEvent.target !== zoomPane.current) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
updateTransform(event.transform);
|
updateTransform(event.transform);
|
||||||
onMove();
|
onMove();
|
||||||
});
|
});
|
||||||
if (state.d3Selection) {
|
if (state.d3Selection && state.d3Zoom) {
|
||||||
// we need to restore the graph transform otherwise d3 zoom transform and graph transform are not synced
|
// we need to restore the graph transform otherwise d3 zoom transform and graph transform are not synced
|
||||||
var graphTransform = identity$1
|
var graphTransform = identity$1
|
||||||
.translate(state.transform[0], state.transform[1])
|
.translate(state.transform[0], state.transform[1])
|
||||||
@@ -8130,14 +8215,18 @@ var useD3Zoom = (function (zoomPane, onMove, shiftPressed) {
|
|||||||
|
|
||||||
var useGlobalKeyHandler = (function (_a) {
|
var useGlobalKeyHandler = (function (_a) {
|
||||||
var deleteKeyCode = _a.deleteKeyCode, onElementsRemove = _a.onElementsRemove;
|
var deleteKeyCode = _a.deleteKeyCode, onElementsRemove = _a.onElementsRemove;
|
||||||
var state = useStoreState$1(function (s) { return ({ selectedElements: s.selectedElements, edges: s.edges }); });
|
var state = useStoreState$1(function (s) { return ({
|
||||||
|
selectedElements: s.selectedElements,
|
||||||
|
edges: s.edges,
|
||||||
|
}); });
|
||||||
var setNodesSelection = useStoreActions$1(function (a) { return a.setNodesSelection; });
|
var setNodesSelection = useStoreActions$1(function (a) { return a.setNodesSelection; });
|
||||||
var deleteKeyPressed = useKeyPress(deleteKeyCode);
|
var deleteKeyPressed = useKeyPress(deleteKeyCode);
|
||||||
useEffect(function () {
|
useEffect(function () {
|
||||||
if (deleteKeyPressed && state.selectedElements.length) {
|
if (deleteKeyPressed && state.selectedElements.length) {
|
||||||
var elementsToRemove = state.selectedElements;
|
var elementsToRemove = state.selectedElements;
|
||||||
// we also want to remove the edges if only one node is selected
|
// we also want to remove the edges if only one node is selected
|
||||||
if (state.selectedElements.length === 1 && !isEdge(state.selectedElements[0])) {
|
if (state.selectedElements.length === 1 &&
|
||||||
|
!isEdge(state.selectedElements[0])) {
|
||||||
var node = state.selectedElements[0];
|
var node = state.selectedElements[0];
|
||||||
var connectedEdges = getConnectedEdges([node], state.edges);
|
var connectedEdges = getConnectedEdges([node], state.edges);
|
||||||
elementsToRemove = __spreadArrays(state.selectedElements, connectedEdges);
|
elementsToRemove = __spreadArrays(state.selectedElements, connectedEdges);
|
||||||
@@ -8146,14 +8235,13 @@ var useGlobalKeyHandler = (function (_a) {
|
|||||||
setNodesSelection({ isActive: false });
|
setNodesSelection({ isActive: false });
|
||||||
}
|
}
|
||||||
}, [deleteKeyPressed]);
|
}, [deleteKeyPressed]);
|
||||||
return null;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var useElementUpdater = function (elements) {
|
var useElementUpdater = function (elements) {
|
||||||
var state = useStoreState$1(function (s) { return ({
|
var state = useStoreState$1(function (s) { return ({
|
||||||
nodes: s.nodes,
|
nodes: s.nodes,
|
||||||
edges: s.edges,
|
edges: s.edges,
|
||||||
transform: s.transform
|
transform: s.transform,
|
||||||
}); });
|
}); });
|
||||||
var setNodes = useStoreActions$1(function (a) { return a.setNodes; });
|
var setNodes = useStoreActions$1(function (a) { return a.setNodes; });
|
||||||
var setEdges = useStoreActions$1(function (a) { return a.setEdges; });
|
var setEdges = useStoreActions$1(function (a) { return a.setEdges; });
|
||||||
@@ -8163,7 +8251,8 @@ var useElementUpdater = function (elements) {
|
|||||||
var nextNodes = nodes.map(function (propNode) {
|
var nextNodes = nodes.map(function (propNode) {
|
||||||
var existingNode = state.nodes.find(function (n) { return n.id === propNode.id; });
|
var existingNode = state.nodes.find(function (n) { return n.id === propNode.id; });
|
||||||
if (existingNode) {
|
if (existingNode) {
|
||||||
var data = !fastDeepEqual(existingNode.data, propNode.data) ? __assign(__assign({}, existingNode.data), propNode.data) : existingNode.data;
|
var data = !fastDeepEqual(existingNode.data, propNode.data)
|
||||||
|
? __assign(__assign({}, existingNode.data), propNode.data) : existingNode.data;
|
||||||
return __assign(__assign({}, existingNode), { data: data });
|
return __assign(__assign({}, existingNode), { data: data });
|
||||||
}
|
}
|
||||||
return parseElement(propNode, state.transform);
|
return parseElement(propNode, state.transform);
|
||||||
@@ -8177,11 +8266,10 @@ var useElementUpdater = function (elements) {
|
|||||||
setEdges(edges);
|
setEdges(edges);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var GraphView = memo(function (_a) {
|
var GraphView = memo(function (_a) {
|
||||||
var nodeTypes = _a.nodeTypes, edgeTypes = _a.edgeTypes, onMove = _a.onMove, onLoad = _a.onLoad, onElementClick = _a.onElementClick, onNodeDragStop = _a.onNodeDragStop, connectionLineType = _a.connectionLineType, connectionLineStyle = _a.connectionLineStyle, selectionKeyCode = _a.selectionKeyCode, onElementsRemove = _a.onElementsRemove, deleteKeyCode = _a.deleteKeyCode, elements = _a.elements, showBackground = _a.showBackground, backgroundGap = _a.backgroundGap, backgroundColor = _a.backgroundColor, backgroundType = _a.backgroundType, onConnect = _a.onConnect;
|
var nodeTypes = _a.nodeTypes, edgeTypes = _a.edgeTypes, onMove = _a.onMove, onLoad = _a.onLoad, onElementClick = _a.onElementClick, onNodeDragStop = _a.onNodeDragStop, connectionLineType = _a.connectionLineType, connectionLineStyle = _a.connectionLineStyle, selectionKeyCode = _a.selectionKeyCode, onElementsRemove = _a.onElementsRemove, deleteKeyCode = _a.deleteKeyCode, elements = _a.elements, showBackground = _a.showBackground, backgroundGap = _a.backgroundGap, backgroundColor = _a.backgroundColor, backgroundType = _a.backgroundType, onConnect = _a.onConnect, snapToGrid = _a.snapToGrid, snapGrid = _a.snapGrid;
|
||||||
var zoomPane = useRef(null);
|
var zoomPane = useRef(null);
|
||||||
var rendererNode = useRef(null);
|
var rendererNode = useRef(null);
|
||||||
var state = useStoreState$1(function (s) { return ({
|
var state = useStoreState$1(function (s) { return ({
|
||||||
@@ -8190,14 +8278,18 @@ var GraphView = memo(function (_a) {
|
|||||||
nodes: s.nodes,
|
nodes: s.nodes,
|
||||||
edges: s.edges,
|
edges: s.edges,
|
||||||
d3Initialised: s.d3Initialised,
|
d3Initialised: s.d3Initialised,
|
||||||
nodesSelectionActive: s.nodesSelectionActive
|
nodesSelectionActive: s.nodesSelectionActive,
|
||||||
}); });
|
}); });
|
||||||
var updateSize = useStoreActions$1(function (actions) { return actions.updateSize; });
|
var updateSize = useStoreActions$1(function (actions) { return actions.updateSize; });
|
||||||
var setNodesSelection = useStoreActions$1(function (actions) { return actions.setNodesSelection; });
|
var setNodesSelection = useStoreActions$1(function (actions) { return actions.setNodesSelection; });
|
||||||
var setOnConnect = useStoreActions$1(function (a) { return a.setOnConnect; });
|
var setOnConnect = useStoreActions$1(function (a) { return a.setOnConnect; });
|
||||||
|
var setSnapGrid = useStoreActions$1(function (actions) { return actions.setSnapGrid; });
|
||||||
var selectionKeyPressed = useKeyPress(selectionKeyCode);
|
var selectionKeyPressed = useKeyPress(selectionKeyCode);
|
||||||
var onZoomPaneClick = function () { return setNodesSelection({ isActive: false }); };
|
var onZoomPaneClick = function () { return setNodesSelection({ isActive: false }); };
|
||||||
var updateDimensions = function () {
|
var updateDimensions = function () {
|
||||||
|
if (!rendererNode.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var size = getDimensions(rendererNode.current);
|
var size = getDimensions(rendererNode.current);
|
||||||
updateSize(size);
|
updateSize(size);
|
||||||
};
|
};
|
||||||
@@ -8215,10 +8307,13 @@ var GraphView = memo(function (_a) {
|
|||||||
onLoad({
|
onLoad({
|
||||||
fitView: fitView,
|
fitView: fitView,
|
||||||
zoomIn: zoomIn,
|
zoomIn: zoomIn,
|
||||||
zoomOut: zoomOut
|
zoomOut: zoomOut,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [state.d3Initialised]);
|
}, [state.d3Initialised]);
|
||||||
|
useEffect(function () {
|
||||||
|
setSnapGrid({ snapToGrid: snapToGrid, snapGrid: snapGrid });
|
||||||
|
}, [snapToGrid]);
|
||||||
useGlobalKeyHandler({ onElementsRemove: onElementsRemove, deleteKeyCode: deleteKeyCode });
|
useGlobalKeyHandler({ onElementsRemove: onElementsRemove, deleteKeyCode: deleteKeyCode });
|
||||||
useElementUpdater(elements);
|
useElementUpdater(elements);
|
||||||
return (React.createElement("div", { className: "react-flow__renderer", ref: rendererNode },
|
return (React.createElement("div", { className: "react-flow__renderer", ref: rendererNode },
|
||||||
@@ -8234,10 +8329,10 @@ GraphView.displayName = 'GraphView';
|
|||||||
function onMouseDown(evt, nodeId, setSourceId, setPosition, onConnect, isTarget, isValidConnection) {
|
function onMouseDown(evt, nodeId, setSourceId, setPosition, onConnect, isTarget, isValidConnection) {
|
||||||
var reactFlowNode = document.querySelector('.react-flow');
|
var reactFlowNode = document.querySelector('.react-flow');
|
||||||
if (!reactFlowNode) {
|
if (!reactFlowNode) {
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
var containerBounds = reactFlowNode.getBoundingClientRect();
|
var containerBounds = reactFlowNode.getBoundingClientRect();
|
||||||
var recentHoveredHandle = null;
|
var recentHoveredHandle;
|
||||||
setPosition({
|
setPosition({
|
||||||
x: evt.clientX - containerBounds.left,
|
x: evt.clientX - containerBounds.left,
|
||||||
y: evt.clientY - containerBounds.top,
|
y: evt.clientY - containerBounds.top,
|
||||||
@@ -8245,7 +8340,7 @@ function onMouseDown(evt, nodeId, setSourceId, setPosition, onConnect, isTarget,
|
|||||||
setSourceId(nodeId);
|
setSourceId(nodeId);
|
||||||
function resetRecentHandle() {
|
function resetRecentHandle() {
|
||||||
if (!recentHoveredHandle) {
|
if (!recentHoveredHandle) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
recentHoveredHandle.classList.remove('valid');
|
recentHoveredHandle.classList.remove('valid');
|
||||||
recentHoveredHandle.classList.remove('connecting');
|
recentHoveredHandle.classList.remove('connecting');
|
||||||
@@ -8257,9 +8352,11 @@ function onMouseDown(evt, nodeId, setSourceId, setPosition, onConnect, isTarget,
|
|||||||
elementBelow: elementBelow,
|
elementBelow: elementBelow,
|
||||||
isValid: false,
|
isValid: false,
|
||||||
connection: { source: null, target: null },
|
connection: { source: null, target: null },
|
||||||
isHoveringHandle: false
|
isHoveringHandle: false,
|
||||||
};
|
};
|
||||||
if (elementBelow && (elementBelow.classList.contains('target') || elementBelow.classList.contains('source'))) {
|
if (elementBelow &&
|
||||||
|
(elementBelow.classList.contains('target') ||
|
||||||
|
elementBelow.classList.contains('source'))) {
|
||||||
var connection = { source: null, target: null };
|
var connection = { source: null, target: null };
|
||||||
if (isTarget) {
|
if (isTarget) {
|
||||||
var sourceId = elementBelow.getAttribute('data-nodeid');
|
var sourceId = elementBelow.getAttribute('data-nodeid');
|
||||||
@@ -8286,7 +8383,7 @@ function onMouseDown(evt, nodeId, setSourceId, setPosition, onConnect, isTarget,
|
|||||||
return resetRecentHandle();
|
return resetRecentHandle();
|
||||||
}
|
}
|
||||||
var isOwnHandle = connection.source === connection.target;
|
var isOwnHandle = connection.source === connection.target;
|
||||||
if (!isOwnHandle) {
|
if (!isOwnHandle && elementBelow) {
|
||||||
recentHoveredHandle = elementBelow;
|
recentHoveredHandle = elementBelow;
|
||||||
elementBelow.classList.add('connecting');
|
elementBelow.classList.add('connecting');
|
||||||
elementBelow.classList.toggle('valid', isValid);
|
elementBelow.classList.toggle('valid', isValid);
|
||||||
@@ -8308,9 +8405,14 @@ function onMouseDown(evt, nodeId, setSourceId, setPosition, onConnect, isTarget,
|
|||||||
var BaseHandle = memo(function (_a) {
|
var BaseHandle = memo(function (_a) {
|
||||||
var type = _a.type, nodeId = _a.nodeId, onConnect = _a.onConnect, position = _a.position, setSourceId = _a.setSourceId, setPosition = _a.setPosition, className = _a.className, _b = _a.id, id = _b === void 0 ? false : _b, isValidConnection = _a.isValidConnection, rest = __rest(_a, ["type", "nodeId", "onConnect", "position", "setSourceId", "setPosition", "className", "id", "isValidConnection"]);
|
var type = _a.type, nodeId = _a.nodeId, onConnect = _a.onConnect, position = _a.position, setSourceId = _a.setSourceId, setPosition = _a.setPosition, className = _a.className, _b = _a.id, id = _b === void 0 ? false : _b, isValidConnection = _a.isValidConnection, rest = __rest(_a, ["type", "nodeId", "onConnect", "position", "setSourceId", "setPosition", "className", "id", "isValidConnection"]);
|
||||||
var isTarget = type === 'target';
|
var isTarget = type === 'target';
|
||||||
var handleClasses = classnames('react-flow__handle', className, position, { source: !isTarget, target: isTarget });
|
var handleClasses = classnames('react-flow__handle', className, position, {
|
||||||
|
source: !isTarget,
|
||||||
|
target: isTarget,
|
||||||
|
});
|
||||||
var nodeIdWithHandleId = id ? nodeId + "__" + id : nodeId;
|
var nodeIdWithHandleId = id ? nodeId + "__" + id : nodeId;
|
||||||
return (React.createElement("div", __assign({ "data-nodeid": nodeIdWithHandleId, "data-handlepos": position, className: handleClasses, onMouseDown: function (evt) { return onMouseDown(evt, nodeIdWithHandleId, setSourceId, setPosition, onConnect, isTarget, isValidConnection); } }, rest)));
|
return (React.createElement("div", __assign({ "data-nodeid": nodeIdWithHandleId, "data-handlepos": position, className: handleClasses, onMouseDown: function (evt) {
|
||||||
|
return onMouseDown(evt, nodeIdWithHandleId, setSourceId, setPosition, onConnect, isTarget, isValidConnection);
|
||||||
|
} }, rest)));
|
||||||
});
|
});
|
||||||
BaseHandle.displayName = 'BaseHandle';
|
BaseHandle.displayName = 'BaseHandle';
|
||||||
|
|
||||||
@@ -8323,7 +8425,7 @@ var Handle = memo(function (_a) {
|
|||||||
var nodeId = useContext(NodeIdContext);
|
var nodeId = useContext(NodeIdContext);
|
||||||
var _f = useStoreActions$1(function (a) { return ({
|
var _f = useStoreActions$1(function (a) { return ({
|
||||||
setPosition: a.setConnectionPosition,
|
setPosition: a.setConnectionPosition,
|
||||||
setSourceId: a.setConnectionSourceId
|
setSourceId: a.setConnectionSourceId,
|
||||||
}); }), setPosition = _f.setPosition, setSourceId = _f.setSourceId;
|
}); }), setPosition = _f.setPosition, setSourceId = _f.setSourceId;
|
||||||
var onConnectAction = useStoreState$1(function (s) { return s.onConnect; });
|
var onConnectAction = useStoreState$1(function (s) { return s.onConnect; });
|
||||||
var onConnectExtended = function (params) {
|
var onConnectExtended = function (params) {
|
||||||
@@ -8338,7 +8440,7 @@ var nodeStyles = {
|
|||||||
background: '#ff6060',
|
background: '#ff6060',
|
||||||
padding: 10,
|
padding: 10,
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
width: 150
|
width: 150,
|
||||||
};
|
};
|
||||||
var DefaultNode = (function (_a) {
|
var DefaultNode = (function (_a) {
|
||||||
var data = _a.data, style = _a.style;
|
var data = _a.data, style = _a.style;
|
||||||
@@ -8352,7 +8454,7 @@ var nodeStyles$1 = {
|
|||||||
background: '#9999ff',
|
background: '#9999ff',
|
||||||
padding: 10,
|
padding: 10,
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
width: 150
|
width: 150,
|
||||||
};
|
};
|
||||||
var InputNode = (function (_a) {
|
var InputNode = (function (_a) {
|
||||||
var data = _a.data, style = _a.style;
|
var data = _a.data, style = _a.style;
|
||||||
@@ -8365,7 +8467,7 @@ var nodeStyles$2 = {
|
|||||||
background: '#55dd99',
|
background: '#55dd99',
|
||||||
padding: 10,
|
padding: 10,
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
width: 150
|
width: 150,
|
||||||
};
|
};
|
||||||
var OutputNode = (function (_a) {
|
var OutputNode = (function (_a) {
|
||||||
var data = _a.data, style = _a.style;
|
var data = _a.data, style = _a.style;
|
||||||
@@ -8642,15 +8744,18 @@ var getHandleBounds = function (selector, nodeElement, parentBounds, k) {
|
|||||||
if (!handles || !handles.length) {
|
if (!handles || !handles.length) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return [].map.call(handles, function (handle) {
|
var handlesArray = Array.from(handles);
|
||||||
|
return handlesArray.map(function (handle) {
|
||||||
var bounds = handle.getBoundingClientRect();
|
var bounds = handle.getBoundingClientRect();
|
||||||
var dimensions = getDimensions(handle);
|
var dimensions = getDimensions(handle);
|
||||||
var nodeIdAttr = handle.getAttribute('data-nodeid');
|
var nodeIdAttr = handle.getAttribute('data-nodeid');
|
||||||
var handlePosition = handle.getAttribute('data-handlepos');
|
var handlePosition = handle.getAttribute('data-handlepos');
|
||||||
var nodeIdSplitted = nodeIdAttr.split('__');
|
var nodeIdSplitted = nodeIdAttr ? nodeIdAttr.split('__') : null;
|
||||||
var handleId = null;
|
var handleId = null;
|
||||||
if (nodeIdSplitted) {
|
if (nodeIdSplitted) {
|
||||||
handleId = (nodeIdSplitted.length ? nodeIdSplitted[1] : nodeIdSplitted);
|
handleId = (nodeIdSplitted.length
|
||||||
|
? nodeIdSplitted[1]
|
||||||
|
: nodeIdSplitted);
|
||||||
}
|
}
|
||||||
return __assign({ id: handleId, position: handlePosition, x: (bounds.left - parentBounds.left) * (1 / k), y: (bounds.top - parentBounds.top) * (1 / k) }, dimensions);
|
return __assign({ id: handleId, position: handlePosition, x: (bounds.left - parentBounds.left) * (1 / k), y: (bounds.top - parentBounds.top) * (1 / k) }, dimensions);
|
||||||
});
|
});
|
||||||
@@ -8661,7 +8766,7 @@ var onStart = function (evt, onClick, id, type, data, setOffset, transform, posi
|
|||||||
}
|
}
|
||||||
var scaledClient = {
|
var scaledClient = {
|
||||||
x: evt.clientX * (1 / transform[2]),
|
x: evt.clientX * (1 / transform[2]),
|
||||||
y: evt.clientY * (1 / transform[2])
|
y: evt.clientY * (1 / transform[2]),
|
||||||
};
|
};
|
||||||
var offsetX = scaledClient.x - position.x - transform[0];
|
var offsetX = scaledClient.x - position.x - transform[0];
|
||||||
var offsetY = scaledClient.y - position.y - transform[1];
|
var offsetY = scaledClient.y - position.y - transform[1];
|
||||||
@@ -8673,19 +8778,25 @@ var onStart = function (evt, onClick, id, type, data, setOffset, transform, posi
|
|||||||
var onDrag = function (evt, setDragging, id, offset, transform) {
|
var onDrag = function (evt, setDragging, id, offset, transform) {
|
||||||
var scaledClient = {
|
var scaledClient = {
|
||||||
x: evt.clientX * (1 / transform[2]),
|
x: evt.clientX * (1 / transform[2]),
|
||||||
y: evt.clientY * (1 / transform[2])
|
y: evt.clientY * (1 / transform[2]),
|
||||||
};
|
};
|
||||||
setDragging(true);
|
setDragging(true);
|
||||||
store.dispatch.updateNodePos({ id: id, pos: {
|
store.dispatch.updateNodePos({
|
||||||
|
id: id,
|
||||||
|
pos: {
|
||||||
x: scaledClient.x - transform[0] - offset.x,
|
x: scaledClient.x - transform[0] - offset.x,
|
||||||
y: scaledClient.y - transform[1] - offset.y
|
y: scaledClient.y - transform[1] - offset.y,
|
||||||
} });
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
var onStop = function (onNodeDragStop, isDragging, setDragging, id, type, position, data) {
|
var onStop = function (onNodeDragStop, isDragging, setDragging, id, type, position, data) {
|
||||||
if (isDragging) {
|
if (isDragging) {
|
||||||
setDragging(false);
|
setDragging(false);
|
||||||
onNodeDragStop({
|
onNodeDragStop({
|
||||||
id: id, type: type, position: position, data: data
|
id: id,
|
||||||
|
type: type,
|
||||||
|
position: position,
|
||||||
|
data: data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -8697,17 +8808,20 @@ var wrapNode = (function (NodeComponent) {
|
|||||||
var _c = useState(false), isDragging = _c[0], setDragging = _c[1];
|
var _c = useState(false), isDragging = _c[0], setDragging = _c[1];
|
||||||
var position = { x: xPos, y: yPos };
|
var position = { x: xPos, y: yPos };
|
||||||
var nodeClasses = classnames('react-flow__node', { selected: selected });
|
var nodeClasses = classnames('react-flow__node', { selected: selected });
|
||||||
var nodeStyle = { zIndex: selected ? 10 : 3, transform: "translate(" + xPos + "px," + yPos + "px)" };
|
var nodeStyle = {
|
||||||
|
zIndex: selected ? 10 : 3,
|
||||||
|
transform: "translate(" + xPos + "px," + yPos + "px)",
|
||||||
|
};
|
||||||
var updateNode = function () {
|
var updateNode = function () {
|
||||||
if (!nodeElement.current) {
|
if (!nodeElement.current) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
var storeState = store.getState();
|
var storeState = store.getState();
|
||||||
var bounds = nodeElement.current.getBoundingClientRect();
|
var bounds = nodeElement.current.getBoundingClientRect();
|
||||||
var dimensions = getDimensions(nodeElement.current);
|
var dimensions = getDimensions(nodeElement.current);
|
||||||
var handleBounds = {
|
var handleBounds = {
|
||||||
source: getHandleBounds('.source', nodeElement.current, bounds, storeState.transform[2]),
|
source: getHandleBounds('.source', nodeElement.current, bounds, storeState.transform[2]),
|
||||||
target: getHandleBounds('.target', nodeElement.current, bounds, storeState.transform[2])
|
target: getHandleBounds('.target', nodeElement.current, bounds, storeState.transform[2]),
|
||||||
};
|
};
|
||||||
store.dispatch.updateNodeData(__assign(__assign({ id: id }, dimensions), { handleBounds: handleBounds }));
|
store.dispatch.updateNodeData(__assign(__assign({ id: id }, dimensions), { handleBounds: handleBounds }));
|
||||||
};
|
};
|
||||||
@@ -8727,8 +8841,15 @@ var wrapNode = (function (NodeComponent) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}, [nodeElement.current]);
|
}, [nodeElement.current]);
|
||||||
return (React.createElement(DraggableCore, { onStart: function (evt) { return onStart(evt, onClick, id, type, data, setOffset, transform, position); }, onDrag: function (evt) { return onDrag(evt, setDragging, id, offset, transform); }, onStop: function () { return onStop(onNodeDragStop, isDragging, setDragging, id, type, position, data); }, scale: transform[2] },
|
return (React.createElement(DraggableCore, { onStart: function (evt) {
|
||||||
|
return onStart(evt, onClick, id, type, data, setOffset, transform, position);
|
||||||
|
}, onDrag: function (evt) {
|
||||||
|
return onDrag(evt, setDragging, id, offset, transform);
|
||||||
|
}, onStop: function () {
|
||||||
|
return onStop(onNodeDragStop, isDragging, setDragging, id, type, position, data);
|
||||||
|
}, scale: transform[2] },
|
||||||
React.createElement("div", { className: nodeClasses, ref: nodeElement, style: nodeStyle },
|
React.createElement("div", { className: nodeClasses, ref: nodeElement, style: nodeStyle },
|
||||||
React.createElement(Provider, { value: id },
|
React.createElement(Provider, { value: id },
|
||||||
React.createElement(NodeComponent, { id: id, data: data, type: type, style: style, selected: selected })))));
|
React.createElement(NodeComponent, { id: id, data: data, type: type, style: style, selected: selected })))));
|
||||||
@@ -8741,15 +8862,15 @@ function createNodeTypes(nodeTypes) {
|
|||||||
var standardTypes = {
|
var standardTypes = {
|
||||||
input: wrapNode((nodeTypes.input || InputNode)),
|
input: wrapNode((nodeTypes.input || InputNode)),
|
||||||
default: wrapNode((nodeTypes.default || DefaultNode)),
|
default: wrapNode((nodeTypes.default || DefaultNode)),
|
||||||
output: wrapNode((nodeTypes.output || OutputNode))
|
output: wrapNode((nodeTypes.output || OutputNode)),
|
||||||
};
|
};
|
||||||
var specialTypes = Object
|
var wrappedTypes = {};
|
||||||
.keys(nodeTypes)
|
var specialTypes = Object.keys(nodeTypes)
|
||||||
.filter(function (k) { return !['input', 'default', 'output'].includes(k); })
|
.filter(function (k) { return !['input', 'default', 'output'].includes(k); })
|
||||||
.reduce(function (res, key) {
|
.reduce(function (res, key) {
|
||||||
res[key] = wrapNode((nodeTypes[key] || DefaultNode));
|
res[key] = wrapNode((nodeTypes[key] || DefaultNode));
|
||||||
return res;
|
return res;
|
||||||
}, {});
|
}, wrappedTypes);
|
||||||
return __assign(__assign({}, standardTypes), specialTypes);
|
return __assign(__assign({}, standardTypes), specialTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8758,15 +8879,17 @@ var BezierEdge = memo(function (_a) {
|
|||||||
var yOffset = Math.abs(targetY - sourceY) / 2;
|
var yOffset = Math.abs(targetY - sourceY) / 2;
|
||||||
var centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
var centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
||||||
var dAttr = "M" + sourceX + "," + sourceY + " C" + sourceX + "," + centerY + " " + targetX + "," + centerY + " " + targetX + "," + targetY;
|
var dAttr = "M" + sourceX + "," + sourceY + " C" + sourceX + "," + centerY + " " + targetX + "," + centerY + " " + targetX + "," + targetY;
|
||||||
if (['left', 'right'].includes(sourcePosition) && ['left', 'right'].includes(targetPosition)) {
|
if (['left', 'right'].includes(sourcePosition) &&
|
||||||
|
['left', 'right'].includes(targetPosition)) {
|
||||||
var xOffset = Math.abs(targetX - sourceX) / 2;
|
var xOffset = Math.abs(targetX - sourceX) / 2;
|
||||||
var centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
|
var centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
|
||||||
dAttr = "M" + sourceX + "," + sourceY + " C" + centerX + "," + sourceY + " " + centerX + "," + targetY + " " + targetX + "," + targetY;
|
dAttr = "M" + sourceX + "," + sourceY + " C" + centerX + "," + sourceY + " " + centerX + "," + targetY + " " + targetX + "," + targetY;
|
||||||
}
|
}
|
||||||
else if (['left', 'right'].includes(sourcePosition) || ['left', 'right'].includes(targetPosition)) {
|
else if (['left', 'right'].includes(sourcePosition) ||
|
||||||
|
['left', 'right'].includes(targetPosition)) {
|
||||||
dAttr = "M" + sourceX + "," + sourceY + " C" + sourceX + "," + targetY + " " + sourceX + "," + targetY + " " + targetX + "," + targetY;
|
dAttr = "M" + sourceX + "," + sourceY + " C" + sourceX + "," + targetY + " " + sourceX + "," + targetY + " " + targetX + "," + targetY;
|
||||||
}
|
}
|
||||||
return (React.createElement("path", __assign({}, style, { d: dAttr })));
|
return React.createElement("path", __assign({}, style, { d: dAttr }));
|
||||||
});
|
});
|
||||||
|
|
||||||
var StraightEdge = memo(function (_a) {
|
var StraightEdge = memo(function (_a) {
|
||||||
@@ -8787,7 +8910,7 @@ var wrapEdge = (function (EdgeComponent) {
|
|||||||
var edgeClasses = classnames('react-flow__edge', { selected: selected, animated: animated });
|
var edgeClasses = classnames('react-flow__edge', { selected: selected, animated: animated });
|
||||||
var onEdgeClick = function (evt) {
|
var onEdgeClick = function (evt) {
|
||||||
if (isInputDOMNode(evt)) {
|
if (isInputDOMNode(evt)) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
store.dispatch.setSelectedElements({ id: id, source: source, target: target });
|
store.dispatch.setSelectedElements({ id: id, source: source, target: target });
|
||||||
onClick({ id: id, source: source, target: target, type: type });
|
onClick({ id: id, source: source, target: target, type: type });
|
||||||
@@ -8802,15 +8925,15 @@ var wrapEdge = (function (EdgeComponent) {
|
|||||||
function createEdgeTypes(edgeTypes) {
|
function createEdgeTypes(edgeTypes) {
|
||||||
var standardTypes = {
|
var standardTypes = {
|
||||||
default: wrapEdge((edgeTypes.default || BezierEdge)),
|
default: wrapEdge((edgeTypes.default || BezierEdge)),
|
||||||
straight: wrapEdge((edgeTypes.bezier || StraightEdge))
|
straight: wrapEdge((edgeTypes.bezier || StraightEdge)),
|
||||||
};
|
};
|
||||||
var specialTypes = Object
|
var wrappedTypes = {};
|
||||||
.keys(edgeTypes)
|
var specialTypes = Object.keys(edgeTypes)
|
||||||
.filter(function (k) { return !['default', 'bezier'].includes(k); })
|
.filter(function (k) { return !['default', 'bezier'].includes(k); })
|
||||||
.reduce(function (res, key) {
|
.reduce(function (res, key) {
|
||||||
res[key] = wrapEdge((edgeTypes[key] || BezierEdge));
|
res[key] = wrapEdge((edgeTypes[key] || BezierEdge));
|
||||||
return res;
|
return res;
|
||||||
}, {});
|
}, wrappedTypes);
|
||||||
return __assign(__assign({}, standardTypes), specialTypes);
|
return __assign(__assign({}, standardTypes), specialTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8845,12 +8968,12 @@ var css = ".react-flow {\n width: 100%;\n height: 100%;\n position: relative;
|
|||||||
styleInject(css);
|
styleInject(css);
|
||||||
|
|
||||||
var ReactFlow = function (_a) {
|
var ReactFlow = function (_a) {
|
||||||
var style = _a.style, onElementClick = _a.onElementClick, elements = _a.elements, children = _a.children, nodeTypes = _a.nodeTypes, edgeTypes = _a.edgeTypes, onLoad = _a.onLoad, onMove = _a.onMove, onElementsRemove = _a.onElementsRemove, onConnect = _a.onConnect, onNodeDragStop = _a.onNodeDragStop, connectionLineType = _a.connectionLineType, connectionLineStyle = _a.connectionLineStyle, deleteKeyCode = _a.deleteKeyCode, selectionKeyCode = _a.selectionKeyCode, showBackground = _a.showBackground, backgroundGap = _a.backgroundGap, backgroundType = _a.backgroundType, backgroundColor = _a.backgroundColor;
|
var style = _a.style, onElementClick = _a.onElementClick, elements = _a.elements, children = _a.children, nodeTypes = _a.nodeTypes, edgeTypes = _a.edgeTypes, onLoad = _a.onLoad, onMove = _a.onMove, onElementsRemove = _a.onElementsRemove, onConnect = _a.onConnect, onNodeDragStop = _a.onNodeDragStop, connectionLineType = _a.connectionLineType, connectionLineStyle = _a.connectionLineStyle, deleteKeyCode = _a.deleteKeyCode, selectionKeyCode = _a.selectionKeyCode, showBackground = _a.showBackground, backgroundGap = _a.backgroundGap, backgroundType = _a.backgroundType, backgroundColor = _a.backgroundColor, snapToGrid = _a.snapToGrid, snapGrid = _a.snapGrid;
|
||||||
var nodeTypesParsed = useMemo(function () { return createNodeTypes(nodeTypes); }, []);
|
var nodeTypesParsed = useMemo(function () { return createNodeTypes(nodeTypes); }, []);
|
||||||
var edgeTypesParsed = useMemo(function () { return createEdgeTypes(edgeTypes); }, []);
|
var edgeTypesParsed = useMemo(function () { return createEdgeTypes(edgeTypes); }, []);
|
||||||
return (React.createElement("div", { style: style, className: "react-flow" },
|
return (React.createElement("div", { style: style, className: "react-flow" },
|
||||||
React.createElement(StoreProvider, { store: store },
|
React.createElement(StoreProvider, { store: store },
|
||||||
React.createElement(GraphView, { onLoad: onLoad, onMove: onMove, onElementClick: onElementClick, onNodeDragStop: onNodeDragStop, nodeTypes: nodeTypesParsed, edgeTypes: edgeTypesParsed, connectionLineType: connectionLineType, connectionLineStyle: connectionLineStyle, selectionKeyCode: selectionKeyCode, onElementsRemove: onElementsRemove, deleteKeyCode: deleteKeyCode, elements: elements, onConnect: onConnect, backgroundColor: backgroundColor, backgroundGap: backgroundGap, showBackground: showBackground, backgroundType: backgroundType }),
|
React.createElement(GraphView, { onLoad: onLoad, onMove: onMove, onElementClick: onElementClick, onNodeDragStop: onNodeDragStop, nodeTypes: nodeTypesParsed, edgeTypes: edgeTypesParsed, connectionLineType: connectionLineType, connectionLineStyle: connectionLineStyle, selectionKeyCode: selectionKeyCode, onElementsRemove: onElementsRemove, deleteKeyCode: deleteKeyCode, elements: elements, onConnect: onConnect, backgroundColor: backgroundColor, backgroundGap: backgroundGap, showBackground: showBackground, backgroundType: backgroundType, snapToGrid: snapToGrid, snapGrid: snapGrid }),
|
||||||
children)));
|
children)));
|
||||||
};
|
};
|
||||||
ReactFlow.displayName = 'ReactFlow';
|
ReactFlow.displayName = 'ReactFlow';
|
||||||
@@ -8864,12 +8987,12 @@ ReactFlow.defaultProps = {
|
|||||||
nodeTypes: {
|
nodeTypes: {
|
||||||
input: InputNode,
|
input: InputNode,
|
||||||
default: DefaultNode,
|
default: DefaultNode,
|
||||||
output: OutputNode
|
output: OutputNode,
|
||||||
},
|
},
|
||||||
edgeTypes: {
|
edgeTypes: {
|
||||||
default: BezierEdge,
|
default: BezierEdge,
|
||||||
straight: StraightEdge,
|
straight: StraightEdge,
|
||||||
step: StepEdge
|
step: StepEdge,
|
||||||
},
|
},
|
||||||
connectionLineType: 'bezier',
|
connectionLineType: 'bezier',
|
||||||
connectionLineStyle: {},
|
connectionLineStyle: {},
|
||||||
@@ -8878,7 +9001,9 @@ ReactFlow.defaultProps = {
|
|||||||
backgroundColor: '#eee',
|
backgroundColor: '#eee',
|
||||||
backgroundGap: 24,
|
backgroundGap: 24,
|
||||||
showBackground: true,
|
showBackground: true,
|
||||||
backgroundType: GridType.Dots
|
backgroundType: GridType.Dots,
|
||||||
|
snapToGrid: false,
|
||||||
|
snapGrid: [16, 16],
|
||||||
};
|
};
|
||||||
|
|
||||||
var baseStyle = {
|
var baseStyle = {
|
||||||
@@ -8886,7 +9011,7 @@ var baseStyle = {
|
|||||||
zIndex: 5,
|
zIndex: 5,
|
||||||
bottom: 10,
|
bottom: 10,
|
||||||
right: 10,
|
right: 10,
|
||||||
width: 200
|
width: 200,
|
||||||
};
|
};
|
||||||
var index = (function (_a) {
|
var index = (function (_a) {
|
||||||
var _b = _a.style, style = _b === void 0 ? {} : _b, className = _a.className, _c = _a.bgColor, bgColor = _c === void 0 ? '#f8f8f8' : _c, _d = _a.nodeColor, nodeColor = _d === void 0 ? '#ddd' : _d;
|
var _b = _a.style, style = _b === void 0 ? {} : _b, className = _a.className, _c = _a.bgColor, bgColor = _c === void 0 ? '#f8f8f8' : _c, _d = _a.nodeColor, nodeColor = _d === void 0 ? '#ddd' : _d;
|
||||||
@@ -8903,23 +9028,29 @@ var index = (function (_a) {
|
|||||||
var height = (state.height / (state.width || 1)) * width;
|
var height = (state.height / (state.width || 1)) * width;
|
||||||
var bbox = { x: 0, y: 0, width: state.width, height: state.height };
|
var bbox = { x: 0, y: 0, width: state.width, height: state.height };
|
||||||
var scaleFactor = width / state.width;
|
var scaleFactor = width / state.width;
|
||||||
var nodeColorFunc = (nodeColor instanceof Function ? nodeColor : function () { return nodeColor; });
|
var nodeColorFunc = (nodeColor instanceof Function
|
||||||
|
? nodeColor
|
||||||
|
: function () { return nodeColor; });
|
||||||
useEffect(function () {
|
useEffect(function () {
|
||||||
if (canvasNode && canvasNode.current) {
|
if (!canvasNode || !canvasNode.current) {
|
||||||
var ctx_1 = canvasNode.current.getContext('2d');
|
return;
|
||||||
var nodesInside = getNodesInside(state.nodes, bbox, state.transform, true);
|
|
||||||
ctx_1.fillStyle = bgColor;
|
|
||||||
ctx_1.fillRect(0, 0, width, height);
|
|
||||||
nodesInside.forEach(function (n) {
|
|
||||||
var pos = n.__rg.position;
|
|
||||||
var transformX = state.transform[0];
|
|
||||||
var transformY = state.transform[1];
|
|
||||||
var x = (pos.x * state.transform[2]) + transformX;
|
|
||||||
var y = (pos.y * state.transform[2]) + transformY;
|
|
||||||
ctx_1.fillStyle = nodeColorFunc(n);
|
|
||||||
ctx_1.fillRect((x * scaleFactor), (y * scaleFactor), n.__rg.width * scaleFactor * state.transform[2], n.__rg.height * scaleFactor * state.transform[2]);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
var ctx = canvasNode.current.getContext('2d');
|
||||||
|
if (!ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var nodesInside = getNodesInside(state.nodes, bbox, state.transform, true);
|
||||||
|
ctx.fillStyle = bgColor;
|
||||||
|
ctx.fillRect(0, 0, width, height);
|
||||||
|
nodesInside.forEach(function (n) {
|
||||||
|
var pos = n.__rg.position;
|
||||||
|
var transformX = state.transform[0];
|
||||||
|
var transformY = state.transform[1];
|
||||||
|
var x = pos.x * state.transform[2] + transformX;
|
||||||
|
var y = pos.y * state.transform[2] + transformY;
|
||||||
|
ctx.fillStyle = nodeColorFunc(n);
|
||||||
|
ctx.fillRect(x * scaleFactor, y * scaleFactor, n.__rg.width * scaleFactor * state.transform[2], n.__rg.height * scaleFactor * state.transform[2]);
|
||||||
|
});
|
||||||
}, [canvasNode.current, nodePositions, state.transform, height]);
|
}, [canvasNode.current, nodePositions, state.transform, height]);
|
||||||
return (React.createElement("canvas", { style: __assign(__assign(__assign({}, baseStyle), style), { height: height }), width: width, height: height, className: mapClasses, ref: canvasNode }));
|
return (React.createElement("canvas", { style: __assign(__assign(__assign({}, baseStyle), style), { height: height }), width: width, height: height, className: mapClasses, ref: canvasNode }));
|
||||||
});
|
});
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+306
-175
@@ -5763,6 +5763,8 @@ var storeModel = {
|
|||||||
selection: null,
|
selection: null,
|
||||||
connectionSourceId: null,
|
connectionSourceId: null,
|
||||||
connectionPosition: { x: 0, y: 0 },
|
connectionPosition: { x: 0, y: 0 },
|
||||||
|
snapGrid: [16, 16],
|
||||||
|
snapToGrid: true,
|
||||||
onConnect: function () { },
|
onConnect: function () { },
|
||||||
setOnConnect: action(function (state, onConnect) {
|
setOnConnect: action(function (state, onConnect) {
|
||||||
state.onConnect = onConnect;
|
state.onConnect = onConnect;
|
||||||
@@ -5783,9 +5785,18 @@ var storeModel = {
|
|||||||
}),
|
}),
|
||||||
updateNodePos: action(function (state, _a) {
|
updateNodePos: action(function (state, _a) {
|
||||||
var id = _a.id, pos = _a.pos;
|
var id = _a.id, pos = _a.pos;
|
||||||
|
var position = pos;
|
||||||
|
if (state.snapToGrid) {
|
||||||
|
var transformedGridSizeX = state.snapGrid[0] * state.transform[2];
|
||||||
|
var transformedGridSizeY = state.snapGrid[1] * state.transform[2];
|
||||||
|
position = {
|
||||||
|
x: transformedGridSizeX * Math.round(pos.x / transformedGridSizeX),
|
||||||
|
y: transformedGridSizeY * Math.round(pos.y / transformedGridSizeY),
|
||||||
|
};
|
||||||
|
}
|
||||||
state.nodes.forEach(function (n) {
|
state.nodes.forEach(function (n) {
|
||||||
if (n.id === id) {
|
if (n.id === id) {
|
||||||
n.__rg = __assign(__assign({}, n.__rg), { position: pos });
|
n.__rg = __assign(__assign({}, n.__rg), { position: position });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
@@ -5794,7 +5805,7 @@ var storeModel = {
|
|||||||
}),
|
}),
|
||||||
setNodesSelection: action(function (state, _a) {
|
setNodesSelection: action(function (state, _a) {
|
||||||
var isActive = _a.isActive, selection = _a.selection;
|
var isActive = _a.isActive, selection = _a.selection;
|
||||||
if (!isActive) {
|
if (!isActive || typeof selection === 'undefined') {
|
||||||
state.nodesSelectionActive = false;
|
state.nodesSelectionActive = false;
|
||||||
state.selectedElements = [];
|
state.selectedElements = [];
|
||||||
return;
|
return;
|
||||||
@@ -5809,7 +5820,9 @@ var storeModel = {
|
|||||||
setSelectedElements: action(function (state, elements) {
|
setSelectedElements: action(function (state, elements) {
|
||||||
var selectedElementsArr = Array.isArray(elements) ? elements : [elements];
|
var selectedElementsArr = Array.isArray(elements) ? elements : [elements];
|
||||||
var selectedElementsUpdated = !fastDeepEqual(selectedElementsArr, state.selectedElements);
|
var selectedElementsUpdated = !fastDeepEqual(selectedElementsArr, state.selectedElements);
|
||||||
var selectedElements = selectedElementsUpdated ? selectedElementsArr : state.selectedElements;
|
var selectedElements = selectedElementsUpdated
|
||||||
|
? selectedElementsArr
|
||||||
|
: state.selectedElements;
|
||||||
state.selectedElements = selectedElements;
|
state.selectedElements = selectedElements;
|
||||||
}),
|
}),
|
||||||
updateSelection: action(function (state, selection) {
|
updateSelection: action(function (state, selection) {
|
||||||
@@ -5818,7 +5831,9 @@ var storeModel = {
|
|||||||
var nextSelectedElements = __spreadArrays(selectedNodes, selectedEdges);
|
var nextSelectedElements = __spreadArrays(selectedNodes, selectedEdges);
|
||||||
var selectedElementsUpdated = !fastDeepEqual(nextSelectedElements, state.selectedElements);
|
var selectedElementsUpdated = !fastDeepEqual(nextSelectedElements, state.selectedElements);
|
||||||
state.selection = selection;
|
state.selection = selection;
|
||||||
state.selectedElements = selectedElementsUpdated ? nextSelectedElements : state.selectedElements;
|
state.selectedElements = selectedElementsUpdated
|
||||||
|
? nextSelectedElements
|
||||||
|
: state.selectedElements;
|
||||||
}),
|
}),
|
||||||
updateTransform: action(function (state, transform) {
|
updateTransform: action(function (state, transform) {
|
||||||
state.transform = [transform.x, transform.y, transform.k];
|
state.transform = [transform.x, transform.y, transform.k];
|
||||||
@@ -5838,7 +5853,12 @@ var storeModel = {
|
|||||||
}),
|
}),
|
||||||
setConnectionSourceId: action(function (state, sourceId) {
|
setConnectionSourceId: action(function (state, sourceId) {
|
||||||
state.connectionSourceId = sourceId;
|
state.connectionSourceId = sourceId;
|
||||||
})
|
}),
|
||||||
|
setSnapGrid: action(function (state, _a) {
|
||||||
|
var snapToGrid = _a.snapToGrid, snapGrid = _a.snapGrid;
|
||||||
|
state.snapToGrid = snapToGrid;
|
||||||
|
state.snapGrid = snapGrid;
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
var store = createStore$1(storeModel);
|
var store = createStore$1(storeModel);
|
||||||
|
|
||||||
@@ -5852,7 +5872,9 @@ var getOutgoers = function (node, elements) {
|
|||||||
if (!isNode(node)) {
|
if (!isNode(node)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
var outgoerIds = elements.filter(function (e) { return e.source === node.id; }).map(function (e) { return e.target; });
|
var outgoerIds = elements
|
||||||
|
.filter(function (e) { return e.source === node.id; })
|
||||||
|
.map(function (e) { return e.target; });
|
||||||
return elements.filter(function (e) { return outgoerIds.includes(e.id); });
|
return elements.filter(function (e) { return outgoerIds.includes(e.id); });
|
||||||
};
|
};
|
||||||
var removeElements = function (elementsToRemove, elements) {
|
var removeElements = function (elementsToRemove, elements) {
|
||||||
@@ -5871,7 +5893,9 @@ var addEdge = function (edgeParams, elements) {
|
|||||||
if (!edgeParams.source || !edgeParams.target) {
|
if (!edgeParams.source || !edgeParams.target) {
|
||||||
throw new Error('Can not create edge. An edge needs a source and a target');
|
throw new Error('Can not create edge. An edge needs a source and a target');
|
||||||
}
|
}
|
||||||
return elements.concat(__assign(__assign({}, edgeParams), { id: typeof edgeParams.id !== 'undefined' ? edgeParams.id : getEdgeId(edgeParams) }));
|
return elements.concat(__assign(__assign({}, edgeParams), { id: typeof edgeParams.id !== 'undefined'
|
||||||
|
? edgeParams.id
|
||||||
|
: getEdgeId(edgeParams) }));
|
||||||
};
|
};
|
||||||
var pointToRendererPoint = function (_a, transform) {
|
var pointToRendererPoint = function (_a, transform) {
|
||||||
var x = _a.x, y = _a.y;
|
var x = _a.x, y = _a.y;
|
||||||
@@ -5879,10 +5903,11 @@ var pointToRendererPoint = function (_a, transform) {
|
|||||||
var rendererY = (y - transform[1]) * (1 / transform[2]);
|
var rendererY = (y - transform[1]) * (1 / transform[2]);
|
||||||
return {
|
return {
|
||||||
x: rendererX,
|
x: rendererX,
|
||||||
y: rendererY
|
y: rendererY,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
var parseElement = function (element, transform) {
|
var parseElement = function (element, transform) {
|
||||||
|
if (transform === void 0) { transform = [0, 0, 1]; }
|
||||||
if (!element.id) {
|
if (!element.id) {
|
||||||
throw new Error('All elements (nodes and edges) need to have an id.');
|
throw new Error('All elements (nodes and edges) need to have an id.');
|
||||||
}
|
}
|
||||||
@@ -5894,7 +5919,7 @@ var parseElement = function (element, transform) {
|
|||||||
position: pointToRendererPoint(nodeElement.position, transform),
|
position: pointToRendererPoint(nodeElement.position, transform),
|
||||||
width: null,
|
width: null,
|
||||||
height: null,
|
height: null,
|
||||||
handleBounds: {}
|
handleBounds: {},
|
||||||
} });
|
} });
|
||||||
};
|
};
|
||||||
var getBoundingBox = function (nodes) {
|
var getBoundingBox = function (nodes) {
|
||||||
@@ -5919,23 +5944,22 @@ var getBoundingBox = function (nodes) {
|
|||||||
minX: Number.MAX_VALUE,
|
minX: Number.MAX_VALUE,
|
||||||
minY: Number.MAX_VALUE,
|
minY: Number.MAX_VALUE,
|
||||||
maxX: 0,
|
maxX: 0,
|
||||||
maxY: 0
|
maxY: 0,
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
x: bbox.minX,
|
x: bbox.minX,
|
||||||
y: bbox.minY,
|
y: bbox.minY,
|
||||||
width: bbox.maxX - bbox.minX,
|
width: bbox.maxX - bbox.minX,
|
||||||
height: bbox.maxY - bbox.minY
|
height: bbox.maxY - bbox.minY,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
var getNodesInside = function (nodes, bbox, transform, partially) {
|
var getNodesInside = function (nodes, bbox, transform, partially) {
|
||||||
if (transform === void 0) { transform = [0, 0, 1]; }
|
if (transform === void 0) { transform = [0, 0, 1]; }
|
||||||
if (partially === void 0) { partially = false; }
|
if (partially === void 0) { partially = false; }
|
||||||
return nodes
|
return nodes.filter(function (n) {
|
||||||
.filter(function (n) {
|
|
||||||
var bboxPos = {
|
var bboxPos = {
|
||||||
x: (bbox.x - transform[0]) * (1 / transform[2]),
|
x: (bbox.x - transform[0]) * (1 / transform[2]),
|
||||||
y: (bbox.y - transform[1]) * (1 / transform[2])
|
y: (bbox.y - transform[1]) * (1 / transform[2]),
|
||||||
};
|
};
|
||||||
var bboxWidth = bbox.width * (1 / transform[2]);
|
var bboxWidth = bbox.width * (1 / transform[2]);
|
||||||
var bboxHeight = bbox.height * (1 / transform[2]);
|
var bboxHeight = bbox.height * (1 / transform[2]);
|
||||||
@@ -5944,8 +5968,10 @@ var getNodesInside = function (nodes, bbox, transform, partially) {
|
|||||||
var nodeHeight = partially ? 0 : height;
|
var nodeHeight = partially ? 0 : height;
|
||||||
var offsetX = partially ? width : 0;
|
var offsetX = partially ? width : 0;
|
||||||
var offsetY = partially ? height : 0;
|
var offsetY = partially ? height : 0;
|
||||||
return ((position.x + offsetX > bboxPos.x && (position.x + nodeWidth) < (bboxPos.x + bboxWidth)) &&
|
return (position.x + offsetX > bboxPos.x &&
|
||||||
(position.y + offsetY > bboxPos.y && (position.y + nodeHeight) < (bboxPos.y + bboxHeight)));
|
position.x + nodeWidth < bboxPos.x + bboxWidth &&
|
||||||
|
(position.y + offsetY > bboxPos.y &&
|
||||||
|
position.y + nodeHeight < bboxPos.y + bboxHeight));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
var getConnectedEdges = function (nodes, edges) {
|
var getConnectedEdges = function (nodes, edges) {
|
||||||
@@ -5961,21 +5987,36 @@ var getConnectedEdges = function (nodes, edges) {
|
|||||||
var fitView = function (_a) {
|
var fitView = function (_a) {
|
||||||
var padding = (_a === void 0 ? { padding: 0 } : _a).padding;
|
var padding = (_a === void 0 ? { padding: 0 } : _a).padding;
|
||||||
var state = store.getState();
|
var state = store.getState();
|
||||||
|
if (!state.d3Selection || !state.d3Zoom) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var bounds = getBoundingBox(state.nodes);
|
var bounds = getBoundingBox(state.nodes);
|
||||||
var maxBoundsSize = Math.max(bounds.width, bounds.height);
|
var maxBoundsSize = Math.max(bounds.width, bounds.height);
|
||||||
var k = Math.min(state.width, state.height) / (maxBoundsSize + (maxBoundsSize * padding));
|
var k = Math.min(state.width, state.height) /
|
||||||
var boundsCenterX = bounds.x + (bounds.width / 2);
|
(maxBoundsSize + maxBoundsSize * padding);
|
||||||
var boundsCenterY = bounds.y + (bounds.height / 2);
|
var boundsCenterX = bounds.x + bounds.width / 2;
|
||||||
var transform = [(state.width / 2) - (boundsCenterX * k), (state.height / 2) - (boundsCenterY * k)];
|
var boundsCenterY = bounds.y + bounds.height / 2;
|
||||||
var fittedTransform = identity$1.translate(transform[0], transform[1]).scale(k);
|
var transform = [
|
||||||
|
state.width / 2 - boundsCenterX * k,
|
||||||
|
state.height / 2 - boundsCenterY * k,
|
||||||
|
];
|
||||||
|
var fittedTransform = identity$1
|
||||||
|
.translate(transform[0], transform[1])
|
||||||
|
.scale(k);
|
||||||
state.d3Selection.call(state.d3Zoom.transform, fittedTransform);
|
state.d3Selection.call(state.d3Zoom.transform, fittedTransform);
|
||||||
};
|
};
|
||||||
var zoomIn = function () {
|
var zoomIn = function () {
|
||||||
var state = store.getState();
|
var state = store.getState();
|
||||||
|
if (!state.d3Zoom || !state.d3Selection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
state.d3Zoom.scaleTo(state.d3Selection, state.transform[2] + 0.2);
|
state.d3Zoom.scaleTo(state.d3Selection, state.transform[2] + 0.2);
|
||||||
};
|
};
|
||||||
var zoomOut = function () {
|
var zoomOut = function () {
|
||||||
var state = store.getState();
|
var state = store.getState();
|
||||||
|
if (!state.d3Zoom || !state.d3Selection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
state.d3Zoom.scaleTo(state.d3Selection, state.transform[2] - 0.2);
|
state.d3Zoom.scaleTo(state.d3Selection, state.transform[2] - 0.2);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -5984,21 +6025,24 @@ function renderNode(node, props, state) {
|
|||||||
if (!props.nodeTypes[nodeType]) {
|
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\".");
|
||||||
}
|
}
|
||||||
var NodeComponent = (props.nodeTypes[nodeType] || props.nodeTypes.default);
|
var NodeComponent = (props.nodeTypes[nodeType] ||
|
||||||
|
props.nodeTypes.default);
|
||||||
var selected = state.selectedElements
|
var selected = state.selectedElements
|
||||||
.filter(isNode)
|
.filter(isNode)
|
||||||
.map(function (e) { return e.id; })
|
.map(function (e) { return e.id; })
|
||||||
.includes(node.id);
|
.includes(node.id);
|
||||||
return (React__default.createElement(NodeComponent, { key: node.id, id: node.id, type: node.type, data: node.data, xPos: node.__rg.position.x, yPos: node.__rg.position.y, onClick: props.onElementClick, onNodeDragStop: props.onNodeDragStop, transform: state.transform, selected: selected, style: node.style }));
|
return (React__default.createElement(NodeComponent, { key: node.id, id: node.id, type: nodeType, data: node.data, xPos: node.__rg.position.x, yPos: node.__rg.position.y, onClick: props.onElementClick, onNodeDragStop: props.onNodeDragStop, transform: state.transform, selected: selected, style: node.style }));
|
||||||
}
|
}
|
||||||
var NodeRenderer = React.memo(function (props) {
|
var NodeRenderer = React.memo(function (props) {
|
||||||
var state = useStoreState$1(function (s) { return ({
|
var state = useStoreState$1(function (s) { return ({
|
||||||
nodes: s.nodes,
|
nodes: s.nodes,
|
||||||
transform: s.transform,
|
transform: s.transform,
|
||||||
selectedElements: s.selectedElements
|
selectedElements: s.selectedElements,
|
||||||
}); });
|
}); });
|
||||||
var transform = state.transform, nodes = state.nodes;
|
var transform = state.transform, nodes = state.nodes;
|
||||||
var transformStyle = { transform: "translate(" + transform[0] + "px," + transform[1] + "px) scale(" + transform[2] + ")" };
|
var transformStyle = {
|
||||||
|
transform: "translate(" + transform[0] + "px," + transform[1] + "px) scale(" + transform[2] + ")",
|
||||||
|
};
|
||||||
return (React__default.createElement("div", { className: "react-flow__nodes", style: transformStyle }, nodes.map(function (node) { return renderNode(node, props, state); })));
|
return (React__default.createElement("div", { className: "react-flow__nodes", style: transformStyle }, nodes.map(function (node) { return renderNode(node, props, state); })));
|
||||||
});
|
});
|
||||||
NodeRenderer.displayName = 'NodeRenderer';
|
NodeRenderer.displayName = 'NodeRenderer';
|
||||||
@@ -6075,11 +6119,15 @@ var ConnectionLine = (function (_a) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var edgeClasses = classnames('react-flow__edge', 'connection', className);
|
var edgeClasses = classnames('react-flow__edge', 'connection', className);
|
||||||
var sourceHandle = handleId ?
|
var sourceHandle = handleId
|
||||||
sourceNode.__rg.handleBounds.source.find(function (d) { return d.id === handleId; }) :
|
? sourceNode.__rg.handleBounds.source.find(function (d) { return d.id === handleId; })
|
||||||
sourceNode.__rg.handleBounds.source[0];
|
: sourceNode.__rg.handleBounds.source[0];
|
||||||
var sourceHandleX = sourceHandle ? sourceHandle.x + (sourceHandle.width / 2) : sourceNode.__rg.width / 2;
|
var sourceHandleX = sourceHandle
|
||||||
var sourceHandleY = sourceHandle ? sourceHandle.y + (sourceHandle.height / 2) : sourceNode.__rg.height;
|
? sourceHandle.x + sourceHandle.width / 2
|
||||||
|
: sourceNode.__rg.width / 2;
|
||||||
|
var sourceHandleY = sourceHandle
|
||||||
|
? sourceHandle.y + sourceHandle.height / 2
|
||||||
|
: sourceNode.__rg.height;
|
||||||
var sourceX = sourceNode.__rg.position.x + sourceHandleX;
|
var sourceX = sourceNode.__rg.position.x + sourceHandleX;
|
||||||
var sourceY = sourceNode.__rg.position.y + sourceHandleY;
|
var sourceY = sourceNode.__rg.position.y + sourceHandleY;
|
||||||
var targetX = (connectionPositionX - transform[0]) * (1 / transform[2]);
|
var targetX = (connectionPositionX - transform[0]) * (1 / transform[2]);
|
||||||
@@ -6101,42 +6149,49 @@ function getHandlePosition(position, node, handle) {
|
|||||||
if (handle === void 0) { handle = null; }
|
if (handle === void 0) { handle = null; }
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
switch (position) {
|
switch (position) {
|
||||||
case 'top': return {
|
case 'top':
|
||||||
x: node.__rg.width / 2,
|
return {
|
||||||
y: 0
|
x: node.__rg.width / 2,
|
||||||
};
|
y: 0,
|
||||||
case 'right': return {
|
};
|
||||||
x: node.__rg.width,
|
case 'right':
|
||||||
y: node.__rg.height / 2
|
return {
|
||||||
};
|
x: node.__rg.width,
|
||||||
case 'bottom': return {
|
y: node.__rg.height / 2,
|
||||||
x: node.__rg.width / 2,
|
};
|
||||||
y: node.__rg.height
|
case 'bottom':
|
||||||
};
|
return {
|
||||||
case 'left': return {
|
x: node.__rg.width / 2,
|
||||||
x: 0,
|
y: node.__rg.height,
|
||||||
y: node.__rg.height / 2
|
};
|
||||||
};
|
case 'left':
|
||||||
|
return {
|
||||||
|
x: 0,
|
||||||
|
y: node.__rg.height / 2,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
switch (position) {
|
switch (position) {
|
||||||
case 'top': return {
|
case 'top':
|
||||||
x: handle.x + (handle.width / 2),
|
return {
|
||||||
y: handle.y
|
x: handle.x + handle.width / 2,
|
||||||
};
|
y: handle.y,
|
||||||
case 'right': return {
|
};
|
||||||
x: handle.x + handle.width,
|
case 'right':
|
||||||
y: handle.y + (handle.height / 2)
|
return {
|
||||||
};
|
x: handle.x + handle.width,
|
||||||
case 'bottom': return {
|
y: handle.y + handle.height / 2,
|
||||||
x: handle.x + (handle.width / 2),
|
};
|
||||||
y: handle.y + handle.height
|
case 'bottom':
|
||||||
};
|
return {
|
||||||
case 'left': return {
|
x: handle.x + handle.width / 2,
|
||||||
x: handle.x,
|
y: handle.y + handle.height,
|
||||||
y: handle.y + (handle.height / 2)
|
};
|
||||||
};
|
case 'left':
|
||||||
|
return {
|
||||||
|
x: handle.x,
|
||||||
|
y: handle.y + handle.height / 2,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function getHandle(bounds, handleId) {
|
function getHandle(bounds, handleId) {
|
||||||
@@ -6162,7 +6217,10 @@ function getEdgePositions(sourceNode, sourceHandle, sourcePosition, targetNode,
|
|||||||
var targetX = targetNode.__rg.position.x + targetHandlePos.x;
|
var targetX = targetNode.__rg.position.x + targetHandlePos.x;
|
||||||
var targetY = targetNode.__rg.position.y + targetHandlePos.y;
|
var targetY = targetNode.__rg.position.y + targetHandlePos.y;
|
||||||
return {
|
return {
|
||||||
sourceX: sourceX, sourceY: sourceY, targetX: targetX, targetY: targetY
|
sourceX: sourceX,
|
||||||
|
sourceY: sourceY,
|
||||||
|
targetX: targetX,
|
||||||
|
targetY: targetY,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
function renderEdge(edge, props, state) {
|
function renderEdge(edge, props, state) {
|
||||||
@@ -6200,7 +6258,7 @@ var EdgeRenderer = React.memo(function (_a) {
|
|||||||
transform: s.transform,
|
transform: s.transform,
|
||||||
selectedElements: s.selectedElements,
|
selectedElements: s.selectedElements,
|
||||||
connectionSourceId: s.connectionSourceId,
|
connectionSourceId: s.connectionSourceId,
|
||||||
position: s.connectionPosition
|
position: s.connectionPosition,
|
||||||
}); });
|
}); });
|
||||||
if (!width) {
|
if (!width) {
|
||||||
return null;
|
return null;
|
||||||
@@ -6209,7 +6267,12 @@ var EdgeRenderer = React.memo(function (_a) {
|
|||||||
var transformStyle = "translate(" + transform[0] + "," + transform[1] + ") scale(" + transform[2] + ")";
|
var transformStyle = "translate(" + transform[0] + "," + transform[1] + ") scale(" + transform[2] + ")";
|
||||||
return (React__default.createElement("svg", { width: width, height: height, className: "react-flow__edges" },
|
return (React__default.createElement("svg", { width: width, height: height, className: "react-flow__edges" },
|
||||||
React__default.createElement("g", { transform: transformStyle },
|
React__default.createElement("g", { transform: transformStyle },
|
||||||
edges.map(function (e) { return renderEdge(e, __assign({ width: width, height: height, connectionLineStyle: connectionLineStyle, connectionLineType: connectionLineType }, rest), state); }),
|
edges.map(function (e) {
|
||||||
|
return renderEdge(e, __assign({ width: width,
|
||||||
|
height: height,
|
||||||
|
connectionLineStyle: connectionLineStyle,
|
||||||
|
connectionLineType: connectionLineType }, rest), state);
|
||||||
|
}),
|
||||||
connectionSourceId && (React__default.createElement(ConnectionLine, { nodes: nodes, connectionSourceId: connectionSourceId, connectionPositionX: position.x, connectionPositionY: position.y, transform: transform, connectionLineStyle: connectionLineStyle, connectionLineType: connectionLineType })))));
|
connectionSourceId && (React__default.createElement(ConnectionLine, { nodes: nodes, connectionSourceId: connectionSourceId, connectionPositionX: position.x, connectionPositionY: position.y, transform: transform, connectionLineStyle: connectionLineStyle, connectionLineType: connectionLineType })))));
|
||||||
});
|
});
|
||||||
EdgeRenderer.displayName = 'EdgeRenderer';
|
EdgeRenderer.displayName = 'EdgeRenderer';
|
||||||
@@ -6221,7 +6284,7 @@ var initialRect = {
|
|||||||
y: 0,
|
y: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
draw: false
|
draw: false,
|
||||||
};
|
};
|
||||||
function getMousePosition(evt) {
|
function getMousePosition(evt) {
|
||||||
var reactFlowNode = document.querySelector('.react-flow');
|
var reactFlowNode = document.querySelector('.react-flow');
|
||||||
@@ -6244,7 +6307,7 @@ var UserSelection = React.memo(function () {
|
|||||||
function onMouseDown(evt) {
|
function onMouseDown(evt) {
|
||||||
var mousePos = getMousePosition(evt);
|
var mousePos = getMousePosition(evt);
|
||||||
if (!mousePos) {
|
if (!mousePos) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
setRect(function (currentRect) { return (__assign(__assign({}, currentRect), { startX: mousePos.x, startY: mousePos.y, x: mousePos.x, y: mousePos.y, draw: true })); });
|
setRect(function (currentRect) { return (__assign(__assign({}, currentRect), { startX: mousePos.x, startY: mousePos.y, x: mousePos.x, y: mousePos.y, draw: true })); });
|
||||||
setSelection(true);
|
setSelection(true);
|
||||||
@@ -6260,7 +6323,11 @@ var UserSelection = React.memo(function () {
|
|||||||
}
|
}
|
||||||
var negativeX = mousePos.x < currentRect.startX;
|
var negativeX = mousePos.x < currentRect.startX;
|
||||||
var negativeY = mousePos.y < currentRect.startY;
|
var negativeY = mousePos.y < currentRect.startY;
|
||||||
var nextRect = __assign(__assign({}, currentRect), { x: negativeX ? mousePos.x : currentRect.x, y: negativeY ? mousePos.y : currentRect.y, width: negativeX ? currentRect.startX - mousePos.x : mousePos.x - currentRect.startX, height: negativeY ? currentRect.startY - mousePos.y : mousePos.y - currentRect.startY });
|
var nextRect = __assign(__assign({}, currentRect), { x: negativeX ? mousePos.x : currentRect.x, y: negativeY ? mousePos.y : currentRect.y, width: negativeX
|
||||||
|
? currentRect.startX - mousePos.x
|
||||||
|
: mousePos.x - currentRect.startX, height: negativeY
|
||||||
|
? currentRect.startY - mousePos.y
|
||||||
|
: mousePos.y - currentRect.startY });
|
||||||
updateSelection(nextRect);
|
updateSelection(nextRect);
|
||||||
return nextRect;
|
return nextRect;
|
||||||
});
|
});
|
||||||
@@ -6272,19 +6339,25 @@ var UserSelection = React.memo(function () {
|
|||||||
return __assign(__assign({}, currentRect), { draw: false });
|
return __assign(__assign({}, currentRect), { draw: false });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
selectionPane.current.addEventListener('mousedown', onMouseDown);
|
if (selectionPane.current) {
|
||||||
selectionPane.current.addEventListener('mousemove', onMouseMove);
|
selectionPane.current.addEventListener('mousedown', onMouseDown);
|
||||||
selectionPane.current.addEventListener('mouseup', onMouseUp);
|
selectionPane.current.addEventListener('mousemove', onMouseMove);
|
||||||
return function () {
|
selectionPane.current.addEventListener('mouseup', onMouseUp);
|
||||||
selectionPane.current.removeEventListener('mousedown', onMouseDown);
|
return function () {
|
||||||
selectionPane.current.removeEventListener('mousemove', onMouseMove);
|
if (!selectionPane.current) {
|
||||||
selectionPane.current.removeEventListener('mouseup', onMouseUp);
|
return;
|
||||||
};
|
}
|
||||||
}, []);
|
selectionPane.current.removeEventListener('mousedown', onMouseDown);
|
||||||
|
selectionPane.current.removeEventListener('mousemove', onMouseMove);
|
||||||
|
selectionPane.current.removeEventListener('mouseup', onMouseUp);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}, [selectionPane.current]);
|
||||||
return (React__default.createElement("div", { className: "react-flow__selectionpane", ref: selectionPane }, rect.draw && (React__default.createElement("div", { className: "react-flow__selection", style: {
|
return (React__default.createElement("div", { className: "react-flow__selectionpane", ref: selectionPane }, rect.draw && (React__default.createElement("div", { className: "react-flow__selection", style: {
|
||||||
width: rect.width,
|
width: rect.width,
|
||||||
height: rect.height,
|
height: rect.height,
|
||||||
transform: "translate(" + rect.x + "px, " + rect.y + "px)"
|
transform: "translate(" + rect.x + "px, " + rect.y + "px)",
|
||||||
} }))));
|
} }))));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -7955,16 +8028,15 @@ reactDraggable.default = default_1;
|
|||||||
reactDraggable.DraggableCore = DraggableCore;
|
reactDraggable.DraggableCore = DraggableCore;
|
||||||
|
|
||||||
function getStartPositions(elements) {
|
function getStartPositions(elements) {
|
||||||
return elements
|
var startPositions = {};
|
||||||
.filter(isNode)
|
return elements.filter(isNode).reduce(function (res, node) {
|
||||||
.reduce(function (res, node) {
|
|
||||||
var startPosition = {
|
var startPosition = {
|
||||||
x: node.__rg.position.x || node.position.x,
|
x: node.__rg.position.x || node.position.x,
|
||||||
y: node.__rg.position.y || node.position.x
|
y: node.__rg.position.y || node.position.x,
|
||||||
};
|
};
|
||||||
res[node.id] = startPosition;
|
res[node.id] = startPosition;
|
||||||
return res;
|
return res;
|
||||||
}, {});
|
}, startPositions);
|
||||||
}
|
}
|
||||||
var NodesSelection = React.memo(function () {
|
var NodesSelection = React.memo(function () {
|
||||||
var _a = React.useState({ x: 0, y: 0 }), offset = _a[0], setOffset = _a[1];
|
var _a = React.useState({ x: 0, y: 0 }), offset = _a[0], setOffset = _a[1];
|
||||||
@@ -7972,7 +8044,7 @@ var NodesSelection = React.memo(function () {
|
|||||||
var state = useStoreState$1(function (s) { return ({
|
var state = useStoreState$1(function (s) { return ({
|
||||||
transform: s.transform,
|
transform: s.transform,
|
||||||
selectedNodesBbox: s.selectedNodesBbox,
|
selectedNodesBbox: s.selectedNodesBbox,
|
||||||
selectedElements: s.selectedElements
|
selectedElements: s.selectedElements,
|
||||||
}); });
|
}); });
|
||||||
var updateNodePos = useStoreActions$1(function (a) { return a.updateNodePos; });
|
var updateNodePos = useStoreActions$1(function (a) { return a.updateNodePos; });
|
||||||
var _c = state.transform, x = _c[0], y = _c[1], k = _c[2];
|
var _c = state.transform, x = _c[0], y = _c[1], k = _c[2];
|
||||||
@@ -7980,37 +8052,46 @@ var NodesSelection = React.memo(function () {
|
|||||||
var onStart = function (evt) {
|
var onStart = function (evt) {
|
||||||
var scaledClient = {
|
var scaledClient = {
|
||||||
x: evt.clientX * (1 / k),
|
x: evt.clientX * (1 / k),
|
||||||
y: evt.clientY * (1 / k)
|
y: evt.clientY * (1 / k),
|
||||||
};
|
};
|
||||||
var offsetX = scaledClient.x - position.x - x;
|
var offsetX = scaledClient.x - position.x - x;
|
||||||
var offsetY = scaledClient.y - position.y - y;
|
var offsetY = scaledClient.y - position.y - y;
|
||||||
var startPositions = getStartPositions(state.selectedElements);
|
var nextStartPositions = getStartPositions(state.selectedElements);
|
||||||
setOffset({ x: offsetX, y: offsetY });
|
if (nextStartPositions) {
|
||||||
setStartPositions(startPositions);
|
setOffset({ x: offsetX, y: offsetY });
|
||||||
|
setStartPositions(nextStartPositions);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
var onDrag = function (evt) {
|
var onDrag = function (evt) {
|
||||||
var scaledClient = {
|
var scaledClient = {
|
||||||
x: evt.clientX * (1 / k),
|
x: evt.clientX * (1 / k),
|
||||||
y: evt.clientY * (1 / k)
|
y: evt.clientY * (1 / k),
|
||||||
};
|
};
|
||||||
state.selectedElements
|
state.selectedElements.filter(isNode).forEach(function (node) {
|
||||||
.filter(isNode)
|
var pos = {
|
||||||
.forEach(function (node) {
|
x: startPositions[node.id].x +
|
||||||
updateNodePos({ id: node.id, pos: {
|
scaledClient.x -
|
||||||
x: startPositions[node.id].x + scaledClient.x - position.x - offset.x - x,
|
position.x -
|
||||||
y: startPositions[node.id].y + scaledClient.y - position.y - offset.y - y
|
offset.x -
|
||||||
} });
|
x,
|
||||||
|
y: startPositions[node.id].y +
|
||||||
|
scaledClient.y -
|
||||||
|
position.y -
|
||||||
|
offset.y -
|
||||||
|
y,
|
||||||
|
};
|
||||||
|
updateNodePos({ id: node.id, pos: pos });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
return (React__default.createElement("div", { className: "react-flow__nodesselection", style: {
|
return (React__default.createElement("div", { className: "react-flow__nodesselection", style: {
|
||||||
transform: "translate(" + x + "px," + y + "px) scale(" + k + ")"
|
transform: "translate(" + x + "px," + y + "px) scale(" + k + ")",
|
||||||
} },
|
} },
|
||||||
React__default.createElement(reactDraggable, { scale: k, onStart: function (evt) { return onStart(evt); }, onDrag: function (evt) { return onDrag(evt); } },
|
React__default.createElement(reactDraggable, { scale: k, onStart: function (evt) { return onStart(evt); }, onDrag: function (evt) { return onDrag(evt); } },
|
||||||
React__default.createElement("div", { className: "react-flow__nodesselection-rect", style: {
|
React__default.createElement("div", { className: "react-flow__nodesselection-rect", style: {
|
||||||
width: state.selectedNodesBbox.width,
|
width: state.selectedNodesBbox.width,
|
||||||
height: state.selectedNodesBbox.height,
|
height: state.selectedNodesBbox.height,
|
||||||
top: state.selectedNodesBbox.y,
|
top: state.selectedNodesBbox.y,
|
||||||
left: state.selectedNodesBbox.x
|
left: state.selectedNodesBbox.x,
|
||||||
} }))));
|
} }))));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -8039,13 +8120,14 @@ var createGridDots = function (width, height, xOffset, yOffset, gap, size) {
|
|||||||
var x = col * gap + xOffset;
|
var x = col * gap + xOffset;
|
||||||
return Array.from({ length: lineCountY }, function (_, row) {
|
return Array.from({ length: lineCountY }, function (_, row) {
|
||||||
var y = row * gap + yOffset;
|
var y = row * gap + yOffset;
|
||||||
return "M" + x + " " + (y - size) + " l" + size + " " + size + " l" + -size + " " + size + " l" + -size + " " + -size + "z";
|
return "M" + x + " " + (y -
|
||||||
|
size) + " l" + size + " " + size + " l" + -size + " " + size + " l" + -size + " " + -size + "z";
|
||||||
}).join(' ');
|
}).join(' ');
|
||||||
});
|
});
|
||||||
return values.join(' ');
|
return values.join(' ');
|
||||||
};
|
};
|
||||||
var Grid = React.memo(function (_a) {
|
var Grid = React.memo(function (_a) {
|
||||||
var _b = _a.gap, gap = _b === void 0 ? 24 : _b, _c = _a.color, color = _c === void 0 ? '#aaa' : _c, _d = _a.size, size = _d === void 0 ? 0.5 : _d, _e = _a.style, style = _e === void 0 ? {} : _e, _f = _a.className, className = _f === void 0 ? null : _f, _g = _a.backgroundType, backgroundType = _g === void 0 ? GridType.Dots : _g;
|
var _b = _a.gap, gap = _b === void 0 ? 24 : _b, _c = _a.color, color = _c === void 0 ? '#aaa' : _c, _d = _a.size, size = _d === void 0 ? 0.5 : _d, _e = _a.style, style = _e === void 0 ? {} : _e, _f = _a.className, className = _f === void 0 ? '' : _f, _g = _a.backgroundType, backgroundType = _g === void 0 ? GridType.Dots : _g;
|
||||||
var _h = useStoreState$1(function (s) { return s; }), width = _h.width, height = _h.height, _j = _h.transform, x = _j[0], y = _j[1], scale = _j[2];
|
var _h = useStoreState$1(function (s) { return s; }), width = _h.width, height = _h.height, _j = _h.transform, x = _j[0], y = _j[1], scale = _j[2];
|
||||||
var gridClasses = classnames('react-flow__grid', className);
|
var gridClasses = classnames('react-flow__grid', className);
|
||||||
var scaledGap = gap * scale;
|
var scaledGap = gap * scale;
|
||||||
@@ -8064,11 +8146,11 @@ Grid.displayName = 'Grid';
|
|||||||
|
|
||||||
var isInputDOMNode = function (e) {
|
var isInputDOMNode = function (e) {
|
||||||
var target = e.target;
|
var target = e.target;
|
||||||
return e && target && ['INPUT', 'SELECT', 'TEXTAREA'].includes(target.nodeName);
|
return (e && target && ['INPUT', 'SELECT', 'TEXTAREA'].includes(target.nodeName));
|
||||||
};
|
};
|
||||||
var getDimensions = function (node) { return ({
|
var getDimensions = function (node) { return ({
|
||||||
width: node.offsetWidth,
|
width: node.offsetWidth,
|
||||||
height: node.offsetHeight
|
height: node.offsetHeight,
|
||||||
}); };
|
}); };
|
||||||
|
|
||||||
var useKeyPress = (function (keyCode) {
|
var useKeyPress = (function (keyCode) {
|
||||||
@@ -8106,8 +8188,10 @@ var useD3Zoom = (function (zoomPane, onMove, shiftPressed) {
|
|||||||
var initD3 = useStoreActions$1(function (actions) { return actions.initD3; });
|
var initD3 = useStoreActions$1(function (actions) { return actions.initD3; });
|
||||||
var updateTransform = useStoreActions$1(function (actions) { return actions.updateTransform; });
|
var updateTransform = useStoreActions$1(function (actions) { return actions.updateTransform; });
|
||||||
React.useEffect(function () {
|
React.useEffect(function () {
|
||||||
var selection = select(zoomPane.current).call(d3ZoomInstance);
|
if (zoomPane.current) {
|
||||||
initD3({ zoom: d3ZoomInstance, selection: selection });
|
var selection = select(zoomPane.current).call(d3ZoomInstance);
|
||||||
|
initD3({ zoom: d3ZoomInstance, selection: selection });
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
React.useEffect(function () {
|
React.useEffect(function () {
|
||||||
if (shiftPressed) {
|
if (shiftPressed) {
|
||||||
@@ -8115,13 +8199,14 @@ var useD3Zoom = (function (zoomPane, onMove, shiftPressed) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
d3ZoomInstance.on('zoom', function () {
|
d3ZoomInstance.on('zoom', function () {
|
||||||
if (event.sourceEvent && event.sourceEvent.target !== zoomPane.current) {
|
if (event.sourceEvent &&
|
||||||
return false;
|
event.sourceEvent.target !== zoomPane.current) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
updateTransform(event.transform);
|
updateTransform(event.transform);
|
||||||
onMove();
|
onMove();
|
||||||
});
|
});
|
||||||
if (state.d3Selection) {
|
if (state.d3Selection && state.d3Zoom) {
|
||||||
// we need to restore the graph transform otherwise d3 zoom transform and graph transform are not synced
|
// we need to restore the graph transform otherwise d3 zoom transform and graph transform are not synced
|
||||||
var graphTransform = identity$1
|
var graphTransform = identity$1
|
||||||
.translate(state.transform[0], state.transform[1])
|
.translate(state.transform[0], state.transform[1])
|
||||||
@@ -8137,14 +8222,18 @@ var useD3Zoom = (function (zoomPane, onMove, shiftPressed) {
|
|||||||
|
|
||||||
var useGlobalKeyHandler = (function (_a) {
|
var useGlobalKeyHandler = (function (_a) {
|
||||||
var deleteKeyCode = _a.deleteKeyCode, onElementsRemove = _a.onElementsRemove;
|
var deleteKeyCode = _a.deleteKeyCode, onElementsRemove = _a.onElementsRemove;
|
||||||
var state = useStoreState$1(function (s) { return ({ selectedElements: s.selectedElements, edges: s.edges }); });
|
var state = useStoreState$1(function (s) { return ({
|
||||||
|
selectedElements: s.selectedElements,
|
||||||
|
edges: s.edges,
|
||||||
|
}); });
|
||||||
var setNodesSelection = useStoreActions$1(function (a) { return a.setNodesSelection; });
|
var setNodesSelection = useStoreActions$1(function (a) { return a.setNodesSelection; });
|
||||||
var deleteKeyPressed = useKeyPress(deleteKeyCode);
|
var deleteKeyPressed = useKeyPress(deleteKeyCode);
|
||||||
React.useEffect(function () {
|
React.useEffect(function () {
|
||||||
if (deleteKeyPressed && state.selectedElements.length) {
|
if (deleteKeyPressed && state.selectedElements.length) {
|
||||||
var elementsToRemove = state.selectedElements;
|
var elementsToRemove = state.selectedElements;
|
||||||
// we also want to remove the edges if only one node is selected
|
// we also want to remove the edges if only one node is selected
|
||||||
if (state.selectedElements.length === 1 && !isEdge(state.selectedElements[0])) {
|
if (state.selectedElements.length === 1 &&
|
||||||
|
!isEdge(state.selectedElements[0])) {
|
||||||
var node = state.selectedElements[0];
|
var node = state.selectedElements[0];
|
||||||
var connectedEdges = getConnectedEdges([node], state.edges);
|
var connectedEdges = getConnectedEdges([node], state.edges);
|
||||||
elementsToRemove = __spreadArrays(state.selectedElements, connectedEdges);
|
elementsToRemove = __spreadArrays(state.selectedElements, connectedEdges);
|
||||||
@@ -8153,14 +8242,13 @@ var useGlobalKeyHandler = (function (_a) {
|
|||||||
setNodesSelection({ isActive: false });
|
setNodesSelection({ isActive: false });
|
||||||
}
|
}
|
||||||
}, [deleteKeyPressed]);
|
}, [deleteKeyPressed]);
|
||||||
return null;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var useElementUpdater = function (elements) {
|
var useElementUpdater = function (elements) {
|
||||||
var state = useStoreState$1(function (s) { return ({
|
var state = useStoreState$1(function (s) { return ({
|
||||||
nodes: s.nodes,
|
nodes: s.nodes,
|
||||||
edges: s.edges,
|
edges: s.edges,
|
||||||
transform: s.transform
|
transform: s.transform,
|
||||||
}); });
|
}); });
|
||||||
var setNodes = useStoreActions$1(function (a) { return a.setNodes; });
|
var setNodes = useStoreActions$1(function (a) { return a.setNodes; });
|
||||||
var setEdges = useStoreActions$1(function (a) { return a.setEdges; });
|
var setEdges = useStoreActions$1(function (a) { return a.setEdges; });
|
||||||
@@ -8170,7 +8258,8 @@ var useElementUpdater = function (elements) {
|
|||||||
var nextNodes = nodes.map(function (propNode) {
|
var nextNodes = nodes.map(function (propNode) {
|
||||||
var existingNode = state.nodes.find(function (n) { return n.id === propNode.id; });
|
var existingNode = state.nodes.find(function (n) { return n.id === propNode.id; });
|
||||||
if (existingNode) {
|
if (existingNode) {
|
||||||
var data = !fastDeepEqual(existingNode.data, propNode.data) ? __assign(__assign({}, existingNode.data), propNode.data) : existingNode.data;
|
var data = !fastDeepEqual(existingNode.data, propNode.data)
|
||||||
|
? __assign(__assign({}, existingNode.data), propNode.data) : existingNode.data;
|
||||||
return __assign(__assign({}, existingNode), { data: data });
|
return __assign(__assign({}, existingNode), { data: data });
|
||||||
}
|
}
|
||||||
return parseElement(propNode, state.transform);
|
return parseElement(propNode, state.transform);
|
||||||
@@ -8184,11 +8273,10 @@ var useElementUpdater = function (elements) {
|
|||||||
setEdges(edges);
|
setEdges(edges);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var GraphView = React.memo(function (_a) {
|
var GraphView = React.memo(function (_a) {
|
||||||
var nodeTypes = _a.nodeTypes, edgeTypes = _a.edgeTypes, onMove = _a.onMove, onLoad = _a.onLoad, onElementClick = _a.onElementClick, onNodeDragStop = _a.onNodeDragStop, connectionLineType = _a.connectionLineType, connectionLineStyle = _a.connectionLineStyle, selectionKeyCode = _a.selectionKeyCode, onElementsRemove = _a.onElementsRemove, deleteKeyCode = _a.deleteKeyCode, elements = _a.elements, showBackground = _a.showBackground, backgroundGap = _a.backgroundGap, backgroundColor = _a.backgroundColor, backgroundType = _a.backgroundType, onConnect = _a.onConnect;
|
var nodeTypes = _a.nodeTypes, edgeTypes = _a.edgeTypes, onMove = _a.onMove, onLoad = _a.onLoad, onElementClick = _a.onElementClick, onNodeDragStop = _a.onNodeDragStop, connectionLineType = _a.connectionLineType, connectionLineStyle = _a.connectionLineStyle, selectionKeyCode = _a.selectionKeyCode, onElementsRemove = _a.onElementsRemove, deleteKeyCode = _a.deleteKeyCode, elements = _a.elements, showBackground = _a.showBackground, backgroundGap = _a.backgroundGap, backgroundColor = _a.backgroundColor, backgroundType = _a.backgroundType, onConnect = _a.onConnect, snapToGrid = _a.snapToGrid, snapGrid = _a.snapGrid;
|
||||||
var zoomPane = React.useRef(null);
|
var zoomPane = React.useRef(null);
|
||||||
var rendererNode = React.useRef(null);
|
var rendererNode = React.useRef(null);
|
||||||
var state = useStoreState$1(function (s) { return ({
|
var state = useStoreState$1(function (s) { return ({
|
||||||
@@ -8197,14 +8285,18 @@ var GraphView = React.memo(function (_a) {
|
|||||||
nodes: s.nodes,
|
nodes: s.nodes,
|
||||||
edges: s.edges,
|
edges: s.edges,
|
||||||
d3Initialised: s.d3Initialised,
|
d3Initialised: s.d3Initialised,
|
||||||
nodesSelectionActive: s.nodesSelectionActive
|
nodesSelectionActive: s.nodesSelectionActive,
|
||||||
}); });
|
}); });
|
||||||
var updateSize = useStoreActions$1(function (actions) { return actions.updateSize; });
|
var updateSize = useStoreActions$1(function (actions) { return actions.updateSize; });
|
||||||
var setNodesSelection = useStoreActions$1(function (actions) { return actions.setNodesSelection; });
|
var setNodesSelection = useStoreActions$1(function (actions) { return actions.setNodesSelection; });
|
||||||
var setOnConnect = useStoreActions$1(function (a) { return a.setOnConnect; });
|
var setOnConnect = useStoreActions$1(function (a) { return a.setOnConnect; });
|
||||||
|
var setSnapGrid = useStoreActions$1(function (actions) { return actions.setSnapGrid; });
|
||||||
var selectionKeyPressed = useKeyPress(selectionKeyCode);
|
var selectionKeyPressed = useKeyPress(selectionKeyCode);
|
||||||
var onZoomPaneClick = function () { return setNodesSelection({ isActive: false }); };
|
var onZoomPaneClick = function () { return setNodesSelection({ isActive: false }); };
|
||||||
var updateDimensions = function () {
|
var updateDimensions = function () {
|
||||||
|
if (!rendererNode.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var size = getDimensions(rendererNode.current);
|
var size = getDimensions(rendererNode.current);
|
||||||
updateSize(size);
|
updateSize(size);
|
||||||
};
|
};
|
||||||
@@ -8222,10 +8314,13 @@ var GraphView = React.memo(function (_a) {
|
|||||||
onLoad({
|
onLoad({
|
||||||
fitView: fitView,
|
fitView: fitView,
|
||||||
zoomIn: zoomIn,
|
zoomIn: zoomIn,
|
||||||
zoomOut: zoomOut
|
zoomOut: zoomOut,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [state.d3Initialised]);
|
}, [state.d3Initialised]);
|
||||||
|
React.useEffect(function () {
|
||||||
|
setSnapGrid({ snapToGrid: snapToGrid, snapGrid: snapGrid });
|
||||||
|
}, [snapToGrid]);
|
||||||
useGlobalKeyHandler({ onElementsRemove: onElementsRemove, deleteKeyCode: deleteKeyCode });
|
useGlobalKeyHandler({ onElementsRemove: onElementsRemove, deleteKeyCode: deleteKeyCode });
|
||||||
useElementUpdater(elements);
|
useElementUpdater(elements);
|
||||||
return (React__default.createElement("div", { className: "react-flow__renderer", ref: rendererNode },
|
return (React__default.createElement("div", { className: "react-flow__renderer", ref: rendererNode },
|
||||||
@@ -8241,10 +8336,10 @@ GraphView.displayName = 'GraphView';
|
|||||||
function onMouseDown(evt, nodeId, setSourceId, setPosition, onConnect, isTarget, isValidConnection) {
|
function onMouseDown(evt, nodeId, setSourceId, setPosition, onConnect, isTarget, isValidConnection) {
|
||||||
var reactFlowNode = document.querySelector('.react-flow');
|
var reactFlowNode = document.querySelector('.react-flow');
|
||||||
if (!reactFlowNode) {
|
if (!reactFlowNode) {
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
var containerBounds = reactFlowNode.getBoundingClientRect();
|
var containerBounds = reactFlowNode.getBoundingClientRect();
|
||||||
var recentHoveredHandle = null;
|
var recentHoveredHandle;
|
||||||
setPosition({
|
setPosition({
|
||||||
x: evt.clientX - containerBounds.left,
|
x: evt.clientX - containerBounds.left,
|
||||||
y: evt.clientY - containerBounds.top,
|
y: evt.clientY - containerBounds.top,
|
||||||
@@ -8252,7 +8347,7 @@ function onMouseDown(evt, nodeId, setSourceId, setPosition, onConnect, isTarget,
|
|||||||
setSourceId(nodeId);
|
setSourceId(nodeId);
|
||||||
function resetRecentHandle() {
|
function resetRecentHandle() {
|
||||||
if (!recentHoveredHandle) {
|
if (!recentHoveredHandle) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
recentHoveredHandle.classList.remove('valid');
|
recentHoveredHandle.classList.remove('valid');
|
||||||
recentHoveredHandle.classList.remove('connecting');
|
recentHoveredHandle.classList.remove('connecting');
|
||||||
@@ -8264,9 +8359,11 @@ function onMouseDown(evt, nodeId, setSourceId, setPosition, onConnect, isTarget,
|
|||||||
elementBelow: elementBelow,
|
elementBelow: elementBelow,
|
||||||
isValid: false,
|
isValid: false,
|
||||||
connection: { source: null, target: null },
|
connection: { source: null, target: null },
|
||||||
isHoveringHandle: false
|
isHoveringHandle: false,
|
||||||
};
|
};
|
||||||
if (elementBelow && (elementBelow.classList.contains('target') || elementBelow.classList.contains('source'))) {
|
if (elementBelow &&
|
||||||
|
(elementBelow.classList.contains('target') ||
|
||||||
|
elementBelow.classList.contains('source'))) {
|
||||||
var connection = { source: null, target: null };
|
var connection = { source: null, target: null };
|
||||||
if (isTarget) {
|
if (isTarget) {
|
||||||
var sourceId = elementBelow.getAttribute('data-nodeid');
|
var sourceId = elementBelow.getAttribute('data-nodeid');
|
||||||
@@ -8293,7 +8390,7 @@ function onMouseDown(evt, nodeId, setSourceId, setPosition, onConnect, isTarget,
|
|||||||
return resetRecentHandle();
|
return resetRecentHandle();
|
||||||
}
|
}
|
||||||
var isOwnHandle = connection.source === connection.target;
|
var isOwnHandle = connection.source === connection.target;
|
||||||
if (!isOwnHandle) {
|
if (!isOwnHandle && elementBelow) {
|
||||||
recentHoveredHandle = elementBelow;
|
recentHoveredHandle = elementBelow;
|
||||||
elementBelow.classList.add('connecting');
|
elementBelow.classList.add('connecting');
|
||||||
elementBelow.classList.toggle('valid', isValid);
|
elementBelow.classList.toggle('valid', isValid);
|
||||||
@@ -8315,9 +8412,14 @@ function onMouseDown(evt, nodeId, setSourceId, setPosition, onConnect, isTarget,
|
|||||||
var BaseHandle = React.memo(function (_a) {
|
var BaseHandle = React.memo(function (_a) {
|
||||||
var type = _a.type, nodeId = _a.nodeId, onConnect = _a.onConnect, position = _a.position, setSourceId = _a.setSourceId, setPosition = _a.setPosition, className = _a.className, _b = _a.id, id = _b === void 0 ? false : _b, isValidConnection = _a.isValidConnection, rest = __rest(_a, ["type", "nodeId", "onConnect", "position", "setSourceId", "setPosition", "className", "id", "isValidConnection"]);
|
var type = _a.type, nodeId = _a.nodeId, onConnect = _a.onConnect, position = _a.position, setSourceId = _a.setSourceId, setPosition = _a.setPosition, className = _a.className, _b = _a.id, id = _b === void 0 ? false : _b, isValidConnection = _a.isValidConnection, rest = __rest(_a, ["type", "nodeId", "onConnect", "position", "setSourceId", "setPosition", "className", "id", "isValidConnection"]);
|
||||||
var isTarget = type === 'target';
|
var isTarget = type === 'target';
|
||||||
var handleClasses = classnames('react-flow__handle', className, position, { source: !isTarget, target: isTarget });
|
var handleClasses = classnames('react-flow__handle', className, position, {
|
||||||
|
source: !isTarget,
|
||||||
|
target: isTarget,
|
||||||
|
});
|
||||||
var nodeIdWithHandleId = id ? nodeId + "__" + id : nodeId;
|
var nodeIdWithHandleId = id ? nodeId + "__" + id : nodeId;
|
||||||
return (React__default.createElement("div", __assign({ "data-nodeid": nodeIdWithHandleId, "data-handlepos": position, className: handleClasses, onMouseDown: function (evt) { return onMouseDown(evt, nodeIdWithHandleId, setSourceId, setPosition, onConnect, isTarget, isValidConnection); } }, rest)));
|
return (React__default.createElement("div", __assign({ "data-nodeid": nodeIdWithHandleId, "data-handlepos": position, className: handleClasses, onMouseDown: function (evt) {
|
||||||
|
return onMouseDown(evt, nodeIdWithHandleId, setSourceId, setPosition, onConnect, isTarget, isValidConnection);
|
||||||
|
} }, rest)));
|
||||||
});
|
});
|
||||||
BaseHandle.displayName = 'BaseHandle';
|
BaseHandle.displayName = 'BaseHandle';
|
||||||
|
|
||||||
@@ -8330,7 +8432,7 @@ var Handle = React.memo(function (_a) {
|
|||||||
var nodeId = React.useContext(NodeIdContext);
|
var nodeId = React.useContext(NodeIdContext);
|
||||||
var _f = useStoreActions$1(function (a) { return ({
|
var _f = useStoreActions$1(function (a) { return ({
|
||||||
setPosition: a.setConnectionPosition,
|
setPosition: a.setConnectionPosition,
|
||||||
setSourceId: a.setConnectionSourceId
|
setSourceId: a.setConnectionSourceId,
|
||||||
}); }), setPosition = _f.setPosition, setSourceId = _f.setSourceId;
|
}); }), setPosition = _f.setPosition, setSourceId = _f.setSourceId;
|
||||||
var onConnectAction = useStoreState$1(function (s) { return s.onConnect; });
|
var onConnectAction = useStoreState$1(function (s) { return s.onConnect; });
|
||||||
var onConnectExtended = function (params) {
|
var onConnectExtended = function (params) {
|
||||||
@@ -8345,7 +8447,7 @@ var nodeStyles = {
|
|||||||
background: '#ff6060',
|
background: '#ff6060',
|
||||||
padding: 10,
|
padding: 10,
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
width: 150
|
width: 150,
|
||||||
};
|
};
|
||||||
var DefaultNode = (function (_a) {
|
var DefaultNode = (function (_a) {
|
||||||
var data = _a.data, style = _a.style;
|
var data = _a.data, style = _a.style;
|
||||||
@@ -8359,7 +8461,7 @@ var nodeStyles$1 = {
|
|||||||
background: '#9999ff',
|
background: '#9999ff',
|
||||||
padding: 10,
|
padding: 10,
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
width: 150
|
width: 150,
|
||||||
};
|
};
|
||||||
var InputNode = (function (_a) {
|
var InputNode = (function (_a) {
|
||||||
var data = _a.data, style = _a.style;
|
var data = _a.data, style = _a.style;
|
||||||
@@ -8372,7 +8474,7 @@ var nodeStyles$2 = {
|
|||||||
background: '#55dd99',
|
background: '#55dd99',
|
||||||
padding: 10,
|
padding: 10,
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
width: 150
|
width: 150,
|
||||||
};
|
};
|
||||||
var OutputNode = (function (_a) {
|
var OutputNode = (function (_a) {
|
||||||
var data = _a.data, style = _a.style;
|
var data = _a.data, style = _a.style;
|
||||||
@@ -8649,15 +8751,18 @@ var getHandleBounds = function (selector, nodeElement, parentBounds, k) {
|
|||||||
if (!handles || !handles.length) {
|
if (!handles || !handles.length) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return [].map.call(handles, function (handle) {
|
var handlesArray = Array.from(handles);
|
||||||
|
return handlesArray.map(function (handle) {
|
||||||
var bounds = handle.getBoundingClientRect();
|
var bounds = handle.getBoundingClientRect();
|
||||||
var dimensions = getDimensions(handle);
|
var dimensions = getDimensions(handle);
|
||||||
var nodeIdAttr = handle.getAttribute('data-nodeid');
|
var nodeIdAttr = handle.getAttribute('data-nodeid');
|
||||||
var handlePosition = handle.getAttribute('data-handlepos');
|
var handlePosition = handle.getAttribute('data-handlepos');
|
||||||
var nodeIdSplitted = nodeIdAttr.split('__');
|
var nodeIdSplitted = nodeIdAttr ? nodeIdAttr.split('__') : null;
|
||||||
var handleId = null;
|
var handleId = null;
|
||||||
if (nodeIdSplitted) {
|
if (nodeIdSplitted) {
|
||||||
handleId = (nodeIdSplitted.length ? nodeIdSplitted[1] : nodeIdSplitted);
|
handleId = (nodeIdSplitted.length
|
||||||
|
? nodeIdSplitted[1]
|
||||||
|
: nodeIdSplitted);
|
||||||
}
|
}
|
||||||
return __assign({ id: handleId, position: handlePosition, x: (bounds.left - parentBounds.left) * (1 / k), y: (bounds.top - parentBounds.top) * (1 / k) }, dimensions);
|
return __assign({ id: handleId, position: handlePosition, x: (bounds.left - parentBounds.left) * (1 / k), y: (bounds.top - parentBounds.top) * (1 / k) }, dimensions);
|
||||||
});
|
});
|
||||||
@@ -8668,7 +8773,7 @@ var onStart = function (evt, onClick, id, type, data, setOffset, transform, posi
|
|||||||
}
|
}
|
||||||
var scaledClient = {
|
var scaledClient = {
|
||||||
x: evt.clientX * (1 / transform[2]),
|
x: evt.clientX * (1 / transform[2]),
|
||||||
y: evt.clientY * (1 / transform[2])
|
y: evt.clientY * (1 / transform[2]),
|
||||||
};
|
};
|
||||||
var offsetX = scaledClient.x - position.x - transform[0];
|
var offsetX = scaledClient.x - position.x - transform[0];
|
||||||
var offsetY = scaledClient.y - position.y - transform[1];
|
var offsetY = scaledClient.y - position.y - transform[1];
|
||||||
@@ -8680,19 +8785,25 @@ var onStart = function (evt, onClick, id, type, data, setOffset, transform, posi
|
|||||||
var onDrag = function (evt, setDragging, id, offset, transform) {
|
var onDrag = function (evt, setDragging, id, offset, transform) {
|
||||||
var scaledClient = {
|
var scaledClient = {
|
||||||
x: evt.clientX * (1 / transform[2]),
|
x: evt.clientX * (1 / transform[2]),
|
||||||
y: evt.clientY * (1 / transform[2])
|
y: evt.clientY * (1 / transform[2]),
|
||||||
};
|
};
|
||||||
setDragging(true);
|
setDragging(true);
|
||||||
store.dispatch.updateNodePos({ id: id, pos: {
|
store.dispatch.updateNodePos({
|
||||||
|
id: id,
|
||||||
|
pos: {
|
||||||
x: scaledClient.x - transform[0] - offset.x,
|
x: scaledClient.x - transform[0] - offset.x,
|
||||||
y: scaledClient.y - transform[1] - offset.y
|
y: scaledClient.y - transform[1] - offset.y,
|
||||||
} });
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
var onStop = function (onNodeDragStop, isDragging, setDragging, id, type, position, data) {
|
var onStop = function (onNodeDragStop, isDragging, setDragging, id, type, position, data) {
|
||||||
if (isDragging) {
|
if (isDragging) {
|
||||||
setDragging(false);
|
setDragging(false);
|
||||||
onNodeDragStop({
|
onNodeDragStop({
|
||||||
id: id, type: type, position: position, data: data
|
id: id,
|
||||||
|
type: type,
|
||||||
|
position: position,
|
||||||
|
data: data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -8704,17 +8815,20 @@ var wrapNode = (function (NodeComponent) {
|
|||||||
var _c = React.useState(false), isDragging = _c[0], setDragging = _c[1];
|
var _c = React.useState(false), isDragging = _c[0], setDragging = _c[1];
|
||||||
var position = { x: xPos, y: yPos };
|
var position = { x: xPos, y: yPos };
|
||||||
var nodeClasses = classnames('react-flow__node', { selected: selected });
|
var nodeClasses = classnames('react-flow__node', { selected: selected });
|
||||||
var nodeStyle = { zIndex: selected ? 10 : 3, transform: "translate(" + xPos + "px," + yPos + "px)" };
|
var nodeStyle = {
|
||||||
|
zIndex: selected ? 10 : 3,
|
||||||
|
transform: "translate(" + xPos + "px," + yPos + "px)",
|
||||||
|
};
|
||||||
var updateNode = function () {
|
var updateNode = function () {
|
||||||
if (!nodeElement.current) {
|
if (!nodeElement.current) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
var storeState = store.getState();
|
var storeState = store.getState();
|
||||||
var bounds = nodeElement.current.getBoundingClientRect();
|
var bounds = nodeElement.current.getBoundingClientRect();
|
||||||
var dimensions = getDimensions(nodeElement.current);
|
var dimensions = getDimensions(nodeElement.current);
|
||||||
var handleBounds = {
|
var handleBounds = {
|
||||||
source: getHandleBounds('.source', nodeElement.current, bounds, storeState.transform[2]),
|
source: getHandleBounds('.source', nodeElement.current, bounds, storeState.transform[2]),
|
||||||
target: getHandleBounds('.target', nodeElement.current, bounds, storeState.transform[2])
|
target: getHandleBounds('.target', nodeElement.current, bounds, storeState.transform[2]),
|
||||||
};
|
};
|
||||||
store.dispatch.updateNodeData(__assign(__assign({ id: id }, dimensions), { handleBounds: handleBounds }));
|
store.dispatch.updateNodeData(__assign(__assign({ id: id }, dimensions), { handleBounds: handleBounds }));
|
||||||
};
|
};
|
||||||
@@ -8734,8 +8848,15 @@ var wrapNode = (function (NodeComponent) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}, [nodeElement.current]);
|
}, [nodeElement.current]);
|
||||||
return (React__default.createElement(DraggableCore, { onStart: function (evt) { return onStart(evt, onClick, id, type, data, setOffset, transform, position); }, onDrag: function (evt) { return onDrag(evt, setDragging, id, offset, transform); }, onStop: function () { return onStop(onNodeDragStop, isDragging, setDragging, id, type, position, data); }, scale: transform[2] },
|
return (React__default.createElement(DraggableCore, { onStart: function (evt) {
|
||||||
|
return onStart(evt, onClick, id, type, data, setOffset, transform, position);
|
||||||
|
}, onDrag: function (evt) {
|
||||||
|
return onDrag(evt, setDragging, id, offset, transform);
|
||||||
|
}, onStop: function () {
|
||||||
|
return onStop(onNodeDragStop, isDragging, setDragging, id, type, position, data);
|
||||||
|
}, scale: transform[2] },
|
||||||
React__default.createElement("div", { className: nodeClasses, ref: nodeElement, style: nodeStyle },
|
React__default.createElement("div", { className: nodeClasses, ref: nodeElement, style: nodeStyle },
|
||||||
React__default.createElement(Provider, { value: id },
|
React__default.createElement(Provider, { value: id },
|
||||||
React__default.createElement(NodeComponent, { id: id, data: data, type: type, style: style, selected: selected })))));
|
React__default.createElement(NodeComponent, { id: id, data: data, type: type, style: style, selected: selected })))));
|
||||||
@@ -8748,15 +8869,15 @@ function createNodeTypes(nodeTypes) {
|
|||||||
var standardTypes = {
|
var standardTypes = {
|
||||||
input: wrapNode((nodeTypes.input || InputNode)),
|
input: wrapNode((nodeTypes.input || InputNode)),
|
||||||
default: wrapNode((nodeTypes.default || DefaultNode)),
|
default: wrapNode((nodeTypes.default || DefaultNode)),
|
||||||
output: wrapNode((nodeTypes.output || OutputNode))
|
output: wrapNode((nodeTypes.output || OutputNode)),
|
||||||
};
|
};
|
||||||
var specialTypes = Object
|
var wrappedTypes = {};
|
||||||
.keys(nodeTypes)
|
var specialTypes = Object.keys(nodeTypes)
|
||||||
.filter(function (k) { return !['input', 'default', 'output'].includes(k); })
|
.filter(function (k) { return !['input', 'default', 'output'].includes(k); })
|
||||||
.reduce(function (res, key) {
|
.reduce(function (res, key) {
|
||||||
res[key] = wrapNode((nodeTypes[key] || DefaultNode));
|
res[key] = wrapNode((nodeTypes[key] || DefaultNode));
|
||||||
return res;
|
return res;
|
||||||
}, {});
|
}, wrappedTypes);
|
||||||
return __assign(__assign({}, standardTypes), specialTypes);
|
return __assign(__assign({}, standardTypes), specialTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8765,15 +8886,17 @@ var BezierEdge = React.memo(function (_a) {
|
|||||||
var yOffset = Math.abs(targetY - sourceY) / 2;
|
var yOffset = Math.abs(targetY - sourceY) / 2;
|
||||||
var centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
var centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
||||||
var dAttr = "M" + sourceX + "," + sourceY + " C" + sourceX + "," + centerY + " " + targetX + "," + centerY + " " + targetX + "," + targetY;
|
var dAttr = "M" + sourceX + "," + sourceY + " C" + sourceX + "," + centerY + " " + targetX + "," + centerY + " " + targetX + "," + targetY;
|
||||||
if (['left', 'right'].includes(sourcePosition) && ['left', 'right'].includes(targetPosition)) {
|
if (['left', 'right'].includes(sourcePosition) &&
|
||||||
|
['left', 'right'].includes(targetPosition)) {
|
||||||
var xOffset = Math.abs(targetX - sourceX) / 2;
|
var xOffset = Math.abs(targetX - sourceX) / 2;
|
||||||
var centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
|
var centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
|
||||||
dAttr = "M" + sourceX + "," + sourceY + " C" + centerX + "," + sourceY + " " + centerX + "," + targetY + " " + targetX + "," + targetY;
|
dAttr = "M" + sourceX + "," + sourceY + " C" + centerX + "," + sourceY + " " + centerX + "," + targetY + " " + targetX + "," + targetY;
|
||||||
}
|
}
|
||||||
else if (['left', 'right'].includes(sourcePosition) || ['left', 'right'].includes(targetPosition)) {
|
else if (['left', 'right'].includes(sourcePosition) ||
|
||||||
|
['left', 'right'].includes(targetPosition)) {
|
||||||
dAttr = "M" + sourceX + "," + sourceY + " C" + sourceX + "," + targetY + " " + sourceX + "," + targetY + " " + targetX + "," + targetY;
|
dAttr = "M" + sourceX + "," + sourceY + " C" + sourceX + "," + targetY + " " + sourceX + "," + targetY + " " + targetX + "," + targetY;
|
||||||
}
|
}
|
||||||
return (React__default.createElement("path", __assign({}, style, { d: dAttr })));
|
return React__default.createElement("path", __assign({}, style, { d: dAttr }));
|
||||||
});
|
});
|
||||||
|
|
||||||
var StraightEdge = React.memo(function (_a) {
|
var StraightEdge = React.memo(function (_a) {
|
||||||
@@ -8794,7 +8917,7 @@ var wrapEdge = (function (EdgeComponent) {
|
|||||||
var edgeClasses = classnames('react-flow__edge', { selected: selected, animated: animated });
|
var edgeClasses = classnames('react-flow__edge', { selected: selected, animated: animated });
|
||||||
var onEdgeClick = function (evt) {
|
var onEdgeClick = function (evt) {
|
||||||
if (isInputDOMNode(evt)) {
|
if (isInputDOMNode(evt)) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
store.dispatch.setSelectedElements({ id: id, source: source, target: target });
|
store.dispatch.setSelectedElements({ id: id, source: source, target: target });
|
||||||
onClick({ id: id, source: source, target: target, type: type });
|
onClick({ id: id, source: source, target: target, type: type });
|
||||||
@@ -8809,15 +8932,15 @@ var wrapEdge = (function (EdgeComponent) {
|
|||||||
function createEdgeTypes(edgeTypes) {
|
function createEdgeTypes(edgeTypes) {
|
||||||
var standardTypes = {
|
var standardTypes = {
|
||||||
default: wrapEdge((edgeTypes.default || BezierEdge)),
|
default: wrapEdge((edgeTypes.default || BezierEdge)),
|
||||||
straight: wrapEdge((edgeTypes.bezier || StraightEdge))
|
straight: wrapEdge((edgeTypes.bezier || StraightEdge)),
|
||||||
};
|
};
|
||||||
var specialTypes = Object
|
var wrappedTypes = {};
|
||||||
.keys(edgeTypes)
|
var specialTypes = Object.keys(edgeTypes)
|
||||||
.filter(function (k) { return !['default', 'bezier'].includes(k); })
|
.filter(function (k) { return !['default', 'bezier'].includes(k); })
|
||||||
.reduce(function (res, key) {
|
.reduce(function (res, key) {
|
||||||
res[key] = wrapEdge((edgeTypes[key] || BezierEdge));
|
res[key] = wrapEdge((edgeTypes[key] || BezierEdge));
|
||||||
return res;
|
return res;
|
||||||
}, {});
|
}, wrappedTypes);
|
||||||
return __assign(__assign({}, standardTypes), specialTypes);
|
return __assign(__assign({}, standardTypes), specialTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8852,12 +8975,12 @@ var css = ".react-flow {\n width: 100%;\n height: 100%;\n position: relative;
|
|||||||
styleInject(css);
|
styleInject(css);
|
||||||
|
|
||||||
var ReactFlow = function (_a) {
|
var ReactFlow = function (_a) {
|
||||||
var style = _a.style, onElementClick = _a.onElementClick, elements = _a.elements, children = _a.children, nodeTypes = _a.nodeTypes, edgeTypes = _a.edgeTypes, onLoad = _a.onLoad, onMove = _a.onMove, onElementsRemove = _a.onElementsRemove, onConnect = _a.onConnect, onNodeDragStop = _a.onNodeDragStop, connectionLineType = _a.connectionLineType, connectionLineStyle = _a.connectionLineStyle, deleteKeyCode = _a.deleteKeyCode, selectionKeyCode = _a.selectionKeyCode, showBackground = _a.showBackground, backgroundGap = _a.backgroundGap, backgroundType = _a.backgroundType, backgroundColor = _a.backgroundColor;
|
var style = _a.style, onElementClick = _a.onElementClick, elements = _a.elements, children = _a.children, nodeTypes = _a.nodeTypes, edgeTypes = _a.edgeTypes, onLoad = _a.onLoad, onMove = _a.onMove, onElementsRemove = _a.onElementsRemove, onConnect = _a.onConnect, onNodeDragStop = _a.onNodeDragStop, connectionLineType = _a.connectionLineType, connectionLineStyle = _a.connectionLineStyle, deleteKeyCode = _a.deleteKeyCode, selectionKeyCode = _a.selectionKeyCode, showBackground = _a.showBackground, backgroundGap = _a.backgroundGap, backgroundType = _a.backgroundType, backgroundColor = _a.backgroundColor, snapToGrid = _a.snapToGrid, snapGrid = _a.snapGrid;
|
||||||
var nodeTypesParsed = React.useMemo(function () { return createNodeTypes(nodeTypes); }, []);
|
var nodeTypesParsed = React.useMemo(function () { return createNodeTypes(nodeTypes); }, []);
|
||||||
var edgeTypesParsed = React.useMemo(function () { return createEdgeTypes(edgeTypes); }, []);
|
var edgeTypesParsed = React.useMemo(function () { return createEdgeTypes(edgeTypes); }, []);
|
||||||
return (React__default.createElement("div", { style: style, className: "react-flow" },
|
return (React__default.createElement("div", { style: style, className: "react-flow" },
|
||||||
React__default.createElement(StoreProvider, { store: store },
|
React__default.createElement(StoreProvider, { store: store },
|
||||||
React__default.createElement(GraphView, { onLoad: onLoad, onMove: onMove, onElementClick: onElementClick, onNodeDragStop: onNodeDragStop, nodeTypes: nodeTypesParsed, edgeTypes: edgeTypesParsed, connectionLineType: connectionLineType, connectionLineStyle: connectionLineStyle, selectionKeyCode: selectionKeyCode, onElementsRemove: onElementsRemove, deleteKeyCode: deleteKeyCode, elements: elements, onConnect: onConnect, backgroundColor: backgroundColor, backgroundGap: backgroundGap, showBackground: showBackground, backgroundType: backgroundType }),
|
React__default.createElement(GraphView, { onLoad: onLoad, onMove: onMove, onElementClick: onElementClick, onNodeDragStop: onNodeDragStop, nodeTypes: nodeTypesParsed, edgeTypes: edgeTypesParsed, connectionLineType: connectionLineType, connectionLineStyle: connectionLineStyle, selectionKeyCode: selectionKeyCode, onElementsRemove: onElementsRemove, deleteKeyCode: deleteKeyCode, elements: elements, onConnect: onConnect, backgroundColor: backgroundColor, backgroundGap: backgroundGap, showBackground: showBackground, backgroundType: backgroundType, snapToGrid: snapToGrid, snapGrid: snapGrid }),
|
||||||
children)));
|
children)));
|
||||||
};
|
};
|
||||||
ReactFlow.displayName = 'ReactFlow';
|
ReactFlow.displayName = 'ReactFlow';
|
||||||
@@ -8871,12 +8994,12 @@ ReactFlow.defaultProps = {
|
|||||||
nodeTypes: {
|
nodeTypes: {
|
||||||
input: InputNode,
|
input: InputNode,
|
||||||
default: DefaultNode,
|
default: DefaultNode,
|
||||||
output: OutputNode
|
output: OutputNode,
|
||||||
},
|
},
|
||||||
edgeTypes: {
|
edgeTypes: {
|
||||||
default: BezierEdge,
|
default: BezierEdge,
|
||||||
straight: StraightEdge,
|
straight: StraightEdge,
|
||||||
step: StepEdge
|
step: StepEdge,
|
||||||
},
|
},
|
||||||
connectionLineType: 'bezier',
|
connectionLineType: 'bezier',
|
||||||
connectionLineStyle: {},
|
connectionLineStyle: {},
|
||||||
@@ -8885,7 +9008,9 @@ ReactFlow.defaultProps = {
|
|||||||
backgroundColor: '#eee',
|
backgroundColor: '#eee',
|
||||||
backgroundGap: 24,
|
backgroundGap: 24,
|
||||||
showBackground: true,
|
showBackground: true,
|
||||||
backgroundType: GridType.Dots
|
backgroundType: GridType.Dots,
|
||||||
|
snapToGrid: false,
|
||||||
|
snapGrid: [16, 16],
|
||||||
};
|
};
|
||||||
|
|
||||||
var baseStyle = {
|
var baseStyle = {
|
||||||
@@ -8893,7 +9018,7 @@ var baseStyle = {
|
|||||||
zIndex: 5,
|
zIndex: 5,
|
||||||
bottom: 10,
|
bottom: 10,
|
||||||
right: 10,
|
right: 10,
|
||||||
width: 200
|
width: 200,
|
||||||
};
|
};
|
||||||
var index = (function (_a) {
|
var index = (function (_a) {
|
||||||
var _b = _a.style, style = _b === void 0 ? {} : _b, className = _a.className, _c = _a.bgColor, bgColor = _c === void 0 ? '#f8f8f8' : _c, _d = _a.nodeColor, nodeColor = _d === void 0 ? '#ddd' : _d;
|
var _b = _a.style, style = _b === void 0 ? {} : _b, className = _a.className, _c = _a.bgColor, bgColor = _c === void 0 ? '#f8f8f8' : _c, _d = _a.nodeColor, nodeColor = _d === void 0 ? '#ddd' : _d;
|
||||||
@@ -8910,23 +9035,29 @@ var index = (function (_a) {
|
|||||||
var height = (state.height / (state.width || 1)) * width;
|
var height = (state.height / (state.width || 1)) * width;
|
||||||
var bbox = { x: 0, y: 0, width: state.width, height: state.height };
|
var bbox = { x: 0, y: 0, width: state.width, height: state.height };
|
||||||
var scaleFactor = width / state.width;
|
var scaleFactor = width / state.width;
|
||||||
var nodeColorFunc = (nodeColor instanceof Function ? nodeColor : function () { return nodeColor; });
|
var nodeColorFunc = (nodeColor instanceof Function
|
||||||
|
? nodeColor
|
||||||
|
: function () { return nodeColor; });
|
||||||
React.useEffect(function () {
|
React.useEffect(function () {
|
||||||
if (canvasNode && canvasNode.current) {
|
if (!canvasNode || !canvasNode.current) {
|
||||||
var ctx_1 = canvasNode.current.getContext('2d');
|
return;
|
||||||
var nodesInside = getNodesInside(state.nodes, bbox, state.transform, true);
|
|
||||||
ctx_1.fillStyle = bgColor;
|
|
||||||
ctx_1.fillRect(0, 0, width, height);
|
|
||||||
nodesInside.forEach(function (n) {
|
|
||||||
var pos = n.__rg.position;
|
|
||||||
var transformX = state.transform[0];
|
|
||||||
var transformY = state.transform[1];
|
|
||||||
var x = (pos.x * state.transform[2]) + transformX;
|
|
||||||
var y = (pos.y * state.transform[2]) + transformY;
|
|
||||||
ctx_1.fillStyle = nodeColorFunc(n);
|
|
||||||
ctx_1.fillRect((x * scaleFactor), (y * scaleFactor), n.__rg.width * scaleFactor * state.transform[2], n.__rg.height * scaleFactor * state.transform[2]);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
var ctx = canvasNode.current.getContext('2d');
|
||||||
|
if (!ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var nodesInside = getNodesInside(state.nodes, bbox, state.transform, true);
|
||||||
|
ctx.fillStyle = bgColor;
|
||||||
|
ctx.fillRect(0, 0, width, height);
|
||||||
|
nodesInside.forEach(function (n) {
|
||||||
|
var pos = n.__rg.position;
|
||||||
|
var transformX = state.transform[0];
|
||||||
|
var transformY = state.transform[1];
|
||||||
|
var x = pos.x * state.transform[2] + transformX;
|
||||||
|
var y = pos.y * state.transform[2] + transformY;
|
||||||
|
ctx.fillStyle = nodeColorFunc(n);
|
||||||
|
ctx.fillRect(x * scaleFactor, y * scaleFactor, n.__rg.width * scaleFactor * state.transform[2], n.__rg.height * scaleFactor * state.transform[2]);
|
||||||
|
});
|
||||||
}, [canvasNode.current, nodePositions, state.transform, height]);
|
}, [canvasNode.current, nodePositions, state.transform, height]);
|
||||||
return (React__default.createElement("canvas", { style: __assign(__assign(__assign({}, baseStyle), style), { height: height }), width: width, height: height, className: mapClasses, ref: canvasNode }));
|
return (React__default.createElement("canvas", { style: __assign(__assign(__assign({}, baseStyle), style), { height: height }), width: width, height: height, className: mapClasses, ref: canvasNode }));
|
||||||
});
|
});
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+10
@@ -0,0 +1,10 @@
|
|||||||
|
import React, { HTMLAttributes } from 'react';
|
||||||
|
import { GridType } from '../../types';
|
||||||
|
interface GridProps extends HTMLAttributes<SVGElement> {
|
||||||
|
backgroundType?: GridType;
|
||||||
|
gap?: number;
|
||||||
|
color?: string;
|
||||||
|
size?: number;
|
||||||
|
}
|
||||||
|
declare const Grid: React.MemoExoticComponent<({ gap, color, size, style, className, backgroundType, }: GridProps) => JSX.Element>;
|
||||||
|
export default Grid;
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
import { SVGAttributes } from 'react';
|
||||||
|
import { ElementId, Node, Transform } from '../../types';
|
||||||
|
interface ConnectionLineProps {
|
||||||
|
connectionSourceId: ElementId;
|
||||||
|
connectionPositionX: number;
|
||||||
|
connectionPositionY: number;
|
||||||
|
connectionLineType?: string | null;
|
||||||
|
nodes: Node[];
|
||||||
|
transform: Transform;
|
||||||
|
connectionLineStyle?: SVGAttributes<{}>;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
declare const _default: ({ connectionSourceId, connectionLineStyle, connectionPositionX, connectionPositionY, connectionLineType, nodes, className, transform, }: ConnectionLineProps) => JSX.Element | null;
|
||||||
|
export default _default;
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { EdgeBezierProps } from '../../types';
|
||||||
|
declare const _default: React.MemoExoticComponent<({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, style, }: EdgeBezierProps) => JSX.Element>;
|
||||||
|
export default _default;
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { EdgeProps } from '../../types';
|
||||||
|
declare const _default: React.MemoExoticComponent<({ sourceX, sourceY, targetX, targetY, style }: EdgeProps) => JSX.Element>;
|
||||||
|
export default _default;
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { EdgeProps } from '../../types';
|
||||||
|
declare const _default: React.MemoExoticComponent<({ sourceX, sourceY, targetX, targetY, style }: EdgeProps) => JSX.Element>;
|
||||||
|
export default _default;
|
||||||
Vendored
+13
@@ -0,0 +1,13 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { ElementId, Edge, EdgeCompProps } from '../../types';
|
||||||
|
interface EdgeWrapperProps {
|
||||||
|
id: ElementId;
|
||||||
|
source: ElementId;
|
||||||
|
target: ElementId;
|
||||||
|
type: any;
|
||||||
|
onClick: (edge: Edge) => void;
|
||||||
|
animated: boolean;
|
||||||
|
selected: boolean;
|
||||||
|
}
|
||||||
|
declare const _default: (EdgeComponent: React.ComponentType<EdgeCompProps>) => React.MemoExoticComponent<({ id, source, target, type, animated, selected, onClick, ...rest }: EdgeWrapperProps) => JSX.Element>;
|
||||||
|
export default _default;
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { HandleType, ElementId, Position, XYPosition, OnConnectFunc, Connection } from '../../types';
|
||||||
|
declare type ValidConnectionFunc = (connection: Connection) => boolean;
|
||||||
|
declare type SetSourceIdFunc = (nodeId: ElementId | null) => void;
|
||||||
|
interface BaseHandleProps {
|
||||||
|
type: HandleType;
|
||||||
|
nodeId: ElementId;
|
||||||
|
onConnect: OnConnectFunc;
|
||||||
|
position: Position;
|
||||||
|
setSourceId: SetSourceIdFunc;
|
||||||
|
setPosition: (pos: XYPosition) => void;
|
||||||
|
isValidConnection: ValidConnectionFunc;
|
||||||
|
id?: ElementId | boolean;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
declare const BaseHandle: React.MemoExoticComponent<({ type, nodeId, onConnect, position, setSourceId, setPosition, className, id, isValidConnection, ...rest }: BaseHandleProps) => JSX.Element>;
|
||||||
|
export default BaseHandle;
|
||||||
Vendored
+10
@@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { HandleType, Position, OnConnectFunc } from '../../types';
|
||||||
|
interface HandleProps {
|
||||||
|
type: HandleType;
|
||||||
|
position: Position;
|
||||||
|
onConnect?: OnConnectFunc;
|
||||||
|
isValidConnection?: () => boolean;
|
||||||
|
}
|
||||||
|
declare const Handle: React.MemoExoticComponent<({ onConnect, type, position, isValidConnection, ...rest }: HandleProps) => JSX.Element>;
|
||||||
|
export default Handle;
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
/// <reference types="react" />
|
||||||
|
import { NodeProps } from '../../types';
|
||||||
|
declare const _default: ({ data, style }: NodeProps) => JSX.Element;
|
||||||
|
export default _default;
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
/// <reference types="react" />
|
||||||
|
import { NodeProps } from '../../types';
|
||||||
|
declare const _default: ({ data, style }: NodeProps) => JSX.Element;
|
||||||
|
export default _default;
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
/// <reference types="react" />
|
||||||
|
import { NodeProps } from '../../types';
|
||||||
|
declare const _default: ({ data, style }: NodeProps) => JSX.Element;
|
||||||
|
export default _default;
|
||||||
Vendored
+16
@@ -0,0 +1,16 @@
|
|||||||
|
import React, { CSSProperties } from 'react';
|
||||||
|
import { Node, Transform, ElementId, NodeComponentProps } from '../../types';
|
||||||
|
interface WrapNodeProps {
|
||||||
|
id: ElementId;
|
||||||
|
type: string;
|
||||||
|
data: any;
|
||||||
|
selected: boolean;
|
||||||
|
transform: Transform;
|
||||||
|
xPos: number;
|
||||||
|
yPos: number;
|
||||||
|
onClick: (node: Node) => void | undefined;
|
||||||
|
onNodeDragStop: (node: Node) => void;
|
||||||
|
style?: CSSProperties;
|
||||||
|
}
|
||||||
|
declare const _default: (NodeComponent: React.ComponentType<NodeComponentProps>) => React.MemoExoticComponent<({ id, type, data, transform, xPos, yPos, selected, onClick, onNodeDragStop, style, }: WrapNodeProps) => JSX.Element>;
|
||||||
|
export default _default;
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
import React from 'react';
|
||||||
|
declare const _default: React.MemoExoticComponent<() => JSX.Element>;
|
||||||
|
export default _default;
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
import React from 'react';
|
||||||
|
declare const _default: React.MemoExoticComponent<() => JSX.Element>;
|
||||||
|
export default _default;
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
import React, { SVGAttributes } from 'react';
|
||||||
|
interface EdgeRendererProps {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
edgeTypes: any;
|
||||||
|
connectionLineStyle?: SVGAttributes<{}>;
|
||||||
|
connectionLineType?: string;
|
||||||
|
onElementClick?: () => void;
|
||||||
|
}
|
||||||
|
declare const EdgeRenderer: React.MemoExoticComponent<({ width, height, connectionLineStyle, connectionLineType, ...rest }: EdgeRendererProps) => JSX.Element | null>;
|
||||||
|
export default EdgeRenderer;
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
import { EdgeTypesType } from '../../types';
|
||||||
|
export declare function createEdgeTypes(edgeTypes: EdgeTypesType): EdgeTypesType;
|
||||||
Vendored
+25
@@ -0,0 +1,25 @@
|
|||||||
|
import React, { SVGAttributes } from 'react';
|
||||||
|
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;
|
||||||
|
snapToGrid: boolean;
|
||||||
|
snapGrid: [number, number];
|
||||||
|
}
|
||||||
|
declare const GraphView: React.MemoExoticComponent<({ nodeTypes, edgeTypes, onMove, onLoad, onElementClick, onNodeDragStop, connectionLineType, connectionLineStyle, selectionKeyCode, onElementsRemove, deleteKeyCode, elements, showBackground, backgroundGap, backgroundColor, backgroundType, onConnect, snapToGrid, snapGrid, }: GraphViewProps) => JSX.Element>;
|
||||||
|
export default GraphView;
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { NodeTypesType } from '../../types';
|
||||||
|
interface NodeRendererProps {
|
||||||
|
nodeTypes: NodeTypesType;
|
||||||
|
onElementClick: () => void;
|
||||||
|
onNodeDragStop: () => void;
|
||||||
|
}
|
||||||
|
declare const NodeRenderer: React.MemoExoticComponent<(props: NodeRendererProps) => JSX.Element>;
|
||||||
|
export default NodeRenderer;
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
import { NodeTypesType } from '../../types';
|
||||||
|
export declare function createNodeTypes(nodeTypes: NodeTypesType): NodeTypesType;
|
||||||
Vendored
+57
@@ -0,0 +1,57 @@
|
|||||||
|
import React, { SVGAttributes, HTMLAttributes } from 'react';
|
||||||
|
import { Elements, NodeTypesType, EdgeTypesType, GridType, OnLoadFunc } from '../../types';
|
||||||
|
import '../../style.css';
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
declare const ReactFlow: {
|
||||||
|
({ style, onElementClick, elements, children, nodeTypes, edgeTypes, onLoad, onMove, onElementsRemove, onConnect, onNodeDragStop, connectionLineType, connectionLineStyle, deleteKeyCode, selectionKeyCode, showBackground, backgroundGap, backgroundType, backgroundColor, snapToGrid, snapGrid, }: ReactFlowProps): JSX.Element;
|
||||||
|
displayName: string;
|
||||||
|
defaultProps: {
|
||||||
|
onElementClick: () => void;
|
||||||
|
onElementsRemove: () => void;
|
||||||
|
onNodeDragStop: () => void;
|
||||||
|
onConnect: () => void;
|
||||||
|
onLoad: () => void;
|
||||||
|
onMove: () => void;
|
||||||
|
nodeTypes: {
|
||||||
|
input: ({ data, style }: import("../../types").NodeProps) => JSX.Element;
|
||||||
|
default: ({ data, style }: import("../../types").NodeProps) => JSX.Element;
|
||||||
|
output: ({ data, style }: import("../../types").NodeProps) => JSX.Element;
|
||||||
|
};
|
||||||
|
edgeTypes: {
|
||||||
|
default: React.MemoExoticComponent<({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, style, }: import("../../types").EdgeBezierProps) => JSX.Element>;
|
||||||
|
straight: React.MemoExoticComponent<({ sourceX, sourceY, targetX, targetY, style }: import("../../types").EdgeProps) => JSX.Element>;
|
||||||
|
step: React.MemoExoticComponent<({ sourceX, sourceY, targetX, targetY, style }: import("../../types").EdgeProps) => JSX.Element>;
|
||||||
|
};
|
||||||
|
connectionLineType: string;
|
||||||
|
connectionLineStyle: {};
|
||||||
|
deleteKeyCode: number;
|
||||||
|
selectionKeyCode: number;
|
||||||
|
backgroundColor: string;
|
||||||
|
backgroundGap: number;
|
||||||
|
showBackground: boolean;
|
||||||
|
backgroundType: GridType;
|
||||||
|
snapToGrid: boolean;
|
||||||
|
snapGrid: number[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export default ReactFlow;
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
/// <reference types="react" />
|
||||||
|
import { ElementId } from '../types';
|
||||||
|
declare type ContextProps = ElementId | null;
|
||||||
|
export declare const NodeIdContext: import("react").Context<ContextProps>;
|
||||||
|
export declare const Provider: import("react").ProviderExoticComponent<import("react").ProviderProps<ContextProps>>;
|
||||||
|
export declare const Consumer: import("react").ExoticComponent<import("react").ConsumerProps<ContextProps>>;
|
||||||
|
export default NodeIdContext;
|
||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
import { MutableRefObject } from 'react';
|
||||||
|
declare const _default: (zoomPane: MutableRefObject<Element | null>, onMove: () => void, shiftPressed: boolean) => void;
|
||||||
|
export default _default;
|
||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
import { Node, Edge } from '../types';
|
||||||
|
declare const useElementUpdater: (elements: (Node | Edge)[]) => void;
|
||||||
|
export default useElementUpdater;
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
import { Elements } from '../types';
|
||||||
|
interface HookParams {
|
||||||
|
deleteKeyCode: number;
|
||||||
|
onElementsRemove: (elements: Elements) => void;
|
||||||
|
}
|
||||||
|
declare const _default: ({ deleteKeyCode, onElementsRemove }: HookParams) => void;
|
||||||
|
export default _default;
|
||||||
Vendored
+2
@@ -0,0 +1,2 @@
|
|||||||
|
declare const _default: (keyCode: number) => boolean;
|
||||||
|
export default _default;
|
||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
import ReactFlow from './container/ReactFlow';
|
||||||
|
export default ReactFlow;
|
||||||
|
export { default as Handle } from './components/Handle';
|
||||||
|
export { MiniMap, Controls } from './plugins';
|
||||||
|
export { isNode, isEdge, removeElements, addEdge, getOutgoers, } from './utils/graph';
|
||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
import React from 'react';
|
||||||
|
interface ControlProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||||
|
}
|
||||||
|
declare const _default: ({ style, className }: ControlProps) => JSX.Element;
|
||||||
|
export default _default;
|
||||||
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Node } from '../../types';
|
||||||
|
declare type StringFunc = (node: Node) => string;
|
||||||
|
interface MiniMapProps extends React.HTMLAttributes<HTMLCanvasElement> {
|
||||||
|
bgColor?: string;
|
||||||
|
nodeColor?: string | StringFunc;
|
||||||
|
}
|
||||||
|
declare const _default: ({ style, className, bgColor, nodeColor, }: MiniMapProps) => JSX.Element;
|
||||||
|
export default _default;
|
||||||
Vendored
+2
@@ -0,0 +1,2 @@
|
|||||||
|
export { default as MiniMap } from './MiniMap';
|
||||||
|
export { default as Controls } from './Controls';
|
||||||
Vendored
+69
@@ -0,0 +1,69 @@
|
|||||||
|
import { StoreModel } from './index';
|
||||||
|
export declare const useStoreActions: <Result>(mapActions: (actions: import("easy-peasy").ActionMapper<{
|
||||||
|
selectedNodesBbox: import("../types").Rect;
|
||||||
|
d3Zoom: import("d3-zoom").ZoomBehavior<Element, unknown> | null;
|
||||||
|
d3Selection: import("d3-selection").Selection<Element, unknown, null, undefined> | null;
|
||||||
|
selection: import("../types").SelectionRect | null;
|
||||||
|
connectionPosition: import("../types").XYPosition;
|
||||||
|
onConnect: import("../types").OnConnectFunc;
|
||||||
|
setOnConnect: import("easy-peasy").Action<StoreModel, import("../types").OnConnectFunc>;
|
||||||
|
setNodes: import("easy-peasy").Action<StoreModel, import("../types").Node[]>;
|
||||||
|
setEdges: import("easy-peasy").Action<StoreModel, import("../types").Edge[]>;
|
||||||
|
updateNodeData: import("easy-peasy").Action<StoreModel, {
|
||||||
|
id: string;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
handleBounds: {
|
||||||
|
source: import("../types").HandleElement[] | null;
|
||||||
|
target: import("../types").HandleElement[] | null;
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
updateNodePos: import("easy-peasy").Action<StoreModel, {
|
||||||
|
id: string;
|
||||||
|
pos: import("../types").XYPosition;
|
||||||
|
}>;
|
||||||
|
setSelection: import("easy-peasy").Action<StoreModel, boolean>;
|
||||||
|
setNodesSelection: import("easy-peasy").Action<StoreModel, {
|
||||||
|
isActive: boolean;
|
||||||
|
selection?: import("../types").SelectionRect | undefined;
|
||||||
|
}>;
|
||||||
|
setSelectedElements: import("easy-peasy").Action<StoreModel, import("../types").Node | import("../types").Edge | (import("../types").Node | import("../types").Edge)[]>;
|
||||||
|
updateSelection: import("easy-peasy").Action<StoreModel, import("../types").SelectionRect>;
|
||||||
|
updateTransform: import("easy-peasy").Action<StoreModel, {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
k: number;
|
||||||
|
}>;
|
||||||
|
updateSize: import("easy-peasy").Action<StoreModel, import("../types").Dimensions>;
|
||||||
|
initD3: import("easy-peasy").Action<StoreModel, {
|
||||||
|
zoom: import("d3-zoom").ZoomBehavior<Element, unknown>;
|
||||||
|
selection: import("d3-selection").Selection<Element, unknown, null, undefined>;
|
||||||
|
}>;
|
||||||
|
setSnapGrid: import("easy-peasy").Action<StoreModel, {
|
||||||
|
snapToGrid: boolean;
|
||||||
|
snapGrid: [number, number];
|
||||||
|
}>;
|
||||||
|
setConnectionPosition: import("easy-peasy").Action<StoreModel, import("../types").XYPosition>;
|
||||||
|
setConnectionSourceId: import("easy-peasy").Action<StoreModel, string | null>;
|
||||||
|
}, "1">) => Result) => Result;
|
||||||
|
export declare const useStoreDispatch: () => import("easy-peasy").Dispatch<StoreModel, import("redux").Action<any>>;
|
||||||
|
export declare const useStoreState: <Result>(mapState: (state: import("easy-peasy").IntermediateStateMapper<{
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
transform: [number, number, number];
|
||||||
|
nodes: import("../types").Node[];
|
||||||
|
edges: import("../types").Edge[];
|
||||||
|
selectedElements: (import("../types").Node | import("../types").Edge)[];
|
||||||
|
selectedNodesBbox: import("../types").Rect;
|
||||||
|
d3Zoom: import("d3-zoom").ZoomBehavior<Element, unknown> | null;
|
||||||
|
d3Selection: import("d3-selection").Selection<Element, unknown, null, undefined> | null;
|
||||||
|
d3Initialised: boolean;
|
||||||
|
nodesSelectionActive: boolean;
|
||||||
|
selectionActive: boolean;
|
||||||
|
selection: import("../types").SelectionRect | null;
|
||||||
|
connectionSourceId: string | null;
|
||||||
|
connectionPosition: import("../types").XYPosition;
|
||||||
|
snapToGrid: boolean;
|
||||||
|
snapGrid: [number, number];
|
||||||
|
onConnect: import("../types").OnConnectFunc;
|
||||||
|
}, "1">) => Result, dependencies?: any[] | undefined) => Result;
|
||||||
Vendored
+149
@@ -0,0 +1,149 @@
|
|||||||
|
import { Action } from 'easy-peasy';
|
||||||
|
import { Selection as D3Selection, ZoomBehavior } from 'd3';
|
||||||
|
import { ElementId, Elements, Transform, Node, Edge, Rect, Dimensions, XYPosition, OnConnectFunc, SelectionRect, HandleElement } from '../types';
|
||||||
|
declare type TransformXYK = {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
k: number;
|
||||||
|
};
|
||||||
|
declare type NodePosUpdate = {
|
||||||
|
id: ElementId;
|
||||||
|
pos: XYPosition;
|
||||||
|
};
|
||||||
|
declare type NodeUpdate = {
|
||||||
|
id: ElementId;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
handleBounds: {
|
||||||
|
source: HandleElement[] | null;
|
||||||
|
target: HandleElement[] | null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
declare type SelectionUpdate = {
|
||||||
|
isActive: boolean;
|
||||||
|
selection?: SelectionRect;
|
||||||
|
};
|
||||||
|
declare type D3Init = {
|
||||||
|
zoom: ZoomBehavior<Element, unknown>;
|
||||||
|
selection: D3Selection<Element, unknown, null, undefined>;
|
||||||
|
};
|
||||||
|
declare type SetSnapGrid = {
|
||||||
|
snapToGrid: boolean;
|
||||||
|
snapGrid: [number, number];
|
||||||
|
};
|
||||||
|
export interface StoreModel {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
transform: Transform;
|
||||||
|
nodes: Node[];
|
||||||
|
edges: Edge[];
|
||||||
|
selectedElements: Elements;
|
||||||
|
selectedNodesBbox: Rect;
|
||||||
|
d3Zoom: ZoomBehavior<Element, unknown> | null;
|
||||||
|
d3Selection: D3Selection<Element, unknown, null, undefined> | null;
|
||||||
|
d3Initialised: boolean;
|
||||||
|
nodesSelectionActive: boolean;
|
||||||
|
selectionActive: boolean;
|
||||||
|
selection: SelectionRect | null;
|
||||||
|
connectionSourceId: ElementId | null;
|
||||||
|
connectionPosition: XYPosition;
|
||||||
|
snapToGrid: boolean;
|
||||||
|
snapGrid: [number, number];
|
||||||
|
onConnect: OnConnectFunc;
|
||||||
|
setOnConnect: Action<StoreModel, OnConnectFunc>;
|
||||||
|
setNodes: Action<StoreModel, Node[]>;
|
||||||
|
setEdges: Action<StoreModel, Edge[]>;
|
||||||
|
updateNodeData: Action<StoreModel, NodeUpdate>;
|
||||||
|
updateNodePos: Action<StoreModel, NodePosUpdate>;
|
||||||
|
setSelection: Action<StoreModel, boolean>;
|
||||||
|
setNodesSelection: Action<StoreModel, SelectionUpdate>;
|
||||||
|
setSelectedElements: Action<StoreModel, Elements | Node | Edge>;
|
||||||
|
updateSelection: Action<StoreModel, SelectionRect>;
|
||||||
|
updateTransform: Action<StoreModel, TransformXYK>;
|
||||||
|
updateSize: Action<StoreModel, Dimensions>;
|
||||||
|
initD3: Action<StoreModel, D3Init>;
|
||||||
|
setSnapGrid: Action<StoreModel, SetSnapGrid>;
|
||||||
|
setConnectionPosition: Action<StoreModel, XYPosition>;
|
||||||
|
setConnectionSourceId: Action<StoreModel, ElementId | null>;
|
||||||
|
}
|
||||||
|
declare const store: {
|
||||||
|
getState: () => import("easy-peasy").IntermediateStateMapper<{
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
transform: [number, number, number];
|
||||||
|
nodes: Node[];
|
||||||
|
edges: Edge[];
|
||||||
|
selectedElements: (Node | Edge)[];
|
||||||
|
selectedNodesBbox: Rect;
|
||||||
|
d3Zoom: ZoomBehavior<Element, unknown> | null;
|
||||||
|
d3Selection: D3Selection<Element, unknown, null, undefined> | null;
|
||||||
|
d3Initialised: boolean;
|
||||||
|
nodesSelectionActive: boolean;
|
||||||
|
selectionActive: boolean;
|
||||||
|
selection: SelectionRect | null;
|
||||||
|
connectionSourceId: string | null;
|
||||||
|
connectionPosition: XYPosition;
|
||||||
|
snapToGrid: boolean;
|
||||||
|
snapGrid: [number, number];
|
||||||
|
onConnect: OnConnectFunc;
|
||||||
|
}, "1">;
|
||||||
|
subscribe: (listener: () => void) => import("redux").Unsubscribe;
|
||||||
|
replaceReducer: (nextReducer: import("redux").Reducer<import("easy-peasy").IntermediateStateMapper<{
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
transform: [number, number, number];
|
||||||
|
nodes: Node[];
|
||||||
|
edges: Edge[];
|
||||||
|
selectedElements: (Node | Edge)[];
|
||||||
|
selectedNodesBbox: Rect;
|
||||||
|
d3Zoom: ZoomBehavior<Element, unknown> | null;
|
||||||
|
d3Selection: D3Selection<Element, unknown, null, undefined> | null;
|
||||||
|
d3Initialised: boolean;
|
||||||
|
nodesSelectionActive: boolean;
|
||||||
|
selectionActive: boolean;
|
||||||
|
selection: SelectionRect | null;
|
||||||
|
connectionSourceId: string | null;
|
||||||
|
connectionPosition: XYPosition;
|
||||||
|
snapToGrid: boolean;
|
||||||
|
snapGrid: [number, number];
|
||||||
|
onConnect: OnConnectFunc;
|
||||||
|
}, "1">, import("redux").AnyAction>) => void;
|
||||||
|
dispatch: import("easy-peasy").Dispatch<StoreModel, import("redux").Action<any>>;
|
||||||
|
addModel: <ModelSlice extends object>(key: string, modelSlice: ModelSlice) => void;
|
||||||
|
clearMockedActions: () => void;
|
||||||
|
getActions: () => import("easy-peasy").ActionMapper<{
|
||||||
|
selectedNodesBbox: Rect;
|
||||||
|
d3Zoom: ZoomBehavior<Element, unknown> | null;
|
||||||
|
d3Selection: D3Selection<Element, unknown, null, undefined> | null;
|
||||||
|
selection: SelectionRect | null;
|
||||||
|
connectionPosition: XYPosition;
|
||||||
|
onConnect: OnConnectFunc;
|
||||||
|
setOnConnect: Action<StoreModel, OnConnectFunc>;
|
||||||
|
setNodes: Action<StoreModel, Node[]>;
|
||||||
|
setEdges: Action<StoreModel, Edge[]>;
|
||||||
|
updateNodeData: Action<StoreModel, NodeUpdate>;
|
||||||
|
updateNodePos: Action<StoreModel, NodePosUpdate>;
|
||||||
|
setSelection: Action<StoreModel, boolean>;
|
||||||
|
setNodesSelection: Action<StoreModel, SelectionUpdate>;
|
||||||
|
setSelectedElements: Action<StoreModel, Node | Edge | (Node | Edge)[]>;
|
||||||
|
updateSelection: Action<StoreModel, SelectionRect>;
|
||||||
|
updateTransform: Action<StoreModel, TransformXYK>;
|
||||||
|
updateSize: Action<StoreModel, Dimensions>;
|
||||||
|
initD3: Action<StoreModel, D3Init>;
|
||||||
|
setSnapGrid: Action<StoreModel, SetSnapGrid>;
|
||||||
|
setConnectionPosition: Action<StoreModel, XYPosition>;
|
||||||
|
setConnectionSourceId: Action<StoreModel, string | null>;
|
||||||
|
}, "1">;
|
||||||
|
getListeners: () => import("easy-peasy").ListenerMapper<{
|
||||||
|
selectedNodesBbox: Rect;
|
||||||
|
d3Zoom: ZoomBehavior<Element, unknown> | null;
|
||||||
|
d3Selection: D3Selection<Element, unknown, null, undefined> | null;
|
||||||
|
selection: SelectionRect | null;
|
||||||
|
connectionPosition: XYPosition;
|
||||||
|
onConnect: OnConnectFunc;
|
||||||
|
}, "1">;
|
||||||
|
getMockedActions: () => import("easy-peasy").MockedAction[];
|
||||||
|
reconfigure: <NewStoreModel extends object>(model: NewStoreModel) => void;
|
||||||
|
removeModel: (key: string) => void;
|
||||||
|
};
|
||||||
|
export default store;
|
||||||
Vendored
+110
@@ -0,0 +1,110 @@
|
|||||||
|
import { CSSProperties, SVGAttributes } from 'react';
|
||||||
|
export declare type ElementId = string;
|
||||||
|
export declare type Elements = Array<Node | Edge>;
|
||||||
|
export declare type Transform = [number, number, number];
|
||||||
|
export declare type Position = 'left' | 'top' | 'right' | 'bottom';
|
||||||
|
export declare type XYPosition = {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
};
|
||||||
|
export declare enum GridType {
|
||||||
|
Lines = "lines",
|
||||||
|
Dots = "dots"
|
||||||
|
}
|
||||||
|
export declare type HandleType = 'source' | 'target';
|
||||||
|
export declare type NodeTypesType = {
|
||||||
|
[key: string]: React.ReactNode;
|
||||||
|
};
|
||||||
|
export declare type EdgeTypesType = NodeTypesType;
|
||||||
|
export interface Dimensions {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
export interface Rect extends Dimensions {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
|
export interface SelectionRect extends Rect {
|
||||||
|
startX: number;
|
||||||
|
startY: number;
|
||||||
|
draw: boolean;
|
||||||
|
}
|
||||||
|
export interface Node {
|
||||||
|
id: ElementId;
|
||||||
|
position: XYPosition;
|
||||||
|
type?: string;
|
||||||
|
__rg?: any;
|
||||||
|
data?: any;
|
||||||
|
style?: CSSProperties;
|
||||||
|
}
|
||||||
|
export interface Edge {
|
||||||
|
id: ElementId;
|
||||||
|
type?: string;
|
||||||
|
source: ElementId;
|
||||||
|
target: ElementId;
|
||||||
|
style?: SVGAttributes<{}>;
|
||||||
|
animated?: boolean;
|
||||||
|
}
|
||||||
|
export interface EdgeProps {
|
||||||
|
sourceX: number;
|
||||||
|
sourceY: number;
|
||||||
|
targetX: number;
|
||||||
|
targetY: number;
|
||||||
|
style?: SVGAttributes<{}>;
|
||||||
|
}
|
||||||
|
export interface EdgeBezierProps extends EdgeProps {
|
||||||
|
sourcePosition: Position;
|
||||||
|
targetPosition: Position;
|
||||||
|
}
|
||||||
|
export interface NodeProps {
|
||||||
|
id: ElementId;
|
||||||
|
type: string;
|
||||||
|
data: any;
|
||||||
|
selected: boolean;
|
||||||
|
style?: CSSProperties;
|
||||||
|
}
|
||||||
|
export interface NodeComponentProps {
|
||||||
|
id: ElementId;
|
||||||
|
type: string;
|
||||||
|
data: any;
|
||||||
|
selected?: boolean;
|
||||||
|
transform?: Transform;
|
||||||
|
xPos?: number;
|
||||||
|
yPos?: number;
|
||||||
|
onClick?: (node: Node) => void | undefined;
|
||||||
|
onNodeDragStop?: () => any;
|
||||||
|
style?: CSSProperties;
|
||||||
|
}
|
||||||
|
export declare type FitViewParams = {
|
||||||
|
padding: number;
|
||||||
|
};
|
||||||
|
export declare type FitViewFunc = (fitViewOptions: FitViewParams) => void;
|
||||||
|
declare type OnLoadParams = {
|
||||||
|
zoomIn: () => void;
|
||||||
|
zoomOut: () => void;
|
||||||
|
fitView: FitViewFunc;
|
||||||
|
};
|
||||||
|
export declare type OnLoadFunc = (params: OnLoadParams) => void;
|
||||||
|
export declare type Connection = {
|
||||||
|
source: ElementId | null;
|
||||||
|
target: ElementId | null;
|
||||||
|
};
|
||||||
|
export declare type OnConnectFunc = (params: Connection) => void;
|
||||||
|
export interface HandleElement {
|
||||||
|
id?: ElementId | null;
|
||||||
|
position: Position;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
export interface EdgeCompProps {
|
||||||
|
id: ElementId;
|
||||||
|
source: ElementId;
|
||||||
|
target: ElementId;
|
||||||
|
type: any;
|
||||||
|
onClick?: (edge: Edge) => void;
|
||||||
|
animated?: boolean;
|
||||||
|
selected?: boolean;
|
||||||
|
}
|
||||||
|
export {};
|
||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
import { Node, Edge, XYPosition, Rect, FitViewParams } from '../types';
|
||||||
|
export declare const isEdge: (element: Node | Edge) => boolean;
|
||||||
|
export declare const isNode: (element: Node | Edge) => boolean;
|
||||||
|
export declare const getOutgoers: (node: Node, elements: (Node | Edge)[]) => (Node | Edge)[];
|
||||||
|
export declare const removeElements: (elementsToRemove: (Node | Edge)[], elements: (Node | Edge)[]) => (Node | Edge)[];
|
||||||
|
export declare const addEdge: (edgeParams: Edge, elements: (Node | Edge)[]) => (Node | Edge)[];
|
||||||
|
export declare const parseElement: (element: Node | Edge, transform?: [number, number, number]) => Node | Edge;
|
||||||
|
export declare const getBoundingBox: (nodes: Node[]) => Rect;
|
||||||
|
export declare const graphPosToZoomedPos: (pos: XYPosition, transform: [number, number, number]) => XYPosition;
|
||||||
|
export declare const getNodesInside: (nodes: Node[], bbox: Rect, transform?: [number, number, number], partially?: boolean) => Node[];
|
||||||
|
export declare const getConnectedEdges: (nodes: Node[], edges: Edge[]) => Edge[];
|
||||||
|
export declare const fitView: ({ padding }?: FitViewParams) => void;
|
||||||
|
export declare const zoomIn: () => void;
|
||||||
|
export declare const zoomOut: () => void;
|
||||||
Vendored
+6
@@ -0,0 +1,6 @@
|
|||||||
|
import { MouseEvent as ReactMouseEvent } from 'react';
|
||||||
|
export declare const isInputDOMNode: (e: MouseEvent | ReactMouseEvent<Element, MouseEvent> | ReactMouseEvent<HTMLElement | SVGElement, MouseEvent> | import("react").TouchEvent<HTMLElement | SVGElement> | TouchEvent | KeyboardEvent) => boolean;
|
||||||
|
export declare const getDimensions: (node: HTMLDivElement) => {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
};
|
||||||
@@ -14,7 +14,7 @@ class App extends PureComponent {
|
|||||||
const onChange = (option, d) => {
|
const onChange = (option, d) => {
|
||||||
this.setState(prevState => (
|
this.setState(prevState => (
|
||||||
{elements: prevState.elements.map(e => {
|
{elements: prevState.elements.map(e => {
|
||||||
if (isEdge(e) || e.id !== '6') {
|
if (isEdge(e) || e.id !== '6') {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ class App extends PureComponent {
|
|||||||
const onChangeInput = (input, d) => {
|
const onChangeInput = (input, d) => {
|
||||||
this.setState(prevState => (
|
this.setState(prevState => (
|
||||||
{elements: prevState.elements.map(e => {
|
{elements: prevState.elements.map(e => {
|
||||||
if (isEdge(e) || e.id !== '8') {
|
if (isEdge(e) || e.id !== '8') {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ class App extends PureComponent {
|
|||||||
...e,
|
...e,
|
||||||
data: {
|
data: {
|
||||||
...e.data,
|
...e.data,
|
||||||
input: input || 'write something'
|
input: input || 'write something'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
@@ -145,6 +145,8 @@ class App extends PureComponent {
|
|||||||
connectionLineType="bezier"
|
connectionLineType="bezier"
|
||||||
backgroundColor="#888"
|
backgroundColor="#888"
|
||||||
backgroundGap={16}
|
backgroundGap={16}
|
||||||
|
snapToGrid={true}
|
||||||
|
snapGrid={[16, 16]}
|
||||||
>
|
>
|
||||||
<MiniMap
|
<MiniMap
|
||||||
style={{ position: 'absolute', right: 10, bottom: 10 }}
|
style={{ position: 'absolute', right: 10, bottom: 10 }}
|
||||||
|
|||||||
Generated
+17
-30
@@ -3814,8 +3814,7 @@
|
|||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"aproba": {
|
"aproba": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
@@ -3836,14 +3835,12 @@
|
|||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
@@ -3858,20 +3855,17 @@
|
|||||||
"code-point-at": {
|
"code-point-at": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"console-control-strings": {
|
"console-control-strings": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"core-util-is": {
|
"core-util-is": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
@@ -3988,8 +3982,7 @@
|
|||||||
"inherits": {
|
"inherits": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"ini": {
|
"ini": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
@@ -4001,7 +3994,6 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"number-is-nan": "^1.0.0"
|
"number-is-nan": "^1.0.0"
|
||||||
}
|
}
|
||||||
@@ -4016,7 +4008,6 @@
|
|||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
@@ -4024,14 +4015,12 @@
|
|||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"minipass": {
|
"minipass": {
|
||||||
"version": "2.3.5",
|
"version": "2.3.5",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"safe-buffer": "^5.1.2",
|
"safe-buffer": "^5.1.2",
|
||||||
"yallist": "^3.0.0"
|
"yallist": "^3.0.0"
|
||||||
@@ -4050,7 +4039,6 @@
|
|||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "0.0.8"
|
"minimist": "0.0.8"
|
||||||
}
|
}
|
||||||
@@ -4131,8 +4119,7 @@
|
|||||||
"number-is-nan": {
|
"number-is-nan": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"object-assign": {
|
"object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
@@ -4144,7 +4131,6 @@
|
|||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
@@ -4230,8 +4216,7 @@
|
|||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"safer-buffer": {
|
"safer-buffer": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
@@ -4267,7 +4252,6 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"code-point-at": "^1.0.0",
|
"code-point-at": "^1.0.0",
|
||||||
"is-fullwidth-code-point": "^1.0.0",
|
"is-fullwidth-code-point": "^1.0.0",
|
||||||
@@ -4287,7 +4271,6 @@
|
|||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-regex": "^2.0.0"
|
"ansi-regex": "^2.0.0"
|
||||||
}
|
}
|
||||||
@@ -4331,14 +4314,12 @@
|
|||||||
"wrappy": {
|
"wrappy": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"yallist": {
|
"yallist": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -6704,6 +6685,12 @@
|
|||||||
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
|
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"prettier": {
|
||||||
|
"version": "1.18.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz",
|
||||||
|
"integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"pretty-bytes": {
|
"pretty-bytes": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz",
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
"cypress": "^3.4.1",
|
"cypress": "^3.4.1",
|
||||||
"husky": "^3.0.9",
|
"husky": "^3.0.9",
|
||||||
"postcss-nested": "^4.1.2",
|
"postcss-nested": "^4.1.2",
|
||||||
|
"prettier": "1.18.2",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"react": "^16.10.2",
|
"react": "^16.10.2",
|
||||||
"rollup": "^1.25.1",
|
"rollup": "^1.25.1",
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
module.exports = {
|
||||||
|
trailingComma: 'es5',
|
||||||
|
singleQuote: true
|
||||||
|
};
|
||||||
@@ -1,30 +1,40 @@
|
|||||||
import React, {memo} from 'react';
|
import React, { memo, HTMLAttributes, CSSProperties } from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
|
||||||
import { useStoreState } from '../../store/hooks';
|
import { useStoreState } from '../../store/hooks';
|
||||||
import { GridType } from '../../types';
|
import { GridType } from '../../types';
|
||||||
|
|
||||||
interface GridProps {
|
interface GridProps extends HTMLAttributes<SVGElement> {
|
||||||
backgroundType?: GridType;
|
backgroundType?: GridType;
|
||||||
gap?: number;
|
gap?: number;
|
||||||
color?: string;
|
color?: string;
|
||||||
size?: number;
|
size?: number;
|
||||||
style?: React.CSSProperties;
|
}
|
||||||
className?: string | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const baseStyles: React.CSSProperties = {
|
const baseStyles: CSSProperties = {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const createGridLines = (width: number, height: number, xOffset: number, yOffset: number, gap: number): string => {
|
const createGridLines = (
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
xOffset: number,
|
||||||
|
yOffset: number,
|
||||||
|
gap: number
|
||||||
|
): string => {
|
||||||
const lineCountX = Math.ceil(width / gap) + 1;
|
const lineCountX = Math.ceil(width / gap) + 1;
|
||||||
const lineCountY = Math.ceil(height / gap) + 1;
|
const lineCountY = Math.ceil(height / gap) + 1;
|
||||||
|
|
||||||
const xValues = Array.from({length: lineCountX}, (_, i) => `M${i * gap + xOffset} 0 V${height}`);
|
const xValues = Array.from(
|
||||||
const yValues = Array.from({length: lineCountY}, (_, i) => `M0 ${i * gap + yOffset} H${width}`);
|
{ length: lineCountX },
|
||||||
|
(_, i) => `M${i * gap + xOffset} 0 V${height}`
|
||||||
|
);
|
||||||
|
const yValues = Array.from(
|
||||||
|
{ length: lineCountY },
|
||||||
|
(_, i) => `M0 ${i * gap + yOffset} H${width}`
|
||||||
|
);
|
||||||
|
|
||||||
return [...xValues, ...yValues].join(' ');
|
return [...xValues, ...yValues].join(' ');
|
||||||
};
|
};
|
||||||
@@ -40,11 +50,12 @@ const createGridDots = (
|
|||||||
const lineCountX = Math.ceil(width / gap) + 1;
|
const lineCountX = Math.ceil(width / gap) + 1;
|
||||||
const lineCountY = Math.ceil(height / gap) + 1;
|
const lineCountY = Math.ceil(height / gap) + 1;
|
||||||
|
|
||||||
const values = Array.from({length: lineCountX}, (_, col) => {
|
const values = Array.from({ length: lineCountX }, (_, col) => {
|
||||||
const x = col * gap + xOffset;
|
const x = col * gap + xOffset;
|
||||||
return Array.from({length: lineCountY}, (_, row) => {
|
return Array.from({ length: lineCountY }, (_, row) => {
|
||||||
const y = row * gap + yOffset;
|
const y = row * gap + yOffset;
|
||||||
return `M${x} ${y - size} l${size} ${size} l${-size} ${size} l${-size} ${-size}z`;
|
return `M${x} ${y -
|
||||||
|
size} l${size} ${size} l${-size} ${size} l${-size} ${-size}z`;
|
||||||
}).join(' ');
|
}).join(' ');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -52,7 +63,14 @@ const createGridDots = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Grid = memo(
|
const Grid = memo(
|
||||||
({gap = 24, color = '#aaa', size = 0.5, style = {}, className = null, backgroundType = GridType.Dots}: GridProps) => {
|
({
|
||||||
|
gap = 24,
|
||||||
|
color = '#aaa',
|
||||||
|
size = 0.5,
|
||||||
|
style = {},
|
||||||
|
className = '',
|
||||||
|
backgroundType = GridType.Dots,
|
||||||
|
}: GridProps) => {
|
||||||
const {
|
const {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
@@ -73,7 +91,12 @@ const Grid = memo(
|
|||||||
const stroke = isLines ? color : 'none';
|
const stroke = isLines ? color : 'none';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<svg width={width} height={height} style={{...baseStyles, ...style}} className={gridClasses}>
|
<svg
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
style={{ ...baseStyles, ...style }}
|
||||||
|
className={gridClasses}
|
||||||
|
>
|
||||||
<path fill={fill} stroke={stroke} strokeWidth={size} d={path} />
|
<path fill={fill} stroke={stroke} strokeWidth={size} d={path} />
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,16 +7,22 @@ interface ConnectionLineProps {
|
|||||||
connectionSourceId: ElementId;
|
connectionSourceId: ElementId;
|
||||||
connectionPositionX: number;
|
connectionPositionX: number;
|
||||||
connectionPositionY: number;
|
connectionPositionY: number;
|
||||||
connectionLineType?: string | null;
|
connectionLineType?: string | null;
|
||||||
nodes: Node[];
|
nodes: Node[];
|
||||||
transform: Transform;
|
transform: Transform;
|
||||||
connectionLineStyle?: SVGAttributes<{}>;
|
connectionLineStyle?: SVGAttributes<{}>;
|
||||||
className?: string;
|
className?: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
connectionSourceId, connectionLineStyle = {}, connectionPositionX, connectionPositionY,
|
connectionSourceId,
|
||||||
connectionLineType, nodes = [], className, transform
|
connectionLineStyle = {},
|
||||||
|
connectionPositionX,
|
||||||
|
connectionPositionY,
|
||||||
|
connectionLineType,
|
||||||
|
nodes = [],
|
||||||
|
className,
|
||||||
|
transform,
|
||||||
}: ConnectionLineProps) => {
|
}: ConnectionLineProps) => {
|
||||||
const [sourceNode, setSourceNode] = useState<Node | null>(null);
|
const [sourceNode, setSourceNode] = useState<Node | null>(null);
|
||||||
const hasHandleId = connectionSourceId.includes('__');
|
const hasHandleId = connectionSourceId.includes('__');
|
||||||
@@ -25,7 +31,7 @@ export default ({
|
|||||||
const handleId = hasHandleId ? sourceIdSplitted[1] : null;
|
const handleId = hasHandleId ? sourceIdSplitted[1] : null;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const nextSourceNode = nodes.find(n => n.id === nodeId) || null;
|
const nextSourceNode = nodes.find(n => n.id === nodeId) || null;
|
||||||
setSourceNode(nextSourceNode);
|
setSourceNode(nextSourceNode);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -35,11 +41,17 @@ export default ({
|
|||||||
|
|
||||||
const edgeClasses: string = cx('react-flow__edge', 'connection', className);
|
const edgeClasses: string = cx('react-flow__edge', 'connection', className);
|
||||||
|
|
||||||
const sourceHandle = handleId ?
|
const sourceHandle = handleId
|
||||||
sourceNode.__rg.handleBounds.source.find((d: HandleElement) => d.id === handleId) :
|
? sourceNode.__rg.handleBounds.source.find(
|
||||||
sourceNode.__rg.handleBounds.source[0];
|
(d: HandleElement) => d.id === handleId
|
||||||
const sourceHandleX = sourceHandle ? sourceHandle.x + (sourceHandle.width / 2) : sourceNode.__rg.width / 2;
|
)
|
||||||
const sourceHandleY = sourceHandle ? sourceHandle.y + (sourceHandle.height / 2) : sourceNode.__rg.height;
|
: sourceNode.__rg.handleBounds.source[0];
|
||||||
|
const sourceHandleX = sourceHandle
|
||||||
|
? sourceHandle.x + sourceHandle.width / 2
|
||||||
|
: sourceNode.__rg.width / 2;
|
||||||
|
const sourceHandleY = sourceHandle
|
||||||
|
? sourceHandle.y + sourceHandle.height / 2
|
||||||
|
: sourceNode.__rg.height;
|
||||||
const sourceX = sourceNode.__rg.position.x + sourceHandleX;
|
const sourceX = sourceNode.__rg.position.x + sourceHandleX;
|
||||||
const sourceY = sourceNode.__rg.position.y + sourceHandleY;
|
const sourceY = sourceNode.__rg.position.y + sourceHandleY;
|
||||||
|
|
||||||
@@ -58,10 +70,7 @@ export default ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<g className={edgeClasses}>
|
<g className={edgeClasses}>
|
||||||
<path
|
<path d={dAttr} {...connectionLineStyle} />
|
||||||
d={dAttr}
|
|
||||||
{...connectionLineStyle}
|
|
||||||
/>
|
|
||||||
</g>
|
</g>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,28 +2,36 @@ import React, { memo } from 'react';
|
|||||||
|
|
||||||
import { EdgeBezierProps } from '../../types';
|
import { EdgeBezierProps } from '../../types';
|
||||||
|
|
||||||
export default memo(({
|
export default memo(
|
||||||
sourceX, sourceY, targetX, targetY,
|
({
|
||||||
sourcePosition = 'bottom', targetPosition = 'top', style = {}
|
sourceX,
|
||||||
}: EdgeBezierProps) => {
|
sourceY,
|
||||||
const yOffset = Math.abs(targetY - sourceY) / 2;
|
targetX,
|
||||||
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
targetY,
|
||||||
|
sourcePosition = 'bottom',
|
||||||
|
targetPosition = 'top',
|
||||||
|
style = {},
|
||||||
|
}: EdgeBezierProps) => {
|
||||||
|
const yOffset = Math.abs(targetY - sourceY) / 2;
|
||||||
|
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
||||||
|
|
||||||
let dAttr = `M${sourceX},${sourceY} C${sourceX},${centerY} ${targetX},${centerY} ${targetX},${targetY}`;
|
let dAttr = `M${sourceX},${sourceY} C${sourceX},${centerY} ${targetX},${centerY} ${targetX},${targetY}`;
|
||||||
|
|
||||||
if (['left', 'right'].includes(sourcePosition) && ['left', 'right'].includes(targetPosition)) {
|
if (
|
||||||
const xOffset = Math.abs(targetX - sourceX) / 2;
|
['left', 'right'].includes(sourcePosition) &&
|
||||||
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
|
['left', 'right'].includes(targetPosition)
|
||||||
|
) {
|
||||||
|
const xOffset = Math.abs(targetX - sourceX) / 2;
|
||||||
|
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
|
||||||
|
|
||||||
dAttr = `M${sourceX},${sourceY} C${centerX},${sourceY} ${centerX},${targetY} ${targetX},${targetY}`;
|
dAttr = `M${sourceX},${sourceY} C${centerX},${sourceY} ${centerX},${targetY} ${targetX},${targetY}`;
|
||||||
} else if (['left', 'right'].includes(sourcePosition) || ['left', 'right'].includes(targetPosition)) {
|
} else if (
|
||||||
dAttr = `M${sourceX},${sourceY} C${sourceX},${targetY} ${sourceX},${targetY} ${targetX},${targetY}`;
|
['left', 'right'].includes(sourcePosition) ||
|
||||||
|
['left', 'right'].includes(targetPosition)
|
||||||
|
) {
|
||||||
|
dAttr = `M${sourceX},${sourceY} C${sourceX},${targetY} ${sourceX},${targetY} ${targetX},${targetY}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <path {...style} d={dAttr} />;
|
||||||
}
|
}
|
||||||
|
);
|
||||||
return (
|
|
||||||
<path
|
|
||||||
{...style}
|
|
||||||
d={dAttr}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -2,16 +2,16 @@ import React, { memo } from 'react';
|
|||||||
|
|
||||||
import { EdgeProps } from '../../types';
|
import { EdgeProps } from '../../types';
|
||||||
|
|
||||||
export default memo(({
|
export default memo(
|
||||||
sourceX, sourceY, targetX, targetY, style = {}
|
({ sourceX, sourceY, targetX, targetY, style = {} }: EdgeProps) => {
|
||||||
} : EdgeProps) => {
|
const yOffset = Math.abs(targetY - sourceY) / 2;
|
||||||
const yOffset = Math.abs(targetY - sourceY) / 2;
|
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
||||||
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<path
|
<path
|
||||||
{...style}
|
{...style}
|
||||||
d={`M ${sourceX},${sourceY}L ${sourceX},${centerY}L ${targetX},${centerY}L ${targetX},${targetY}`}
|
d={`M ${sourceX},${sourceY}L ${sourceX},${centerY}L ${targetX},${centerY}L ${targetX},${targetY}`}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|||||||
@@ -2,13 +2,10 @@ import React, { memo } from 'react';
|
|||||||
|
|
||||||
import { EdgeProps } from '../../types';
|
import { EdgeProps } from '../../types';
|
||||||
|
|
||||||
export default memo(({
|
export default memo(
|
||||||
sourceX, sourceY, targetX, targetY, style = {}
|
({ sourceX, sourceY, targetX, targetY, style = {} }: EdgeProps) => {
|
||||||
}: EdgeProps) => {
|
return (
|
||||||
return (
|
<path {...style} d={`M ${sourceX},${sourceY}L ${targetX},${targetY}`} />
|
||||||
<path
|
);
|
||||||
{...style}
|
}
|
||||||
d={`M ${sourceX},${sourceY}L ${targetX},${targetY}`}
|
);
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -3,42 +3,56 @@ import cx from 'classnames';
|
|||||||
|
|
||||||
import { isInputDOMNode } from '../../utils';
|
import { isInputDOMNode } from '../../utils';
|
||||||
import store from '../../store';
|
import store from '../../store';
|
||||||
import { EdgeWrapperProps } from '../../types';
|
import { ElementId, Edge, EdgeCompProps } from '../../types';
|
||||||
|
|
||||||
export default (EdgeComponent: ComponentType<EdgeWrapperProps>) => {
|
interface EdgeWrapperProps {
|
||||||
const EdgeWrapper = memo(({
|
id: ElementId;
|
||||||
id, source, target, type,
|
source: ElementId;
|
||||||
animated, selected, onClick,
|
target: ElementId;
|
||||||
...rest
|
type: any;
|
||||||
}: EdgeWrapperProps) => {
|
onClick: (edge: Edge) => void;
|
||||||
const edgeClasses = cx('react-flow__edge', { selected, animated });
|
animated: boolean;
|
||||||
const onEdgeClick = (evt: MouseEvent) => {
|
selected: boolean;
|
||||||
if (isInputDOMNode(evt)) {
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
store.dispatch.setSelectedElements({ id, source, target });
|
export default (EdgeComponent: ComponentType<EdgeCompProps>) => {
|
||||||
onClick({ id, source, target, type });
|
const EdgeWrapper = memo(
|
||||||
};
|
({
|
||||||
|
id,
|
||||||
|
source,
|
||||||
|
target,
|
||||||
|
type,
|
||||||
|
animated,
|
||||||
|
selected,
|
||||||
|
onClick,
|
||||||
|
...rest
|
||||||
|
}: EdgeWrapperProps) => {
|
||||||
|
const edgeClasses = cx('react-flow__edge', { selected, animated });
|
||||||
|
const onEdgeClick = (evt: MouseEvent): void => {
|
||||||
|
if (isInputDOMNode(evt)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
store.dispatch.setSelectedElements({ id, source, target });
|
||||||
<g
|
onClick({ id, source, target, type });
|
||||||
className={edgeClasses}
|
};
|
||||||
onClick={onEdgeClick}
|
|
||||||
>
|
return (
|
||||||
<EdgeComponent
|
<g className={edgeClasses} onClick={onEdgeClick}>
|
||||||
id={id}
|
<EdgeComponent
|
||||||
source={source}
|
id={id}
|
||||||
target={target}
|
source={source}
|
||||||
type={type}
|
target={target}
|
||||||
animated={animated}
|
type={type}
|
||||||
selected={selected}
|
animated={animated}
|
||||||
onClick={onClick}
|
selected={selected}
|
||||||
{...rest}
|
onClick={onClick}
|
||||||
/>
|
{...rest}
|
||||||
</g>
|
/>
|
||||||
);
|
</g>
|
||||||
});
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
EdgeWrapper.displayName = 'EdgeWrapper';
|
EdgeWrapper.displayName = 'EdgeWrapper';
|
||||||
|
|
||||||
|
|||||||
@@ -1,41 +1,54 @@
|
|||||||
import React, { memo, MouseEvent as ReactMouseEvent } from 'react';
|
import React, { memo, MouseEvent as ReactMouseEvent } from 'react';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
|
|
||||||
import { HandleType, ElementId, Position, XYPosition, OnConnectFunc, Connection } from '../../types';
|
import {
|
||||||
|
HandleType,
|
||||||
|
ElementId,
|
||||||
|
Position,
|
||||||
|
XYPosition,
|
||||||
|
OnConnectFunc,
|
||||||
|
Connection,
|
||||||
|
} from '../../types';
|
||||||
|
|
||||||
type ValidConnectionFunc = (connection: Connection) => boolean;
|
type ValidConnectionFunc = (connection: Connection) => boolean;
|
||||||
|
type SetSourceIdFunc = (nodeId: ElementId | null) => void;
|
||||||
|
|
||||||
interface BaseHandleProps {
|
interface BaseHandleProps {
|
||||||
type: HandleType;
|
type: HandleType;
|
||||||
nodeId: ElementId;
|
nodeId: ElementId;
|
||||||
onConnect: OnConnectFunc;
|
onConnect: OnConnectFunc;
|
||||||
position: Position;
|
position: Position;
|
||||||
setSourceId: (nodeId: ElementId) => void;
|
setSourceId: SetSourceIdFunc;
|
||||||
setPosition: (pos: XYPosition) => void;
|
setPosition: (pos: XYPosition) => void;
|
||||||
isValidConnection: ValidConnectionFunc;
|
isValidConnection: ValidConnectionFunc;
|
||||||
id?: ElementId | boolean;
|
id?: ElementId | boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
type Result = {
|
type Result = {
|
||||||
elementBelow: Element;
|
elementBelow: Element | null;
|
||||||
isValid: boolean;
|
isValid: boolean;
|
||||||
connection: Connection;
|
connection: Connection;
|
||||||
isHoveringHandle: boolean;
|
isHoveringHandle: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
function onMouseDown(
|
function onMouseDown(
|
||||||
evt: ReactMouseEvent, nodeId: ElementId, setSourceId: (nodeId: ElementId) => void, setPosition: (pos: XYPosition) => any,
|
evt: ReactMouseEvent,
|
||||||
onConnect: OnConnectFunc, isTarget: boolean, isValidConnection: ValidConnectionFunc
|
nodeId: ElementId,
|
||||||
|
setSourceId: SetSourceIdFunc,
|
||||||
|
setPosition: (pos: XYPosition) => any,
|
||||||
|
onConnect: OnConnectFunc,
|
||||||
|
isTarget: boolean,
|
||||||
|
isValidConnection: ValidConnectionFunc
|
||||||
): void {
|
): void {
|
||||||
const reactFlowNode = document.querySelector('.react-flow');
|
const reactFlowNode = document.querySelector('.react-flow');
|
||||||
|
|
||||||
if (!reactFlowNode) {
|
if (!reactFlowNode) {
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const containerBounds = reactFlowNode.getBoundingClientRect();
|
const containerBounds = reactFlowNode.getBoundingClientRect();
|
||||||
let recentHoveredHandle: Element = null;
|
let recentHoveredHandle: Element;
|
||||||
|
|
||||||
setPosition({
|
setPosition({
|
||||||
x: evt.clientX - containerBounds.left,
|
x: evt.clientX - containerBounds.left,
|
||||||
@@ -43,9 +56,9 @@ function onMouseDown(
|
|||||||
});
|
});
|
||||||
setSourceId(nodeId);
|
setSourceId(nodeId);
|
||||||
|
|
||||||
function resetRecentHandle() {
|
function resetRecentHandle(): void {
|
||||||
if (!recentHoveredHandle) {
|
if (!recentHoveredHandle) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
recentHoveredHandle.classList.remove('valid');
|
recentHoveredHandle.classList.remove('valid');
|
||||||
@@ -55,14 +68,19 @@ function onMouseDown(
|
|||||||
// checks if element below mouse is a handle and returns connection in form of an object { source: 123, target: 312 }
|
// checks if element below mouse is a handle and returns connection in form of an object { source: 123, target: 312 }
|
||||||
function checkElementBelowIsValid(evt: MouseEvent) {
|
function checkElementBelowIsValid(evt: MouseEvent) {
|
||||||
const elementBelow = document.elementFromPoint(evt.clientX, evt.clientY);
|
const elementBelow = document.elementFromPoint(evt.clientX, evt.clientY);
|
||||||
|
|
||||||
const result: Result = {
|
const result: Result = {
|
||||||
elementBelow,
|
elementBelow,
|
||||||
isValid: false,
|
isValid: false,
|
||||||
connection: { source: null, target: null },
|
connection: { source: null, target: null },
|
||||||
isHoveringHandle: false
|
isHoveringHandle: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (elementBelow && (elementBelow.classList.contains('target') || elementBelow.classList.contains('source'))) {
|
if (
|
||||||
|
elementBelow &&
|
||||||
|
(elementBelow.classList.contains('target') ||
|
||||||
|
elementBelow.classList.contains('source'))
|
||||||
|
) {
|
||||||
let connection: Connection = { source: null, target: null };
|
let connection: Connection = { source: null, target: null };
|
||||||
|
|
||||||
if (isTarget) {
|
if (isTarget) {
|
||||||
@@ -89,7 +107,12 @@ function onMouseDown(
|
|||||||
y: evt.clientY - containerBounds.top,
|
y: evt.clientY - containerBounds.top,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { connection, elementBelow, isValid, isHoveringHandle } = checkElementBelowIsValid(evt);
|
const {
|
||||||
|
connection,
|
||||||
|
elementBelow,
|
||||||
|
isValid,
|
||||||
|
isHoveringHandle,
|
||||||
|
} = checkElementBelowIsValid(evt);
|
||||||
|
|
||||||
if (!isHoveringHandle) {
|
if (!isHoveringHandle) {
|
||||||
return resetRecentHandle();
|
return resetRecentHandle();
|
||||||
@@ -97,7 +120,7 @@ function onMouseDown(
|
|||||||
|
|
||||||
const isOwnHandle = connection.source === connection.target;
|
const isOwnHandle = connection.source === connection.target;
|
||||||
|
|
||||||
if (!isOwnHandle) {
|
if (!isOwnHandle && elementBelow) {
|
||||||
recentHoveredHandle = elementBelow;
|
recentHoveredHandle = elementBelow;
|
||||||
elementBelow.classList.add('connecting');
|
elementBelow.classList.add('connecting');
|
||||||
elementBelow.classList.toggle('valid', isValid);
|
elementBelow.classList.toggle('valid', isValid);
|
||||||
@@ -105,7 +128,7 @@ function onMouseDown(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onMouseUp(evt: MouseEvent) {
|
function onMouseUp(evt: MouseEvent) {
|
||||||
const { connection, isValid } = checkElementBelowIsValid(evt);
|
const { connection, isValid } = checkElementBelowIsValid(evt);
|
||||||
|
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
onConnect(connection);
|
onConnect(connection);
|
||||||
@@ -119,37 +142,51 @@ function onMouseDown(
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('mousemove', onMouseMove);
|
document.addEventListener('mousemove', onMouseMove);
|
||||||
document.addEventListener('mouseup', onMouseUp)
|
document.addEventListener('mouseup', onMouseUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
const BaseHandle = memo(({
|
const BaseHandle = memo(
|
||||||
type, nodeId, onConnect, position,
|
({
|
||||||
setSourceId, setPosition, className,
|
type,
|
||||||
id = false, isValidConnection, ...rest
|
nodeId,
|
||||||
}: BaseHandleProps) => {
|
onConnect,
|
||||||
const isTarget = type === 'target';
|
|
||||||
const handleClasses = cx(
|
|
||||||
'react-flow__handle',
|
|
||||||
className,
|
|
||||||
position,
|
position,
|
||||||
{ source: !isTarget, target: isTarget }
|
setSourceId,
|
||||||
);
|
setPosition,
|
||||||
|
className,
|
||||||
|
id = false,
|
||||||
|
isValidConnection,
|
||||||
|
...rest
|
||||||
|
}: BaseHandleProps) => {
|
||||||
|
const isTarget = type === 'target';
|
||||||
|
const handleClasses = cx('react-flow__handle', className, position, {
|
||||||
|
source: !isTarget,
|
||||||
|
target: isTarget,
|
||||||
|
});
|
||||||
|
|
||||||
const nodeIdWithHandleId = id ? `${nodeId}__${id}` : nodeId;
|
const nodeIdWithHandleId = id ? `${nodeId}__${id}` : nodeId;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-nodeid={nodeIdWithHandleId}
|
data-nodeid={nodeIdWithHandleId}
|
||||||
data-handlepos={position}
|
data-handlepos={position}
|
||||||
className={handleClasses}
|
className={handleClasses}
|
||||||
onMouseDown={evt => onMouseDown(evt,
|
onMouseDown={evt =>
|
||||||
nodeIdWithHandleId, setSourceId, setPosition,
|
onMouseDown(
|
||||||
onConnect, isTarget, isValidConnection
|
evt,
|
||||||
)}
|
nodeIdWithHandleId,
|
||||||
{...rest}
|
setSourceId,
|
||||||
/>
|
setPosition,
|
||||||
);
|
onConnect,
|
||||||
});
|
isTarget,
|
||||||
|
isValidConnection
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
BaseHandle.displayName = 'BaseHandle';
|
BaseHandle.displayName = 'BaseHandle';
|
||||||
|
|
||||||
|
|||||||
@@ -2,45 +2,56 @@ import React, { memo, useContext } from 'react';
|
|||||||
|
|
||||||
import { useStoreActions, useStoreState } from '../../store/hooks';
|
import { useStoreActions, useStoreState } from '../../store/hooks';
|
||||||
import BaseHandle from './BaseHandle';
|
import BaseHandle from './BaseHandle';
|
||||||
import NodeIdContext from '../../contexts/NodeIdContext'
|
import NodeIdContext from '../../contexts/NodeIdContext';
|
||||||
|
|
||||||
import { HandleType, ElementId, Position, OnConnectParams, OnConnectFunc } from '../../types';
|
import {
|
||||||
|
HandleType,
|
||||||
|
ElementId,
|
||||||
|
Position,
|
||||||
|
Connection,
|
||||||
|
OnConnectFunc,
|
||||||
|
} from '../../types';
|
||||||
|
|
||||||
interface HandleProps {
|
interface HandleProps {
|
||||||
type: HandleType,
|
type: HandleType;
|
||||||
position: Position,
|
position: Position;
|
||||||
onConnect?: OnConnectFunc,
|
onConnect?: OnConnectFunc;
|
||||||
isValidConnection?: () => boolean
|
isValidConnection?: () => boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
const Handle = memo(({
|
const Handle = memo(
|
||||||
onConnect = _ => {}, type = 'source', position = 'top', isValidConnection = () => true,
|
({
|
||||||
...rest
|
onConnect = _ => {},
|
||||||
}: HandleProps) => {
|
type = 'source',
|
||||||
const nodeId = useContext(NodeIdContext) as ElementId;
|
position = 'top',
|
||||||
const { setPosition, setSourceId } = useStoreActions(a => ({
|
isValidConnection = () => true,
|
||||||
setPosition: a.setConnectionPosition,
|
...rest
|
||||||
setSourceId: a.setConnectionSourceId
|
}: HandleProps) => {
|
||||||
}));
|
const nodeId = useContext(NodeIdContext) as ElementId;
|
||||||
const onConnectAction = useStoreState(s => s.onConnect);
|
const { setPosition, setSourceId } = useStoreActions(a => ({
|
||||||
const onConnectExtended = (params: OnConnectParams) => {
|
setPosition: a.setConnectionPosition,
|
||||||
onConnectAction(params);
|
setSourceId: a.setConnectionSourceId,
|
||||||
onConnect(params);
|
}));
|
||||||
};
|
const onConnectAction = useStoreState(s => s.onConnect);
|
||||||
|
const onConnectExtended = (params: Connection) => {
|
||||||
|
onConnectAction(params);
|
||||||
|
onConnect(params);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseHandle
|
<BaseHandle
|
||||||
nodeId={nodeId}
|
nodeId={nodeId}
|
||||||
setPosition={setPosition}
|
setPosition={setPosition}
|
||||||
setSourceId={setSourceId}
|
setSourceId={setSourceId}
|
||||||
onConnect={onConnectExtended}
|
onConnect={onConnectExtended}
|
||||||
type={type}
|
type={type}
|
||||||
position={position}
|
position={position}
|
||||||
isValidConnection={isValidConnection}
|
isValidConnection={isValidConnection}
|
||||||
{...rest}
|
{...rest}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
Handle.displayName = 'Handle';
|
Handle.displayName = 'Handle';
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const nodeStyles: CSSProperties = {
|
|||||||
background: '#ff6060',
|
background: '#ff6060',
|
||||||
padding: 10,
|
padding: 10,
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
width: 150
|
width: 150,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ({ data, style }: NodeProps) => (
|
export default ({ data, style }: NodeProps) => (
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const nodeStyles: CSSProperties = {
|
|||||||
background: '#9999ff',
|
background: '#9999ff',
|
||||||
padding: 10,
|
padding: 10,
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
width: 150
|
width: 150,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ({ data, style }: NodeProps) => (
|
export default ({ data, style }: NodeProps) => (
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const nodeStyles: CSSProperties = {
|
|||||||
background: '#55dd99',
|
background: '#55dd99',
|
||||||
padding: 10,
|
padding: 10,
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
width: 150
|
width: 150,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ({ data, style }: NodeProps) => (
|
export default ({ data, style }: NodeProps) => (
|
||||||
|
|||||||
+208
-106
@@ -1,4 +1,11 @@
|
|||||||
import React, { useEffect, useRef, useState, memo, ComponentType } from 'react';
|
import React, {
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
memo,
|
||||||
|
ComponentType,
|
||||||
|
CSSProperties,
|
||||||
|
} from 'react';
|
||||||
import { DraggableCore, DraggableEvent } from 'react-draggable';
|
import { DraggableCore, DraggableEvent } from 'react-draggable';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import { ResizeObserver } from 'resize-observer';
|
import { ResizeObserver } from 'resize-observer';
|
||||||
@@ -6,7 +13,28 @@ import { ResizeObserver } from 'resize-observer';
|
|||||||
import { getDimensions, isInputDOMNode } from '../../utils';
|
import { getDimensions, isInputDOMNode } from '../../utils';
|
||||||
import { Provider } from '../../contexts/NodeIdContext';
|
import { Provider } from '../../contexts/NodeIdContext';
|
||||||
import store from '../../store';
|
import store from '../../store';
|
||||||
import { NodeComponentProps, Node, XYPosition, HandleElement, Position, Transform, ElementId } from '../../types';
|
import {
|
||||||
|
Node,
|
||||||
|
XYPosition,
|
||||||
|
HandleElement,
|
||||||
|
Position,
|
||||||
|
Transform,
|
||||||
|
ElementId,
|
||||||
|
NodeComponentProps,
|
||||||
|
} from '../../types';
|
||||||
|
|
||||||
|
interface WrapNodeProps {
|
||||||
|
id: ElementId;
|
||||||
|
type: string;
|
||||||
|
data: any;
|
||||||
|
selected: boolean;
|
||||||
|
transform: Transform;
|
||||||
|
xPos: number;
|
||||||
|
yPos: number;
|
||||||
|
onClick: (node: Node) => void | undefined;
|
||||||
|
onNodeDragStop: (node: Node) => void;
|
||||||
|
style?: CSSProperties;
|
||||||
|
}
|
||||||
|
|
||||||
const isHandle = (evt: MouseEvent | DraggableEvent) => {
|
const isHandle = (evt: MouseEvent | DraggableEvent) => {
|
||||||
const target = evt.target as HTMLElement;
|
const target = evt.target as HTMLElement;
|
||||||
@@ -14,165 +42,239 @@ const isHandle = (evt: MouseEvent | DraggableEvent) => {
|
|||||||
return (
|
return (
|
||||||
target.className &&
|
target.className &&
|
||||||
target.className.includes &&
|
target.className.includes &&
|
||||||
(target.className.includes('source') || target.className.includes('target'))
|
(target.className.includes('source') || target.className.includes('target'))
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getHandleBounds = (
|
const getHandleBounds = (
|
||||||
selector: string, nodeElement: HTMLDivElement, parentBounds: ClientRect | DOMRect, k: number
|
selector: string,
|
||||||
): HandleElement => {
|
nodeElement: HTMLDivElement,
|
||||||
|
parentBounds: ClientRect | DOMRect,
|
||||||
|
k: number
|
||||||
|
): HandleElement[] | null => {
|
||||||
const handles = nodeElement.querySelectorAll(selector);
|
const handles = nodeElement.querySelectorAll(selector);
|
||||||
|
|
||||||
if (!handles || !handles.length) {
|
if (!handles || !handles.length) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [].map.call(handles, (handle: HTMLDivElement): HandleElement => {
|
const handlesArray = Array.from(handles) as HTMLDivElement[];
|
||||||
const bounds = handle.getBoundingClientRect();
|
|
||||||
const dimensions = getDimensions(handle);
|
|
||||||
const nodeIdAttr = handle.getAttribute('data-nodeid');
|
|
||||||
const handlePosition = handle.getAttribute('data-handlepos') as unknown as Position;
|
|
||||||
const nodeIdSplitted = nodeIdAttr.split('__');
|
|
||||||
|
|
||||||
let handleId = null;
|
return handlesArray.map(
|
||||||
|
(handle): HandleElement => {
|
||||||
|
const bounds = handle.getBoundingClientRect();
|
||||||
|
const dimensions = getDimensions(handle);
|
||||||
|
const nodeIdAttr = handle.getAttribute('data-nodeid');
|
||||||
|
const handlePosition = (handle.getAttribute(
|
||||||
|
'data-handlepos'
|
||||||
|
) as unknown) as Position;
|
||||||
|
const nodeIdSplitted = nodeIdAttr ? nodeIdAttr.split('__') : null;
|
||||||
|
|
||||||
if (nodeIdSplitted) {
|
let handleId = null;
|
||||||
handleId = (nodeIdSplitted.length ? nodeIdSplitted[1] : nodeIdSplitted) as string;
|
|
||||||
|
if (nodeIdSplitted) {
|
||||||
|
handleId = (nodeIdSplitted.length
|
||||||
|
? nodeIdSplitted[1]
|
||||||
|
: nodeIdSplitted) as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: handleId,
|
||||||
|
position: handlePosition,
|
||||||
|
x: (bounds.left - parentBounds.left) * (1 / k),
|
||||||
|
y: (bounds.top - parentBounds.top) * (1 / k),
|
||||||
|
...dimensions,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
);
|
||||||
return {
|
|
||||||
id: handleId,
|
|
||||||
position: handlePosition,
|
|
||||||
x: (bounds.left - parentBounds.left) * (1 / k),
|
|
||||||
y: (bounds.top - parentBounds.top) * (1 / k),
|
|
||||||
...dimensions
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onStart = (
|
const onStart = (
|
||||||
evt: MouseEvent, onClick: (node: Node) => void, id: ElementId, type: string,
|
evt: MouseEvent,
|
||||||
data: any, setOffset: (pos: XYPosition) => void, transform: Transform, position: XYPosition
|
onClick: (node: Node) => void,
|
||||||
): false | void => {
|
id: ElementId,
|
||||||
|
type: string,
|
||||||
|
data: any,
|
||||||
|
setOffset: (pos: XYPosition) => void,
|
||||||
|
transform: Transform,
|
||||||
|
position: XYPosition
|
||||||
|
): false | void => {
|
||||||
if (isInputDOMNode(evt) || isHandle(evt)) {
|
if (isInputDOMNode(evt) || isHandle(evt)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const scaledClient: XYPosition = {
|
const scaledClient: XYPosition = {
|
||||||
x: evt.clientX * (1 / transform[2]),
|
x: evt.clientX * (1 / transform[2]),
|
||||||
y: evt.clientY * (1 / transform[2])
|
y: evt.clientY * (1 / transform[2]),
|
||||||
};
|
};
|
||||||
const offsetX = scaledClient.x - position.x - transform[0];
|
const offsetX = scaledClient.x - position.x - transform[0];
|
||||||
const offsetY = scaledClient.y - position.y - transform[1];
|
const offsetY = scaledClient.y - position.y - transform[1];
|
||||||
const node = { id, type, position, data };
|
const node = { id, type, position, data };
|
||||||
|
|
||||||
store.dispatch.setSelectedElements({ id, type });
|
store.dispatch.setSelectedElements({ id, type } as Node);
|
||||||
setOffset({ x: offsetX, y: offsetY });
|
setOffset({ x: offsetX, y: offsetY });
|
||||||
onClick(node);
|
onClick(node);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDrag = (
|
const onDrag = (
|
||||||
evt: MouseEvent, setDragging: (isDragging: boolean) => void, id: ElementId, offset: XYPosition,
|
evt: MouseEvent,
|
||||||
|
setDragging: (isDragging: boolean) => void,
|
||||||
|
id: ElementId,
|
||||||
|
offset: XYPosition,
|
||||||
transform: Transform
|
transform: Transform
|
||||||
): void => {
|
): void => {
|
||||||
const scaledClient = {
|
const scaledClient = {
|
||||||
x: evt.clientX * (1 / transform[2]),
|
x: evt.clientX * (1 / transform[2]),
|
||||||
y: evt.clientY * (1 / transform[2])
|
y: evt.clientY * (1 / transform[2]),
|
||||||
};
|
};
|
||||||
|
|
||||||
setDragging(true);
|
setDragging(true);
|
||||||
store.dispatch.updateNodePos({ id, pos: {
|
store.dispatch.updateNodePos({
|
||||||
x: scaledClient.x - transform[0] - offset.x,
|
id,
|
||||||
y: scaledClient.y - transform[1] - offset.y
|
pos: {
|
||||||
}});
|
x: scaledClient.x - transform[0] - offset.x,
|
||||||
|
y: scaledClient.y - transform[1] - offset.y,
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onStop = (
|
const onStop = (
|
||||||
onNodeDragStop: (params: Node) => void, isDragging: boolean, setDragging: (isDragging: boolean) => void, id: ElementId,
|
onNodeDragStop: (params: Node) => void,
|
||||||
type: string, position: XYPosition, data: any
|
isDragging: boolean,
|
||||||
|
setDragging: (isDragging: boolean) => void,
|
||||||
|
id: ElementId,
|
||||||
|
type: string,
|
||||||
|
position: XYPosition,
|
||||||
|
data: any
|
||||||
): void => {
|
): void => {
|
||||||
if (isDragging) {
|
if (isDragging) {
|
||||||
setDragging(false);
|
setDragging(false);
|
||||||
onNodeDragStop({
|
onNodeDragStop({
|
||||||
id, type, position, data
|
id,
|
||||||
});
|
type,
|
||||||
|
position,
|
||||||
|
data,
|
||||||
|
} as Node);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||||
const NodeWrapper = memo(({
|
const NodeWrapper = memo(
|
||||||
id, type, data, transform,
|
({
|
||||||
xPos, yPos, selected, onClick,
|
id,
|
||||||
onNodeDragStop, style
|
type,
|
||||||
}: NodeComponentProps) => {
|
data,
|
||||||
const nodeElement = useRef<HTMLDivElement>(null);
|
transform,
|
||||||
const [offset, setOffset] = useState({ x: 0, y: 0 });
|
xPos,
|
||||||
const [isDragging, setDragging] = useState(false);
|
yPos,
|
||||||
|
selected,
|
||||||
|
onClick,
|
||||||
|
onNodeDragStop,
|
||||||
|
style,
|
||||||
|
}: WrapNodeProps) => {
|
||||||
|
const nodeElement = useRef<HTMLDivElement>(null);
|
||||||
|
const [offset, setOffset] = useState({ x: 0, y: 0 });
|
||||||
|
const [isDragging, setDragging] = useState(false);
|
||||||
|
|
||||||
const position = { x: xPos, y: yPos };
|
const position = { x: xPos, y: yPos };
|
||||||
const nodeClasses = cx('react-flow__node', { selected });
|
const nodeClasses = cx('react-flow__node', { selected });
|
||||||
const nodeStyle = { zIndex: selected ? 10 : 3, transform: `translate(${xPos}px,${yPos}px)` };
|
const nodeStyle = {
|
||||||
|
zIndex: selected ? 10 : 3,
|
||||||
const updateNode = () => {
|
transform: `translate(${xPos}px,${yPos}px)`,
|
||||||
if (!nodeElement.current) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const storeState = store.getState()
|
|
||||||
const bounds = nodeElement.current.getBoundingClientRect();
|
|
||||||
const dimensions = getDimensions(nodeElement.current);
|
|
||||||
const handleBounds = {
|
|
||||||
source: getHandleBounds('.source', nodeElement.current, bounds, storeState.transform[2]),
|
|
||||||
target: getHandleBounds('.target', nodeElement.current, bounds, storeState.transform[2])
|
|
||||||
};
|
};
|
||||||
store.dispatch.updateNodeData({ id, ...dimensions, handleBounds });
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
const updateNode = (): void => {
|
||||||
if (nodeElement.current) {
|
if (!nodeElement.current) {
|
||||||
updateNode();
|
return;
|
||||||
|
|
||||||
const resizeObserver = new ResizeObserver(entries => {
|
|
||||||
for (let _ of entries) {
|
|
||||||
updateNode();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
resizeObserver.observe(nodeElement.current);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (resizeObserver && nodeElement.current) {
|
|
||||||
resizeObserver.unobserve(nodeElement.current);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}, [nodeElement.current]);
|
|
||||||
|
|
||||||
return (
|
const storeState = store.getState();
|
||||||
<DraggableCore
|
const bounds = nodeElement.current.getBoundingClientRect();
|
||||||
onStart={evt => onStart(evt as MouseEvent, onClick, id, type, data, setOffset, transform, position)}
|
const dimensions = getDimensions(nodeElement.current);
|
||||||
onDrag={evt => onDrag(evt as MouseEvent, setDragging, id, offset, transform)}
|
const handleBounds = {
|
||||||
onStop={() => onStop(onNodeDragStop, isDragging, setDragging, id, type, position, data)}
|
source: getHandleBounds(
|
||||||
scale={transform[2]}
|
'.source',
|
||||||
>
|
nodeElement.current,
|
||||||
<div
|
bounds,
|
||||||
className={nodeClasses}
|
storeState.transform[2]
|
||||||
ref={nodeElement}
|
),
|
||||||
style={nodeStyle}
|
target: getHandleBounds(
|
||||||
|
'.target',
|
||||||
|
nodeElement.current,
|
||||||
|
bounds,
|
||||||
|
storeState.transform[2]
|
||||||
|
),
|
||||||
|
};
|
||||||
|
store.dispatch.updateNodeData({ id, ...dimensions, handleBounds });
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (nodeElement.current) {
|
||||||
|
updateNode();
|
||||||
|
|
||||||
|
const resizeObserver = new ResizeObserver(entries => {
|
||||||
|
for (let _ of entries) {
|
||||||
|
updateNode();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
resizeObserver.observe(nodeElement.current);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (resizeObserver && nodeElement.current) {
|
||||||
|
resizeObserver.unobserve(nodeElement.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}, [nodeElement.current]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DraggableCore
|
||||||
|
onStart={evt =>
|
||||||
|
onStart(
|
||||||
|
evt as MouseEvent,
|
||||||
|
onClick,
|
||||||
|
id,
|
||||||
|
type,
|
||||||
|
data,
|
||||||
|
setOffset,
|
||||||
|
transform,
|
||||||
|
position
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onDrag={evt =>
|
||||||
|
onDrag(evt as MouseEvent, setDragging, id, offset, transform)
|
||||||
|
}
|
||||||
|
onStop={() =>
|
||||||
|
onStop(
|
||||||
|
onNodeDragStop,
|
||||||
|
isDragging,
|
||||||
|
setDragging,
|
||||||
|
id,
|
||||||
|
type,
|
||||||
|
position,
|
||||||
|
data
|
||||||
|
)
|
||||||
|
}
|
||||||
|
scale={transform[2]}
|
||||||
>
|
>
|
||||||
<Provider value={id}>
|
<div className={nodeClasses} ref={nodeElement} style={nodeStyle}>
|
||||||
<NodeComponent
|
<Provider value={id}>
|
||||||
id={id}
|
<NodeComponent
|
||||||
data={data}
|
id={id}
|
||||||
type={type}
|
data={data}
|
||||||
style={style}
|
type={type}
|
||||||
selected={selected}
|
style={style}
|
||||||
/>
|
selected={selected}
|
||||||
</Provider>
|
/>
|
||||||
</div>
|
</Provider>
|
||||||
</DraggableCore>
|
</div>
|
||||||
);
|
</DraggableCore>
|
||||||
});
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
NodeWrapper.displayName = 'NodeWrapper';
|
NodeWrapper.displayName = 'NodeWrapper';
|
||||||
|
|
||||||
|
|||||||
@@ -5,28 +5,30 @@ import { useStoreState, useStoreActions } from '../../store/hooks';
|
|||||||
import { isNode } from '../../utils/graph';
|
import { isNode } from '../../utils/graph';
|
||||||
import { Node, Elements, XYPosition } from '../../types';
|
import { Node, Elements, XYPosition } from '../../types';
|
||||||
|
|
||||||
function getStartPositions(elements: Elements) {
|
type StartPositions = { [key: string]: XYPosition };
|
||||||
return elements
|
|
||||||
.filter(isNode)
|
|
||||||
.reduce((res, node: Node) => {
|
|
||||||
const startPosition = {
|
|
||||||
x: node.__rg.position.x || node.position.x,
|
|
||||||
y: node.__rg.position.y || node.position.x
|
|
||||||
};
|
|
||||||
|
|
||||||
res[node.id] = startPosition;
|
function getStartPositions(elements: Elements): StartPositions {
|
||||||
|
const startPositions: StartPositions = {};
|
||||||
|
|
||||||
return res;
|
return (elements.filter(isNode) as Node[]).reduce((res, node) => {
|
||||||
}, {});
|
const startPosition = {
|
||||||
|
x: node.__rg.position.x || node.position.x,
|
||||||
|
y: node.__rg.position.y || node.position.x,
|
||||||
|
};
|
||||||
|
|
||||||
|
res[node.id] = startPosition;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}, startPositions);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default memo(() => {
|
export default memo(() => {
|
||||||
const [offset, setOffset] = useState({ x: 0, y: 0 });
|
const [offset, setOffset] = useState<XYPosition>({ x: 0, y: 0 });
|
||||||
const [startPositions, setStartPositions] = useState({});
|
const [startPositions, setStartPositions] = useState<StartPositions>({});
|
||||||
const state = useStoreState(s => ({
|
const state = useStoreState(s => ({
|
||||||
transform: s.transform,
|
transform: s.transform,
|
||||||
selectedNodesBbox: s.selectedNodesBbox,
|
selectedNodesBbox: s.selectedNodesBbox,
|
||||||
selectedElements: s.selectedElements
|
selectedElements: s.selectedElements,
|
||||||
}));
|
}));
|
||||||
const updateNodePos = useStoreActions(a => a.updateNodePos);
|
const updateNodePos = useStoreActions(a => a.updateNodePos);
|
||||||
const [x, y, k] = state.transform;
|
const [x, y, k] = state.transform;
|
||||||
@@ -35,43 +37,55 @@ export default memo(() => {
|
|||||||
const onStart = (evt: MouseEvent) => {
|
const onStart = (evt: MouseEvent) => {
|
||||||
const scaledClient: XYPosition = {
|
const scaledClient: XYPosition = {
|
||||||
x: evt.clientX * (1 / k),
|
x: evt.clientX * (1 / k),
|
||||||
y: evt.clientY * (1 / k)
|
y: evt.clientY * (1 / k),
|
||||||
};
|
};
|
||||||
const offsetX: number = scaledClient.x - position.x - x;
|
const offsetX: number = scaledClient.x - position.x - x;
|
||||||
const offsetY: number = scaledClient.y - position.y - y;
|
const offsetY: number = scaledClient.y - position.y - y;
|
||||||
const startPositions = getStartPositions(state.selectedElements);
|
const nextStartPositions = getStartPositions(state.selectedElements);
|
||||||
|
|
||||||
setOffset({ x: offsetX, y: offsetY });
|
if (nextStartPositions) {
|
||||||
setStartPositions(startPositions);
|
setOffset({ x: offsetX, y: offsetY });
|
||||||
|
setStartPositions(nextStartPositions);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDrag = (evt: MouseEvent) => {
|
const onDrag = (evt: MouseEvent) => {
|
||||||
const scaledClient: XYPosition = {
|
const scaledClient: XYPosition = {
|
||||||
x: evt.clientX * (1 / k),
|
x: evt.clientX * (1 / k),
|
||||||
y: evt.clientY * (1 / k)
|
y: evt.clientY * (1 / k),
|
||||||
};
|
};
|
||||||
|
|
||||||
state.selectedElements
|
(state.selectedElements.filter(isNode) as Node[]).forEach(node => {
|
||||||
.filter(isNode)
|
const pos: XYPosition = {
|
||||||
.forEach((node: Node) => {
|
x:
|
||||||
updateNodePos({ id: node.id, pos: {
|
startPositions[node.id].x +
|
||||||
x: startPositions[node.id].x + scaledClient.x - position.x - offset.x - x ,
|
scaledClient.x -
|
||||||
y: startPositions[node.id].y + scaledClient.y - position.y - offset.y - y
|
position.x -
|
||||||
}});
|
offset.x -
|
||||||
});
|
x,
|
||||||
|
y:
|
||||||
|
startPositions[node.id].y +
|
||||||
|
scaledClient.y -
|
||||||
|
position.y -
|
||||||
|
offset.y -
|
||||||
|
y,
|
||||||
|
};
|
||||||
|
|
||||||
|
updateNodePos({ id: node.id, pos });
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="react-flow__nodesselection"
|
className="react-flow__nodesselection"
|
||||||
style={{
|
style={{
|
||||||
transform: `translate(${x}px,${y}px) scale(${k})`
|
transform: `translate(${x}px,${y}px) scale(${k})`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ReactDraggable
|
<ReactDraggable
|
||||||
scale={k}
|
scale={k}
|
||||||
onStart={(evt: MouseEvent) => onStart(evt)}
|
onStart={evt => onStart(evt as MouseEvent)}
|
||||||
onDrag={(evt: MouseEvent) => onDrag(evt)}
|
onDrag={evt => onDrag(evt as MouseEvent)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="react-flow__nodesselection-rect"
|
className="react-flow__nodesselection-rect"
|
||||||
@@ -79,7 +93,7 @@ export default memo(() => {
|
|||||||
width: state.selectedNodesBbox.width,
|
width: state.selectedNodesBbox.width,
|
||||||
height: state.selectedNodesBbox.height,
|
height: state.selectedNodesBbox.height,
|
||||||
top: state.selectedNodesBbox.y,
|
top: state.selectedNodesBbox.y,
|
||||||
left: state.selectedNodesBbox.x
|
left: state.selectedNodesBbox.x,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</ReactDraggable>
|
</ReactDraggable>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useRef, useState, memo, MouseEvent } from 'react';
|
import React, { useEffect, useRef, useState, memo } from 'react';
|
||||||
|
|
||||||
import { useStoreActions } from '../../store/hooks';
|
import { useStoreActions } from '../../store/hooks';
|
||||||
import { SelectionRect } from '../../types';
|
import { SelectionRect } from '../../types';
|
||||||
@@ -10,7 +10,7 @@ const initialRect: SelectionRect = {
|
|||||||
y: 0,
|
y: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
draw: false
|
draw: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
function getMousePosition(evt: MouseEvent) {
|
function getMousePosition(evt: MouseEvent) {
|
||||||
@@ -28,33 +28,33 @@ function getMousePosition(evt: MouseEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default memo(() => {
|
export default memo(() => {
|
||||||
const selectionPane = useRef(null);
|
const selectionPane = useRef<HTMLDivElement>(null);
|
||||||
const [rect, setRect] = useState(initialRect);
|
const [rect, setRect] = useState(initialRect);
|
||||||
const setSelection = useStoreActions(a => a.setSelection);
|
const setSelection = useStoreActions(a => a.setSelection);
|
||||||
const updateSelection = useStoreActions(a => a.updateSelection);
|
const updateSelection = useStoreActions(a => a.updateSelection);
|
||||||
const setNodesSelection = useStoreActions(a => a.setNodesSelection);
|
const setNodesSelection = useStoreActions(a => a.setNodesSelection);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function onMouseDown(evt: MouseEvent) {
|
function onMouseDown(evt: MouseEvent): void {
|
||||||
const mousePos = getMousePosition(evt);
|
const mousePos = getMousePosition(evt);
|
||||||
if (!mousePos) {
|
if (!mousePos) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setRect((currentRect) => ({
|
setRect(currentRect => ({
|
||||||
...currentRect,
|
...currentRect,
|
||||||
startX: mousePos.x,
|
startX: mousePos.x,
|
||||||
startY: mousePos.y,
|
startY: mousePos.y,
|
||||||
x: mousePos.x,
|
x: mousePos.x,
|
||||||
y: mousePos.y,
|
y: mousePos.y,
|
||||||
draw: true
|
draw: true,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
setSelection(true);
|
setSelection(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMouseMove(evt: MouseEvent) {
|
function onMouseMove(evt: MouseEvent): void {
|
||||||
setRect((currentRect) => {
|
setRect(currentRect => {
|
||||||
if (!currentRect.draw) {
|
if (!currentRect.draw) {
|
||||||
return currentRect;
|
return currentRect;
|
||||||
}
|
}
|
||||||
@@ -70,8 +70,12 @@ export default memo(() => {
|
|||||||
...currentRect,
|
...currentRect,
|
||||||
x: negativeX ? mousePos.x : currentRect.x,
|
x: negativeX ? mousePos.x : currentRect.x,
|
||||||
y: negativeY ? mousePos.y : currentRect.y,
|
y: negativeY ? mousePos.y : currentRect.y,
|
||||||
width: negativeX ? currentRect.startX - mousePos.x : mousePos.x - currentRect.startX,
|
width: negativeX
|
||||||
height: negativeY ? currentRect.startY - mousePos.y : mousePos.y - currentRect.startY,
|
? currentRect.startX - mousePos.x
|
||||||
|
: mousePos.x - currentRect.startX,
|
||||||
|
height: negativeY
|
||||||
|
? currentRect.startY - mousePos.y
|
||||||
|
: mousePos.y - currentRect.startY,
|
||||||
};
|
};
|
||||||
|
|
||||||
updateSelection(nextRect);
|
updateSelection(nextRect);
|
||||||
@@ -81,40 +85,44 @@ export default memo(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onMouseUp() {
|
function onMouseUp() {
|
||||||
setRect((currentRect) => {
|
setRect(currentRect => {
|
||||||
setNodesSelection({ isActive: true, selection: currentRect });
|
setNodesSelection({ isActive: true, selection: currentRect });
|
||||||
setSelection(false);
|
setSelection(false);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...currentRect,
|
...currentRect,
|
||||||
draw: false
|
draw: false,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
selectionPane.current.addEventListener('mousedown', onMouseDown);
|
if (selectionPane.current) {
|
||||||
selectionPane.current.addEventListener('mousemove', onMouseMove);
|
selectionPane.current.addEventListener('mousedown', onMouseDown);
|
||||||
selectionPane.current.addEventListener('mouseup', onMouseUp);
|
selectionPane.current.addEventListener('mousemove', onMouseMove);
|
||||||
|
selectionPane.current.addEventListener('mouseup', onMouseUp);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
selectionPane.current.removeEventListener('mousedown', onMouseDown);
|
if (!selectionPane.current) {
|
||||||
selectionPane.current.removeEventListener('mousemove', onMouseMove);
|
return;
|
||||||
selectionPane.current.removeEventListener('mouseup', onMouseUp);
|
}
|
||||||
};
|
selectionPane.current.removeEventListener('mousedown', onMouseDown);
|
||||||
}, []);
|
selectionPane.current.removeEventListener('mousemove', onMouseMove);
|
||||||
|
selectionPane.current.removeEventListener('mouseup', onMouseUp);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}, [selectionPane.current]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className="react-flow__selectionpane" ref={selectionPane}>
|
||||||
className="react-flow__selectionpane"
|
|
||||||
ref={selectionPane}
|
|
||||||
>
|
|
||||||
{rect.draw && (
|
{rect.draw && (
|
||||||
<div
|
<div
|
||||||
className="react-flow__selection"
|
className="react-flow__selection"
|
||||||
style={{
|
style={{
|
||||||
width: rect.width,
|
width: rect.width,
|
||||||
height: rect.height,
|
height: rect.height,
|
||||||
transform: `translate(${rect.x}px, ${rect.y}px)`
|
transform: `translate(${rect.x}px, ${rect.y}px)`,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -3,7 +3,15 @@ import React, { memo, SVGAttributes } from 'react';
|
|||||||
import { useStoreState } from '../../store/hooks';
|
import { useStoreState } from '../../store/hooks';
|
||||||
import ConnectionLine from '../../components/ConnectionLine/index';
|
import ConnectionLine from '../../components/ConnectionLine/index';
|
||||||
import { isEdge } from '../../utils/graph';
|
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 {
|
interface EdgeRendererProps {
|
||||||
width: number;
|
width: number;
|
||||||
@@ -12,69 +20,82 @@ interface EdgeRendererProps {
|
|||||||
connectionLineStyle?: SVGAttributes<{}>;
|
connectionLineStyle?: SVGAttributes<{}>;
|
||||||
connectionLineType?: string;
|
connectionLineType?: string;
|
||||||
onElementClick?: () => void;
|
onElementClick?: () => void;
|
||||||
};
|
}
|
||||||
|
|
||||||
interface EdgeRendererState {
|
interface EdgeRendererState {
|
||||||
nodes: Node[];
|
nodes: Node[];
|
||||||
edges: Edge[];
|
edges: Edge[];
|
||||||
transform: Transform;
|
transform: Transform;
|
||||||
selectedElements: any;
|
selectedElements: any;
|
||||||
connectionSourceId: ElementId | null;
|
connectionSourceId: ElementId | null;
|
||||||
position: XYPosition;
|
position: XYPosition;
|
||||||
};
|
}
|
||||||
|
|
||||||
interface EdgePositions {
|
interface EdgePositions {
|
||||||
sourceX: number;
|
sourceX: number;
|
||||||
sourceY: number;
|
sourceY: number;
|
||||||
targetX: number;
|
targetX: number;
|
||||||
targetY: 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) {
|
if (!handle) {
|
||||||
switch (position) {
|
switch (position) {
|
||||||
case 'top': return {
|
case 'top':
|
||||||
x: node.__rg.width / 2,
|
return {
|
||||||
y: 0
|
x: node.__rg.width / 2,
|
||||||
};
|
y: 0,
|
||||||
case 'right': return {
|
};
|
||||||
x: node.__rg.width,
|
case 'right':
|
||||||
y: node.__rg.height / 2
|
return {
|
||||||
};
|
x: node.__rg.width,
|
||||||
case 'bottom': return {
|
y: node.__rg.height / 2,
|
||||||
x: node.__rg.width / 2,
|
};
|
||||||
y: node.__rg.height
|
case 'bottom':
|
||||||
};
|
return {
|
||||||
case 'left': return {
|
x: node.__rg.width / 2,
|
||||||
x: 0,
|
y: node.__rg.height,
|
||||||
y: node.__rg.height / 2
|
};
|
||||||
};
|
case 'left':
|
||||||
|
return {
|
||||||
|
x: 0,
|
||||||
|
y: node.__rg.height / 2,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (position) {
|
switch (position) {
|
||||||
case 'top': return {
|
case 'top':
|
||||||
x: handle.x + (handle.width / 2),
|
return {
|
||||||
y: handle.y
|
x: handle.x + handle.width / 2,
|
||||||
};
|
y: handle.y,
|
||||||
case 'right': return {
|
};
|
||||||
x: handle.x + handle.width,
|
case 'right':
|
||||||
y: handle.y + (handle.height / 2)
|
return {
|
||||||
};
|
x: handle.x + handle.width,
|
||||||
case 'bottom': return {
|
y: handle.y + handle.height / 2,
|
||||||
x: handle.x + (handle.width / 2),
|
};
|
||||||
y: handle.y + handle.height
|
case 'bottom':
|
||||||
};
|
return {
|
||||||
case 'left': return {
|
x: handle.x + handle.width / 2,
|
||||||
x: handle.x,
|
y: handle.y + handle.height,
|
||||||
y: handle.y + (handle.height / 2)
|
};
|
||||||
};
|
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;
|
let handle = null;
|
||||||
|
|
||||||
if (!bounds) {
|
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
|
// there is no handleId when there are no multiple handles/ handles with ids
|
||||||
// so we just pick the first one
|
// so we just pick the first one
|
||||||
if (bounds.length === 1 || !handleId) {
|
if (bounds.length === 1 || !handleId) {
|
||||||
handle = bounds[0];
|
handle = bounds[0];
|
||||||
} else if (handleId) {
|
} else if (handleId) {
|
||||||
handle = bounds.find(d => d.id === handleId);
|
handle = bounds.find(d => d.id === handleId);
|
||||||
@@ -93,23 +114,42 @@ function getHandle(bounds: HandleElement[], handleId: ElementId): HandleElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getEdgePositions(
|
function getEdgePositions(
|
||||||
sourceNode: Node, sourceHandle: HandleElement, sourcePosition: Position,
|
sourceNode: Node,
|
||||||
targetNode: Node, targetHandle: HandleElement, targetPosition: Position
|
sourceHandle: HandleElement | unknown,
|
||||||
|
sourcePosition: Position,
|
||||||
|
targetNode: Node,
|
||||||
|
targetHandle: HandleElement | unknown,
|
||||||
|
targetPosition: Position
|
||||||
): EdgePositions {
|
): EdgePositions {
|
||||||
const sourceHandlePos = getHandlePosition(sourcePosition, sourceNode, sourceHandle)
|
const sourceHandlePos = getHandlePosition(
|
||||||
|
sourcePosition,
|
||||||
|
sourceNode,
|
||||||
|
sourceHandle
|
||||||
|
);
|
||||||
const sourceX = sourceNode.__rg.position.x + sourceHandlePos.x;
|
const sourceX = sourceNode.__rg.position.x + sourceHandlePos.x;
|
||||||
const sourceY = sourceNode.__rg.position.y + sourceHandlePos.y;
|
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 targetX = targetNode.__rg.position.x + targetHandlePos.x;
|
||||||
const targetY = targetNode.__rg.position.y + targetHandlePos.y;
|
const targetY = targetNode.__rg.position.y + targetHandlePos.y;
|
||||||
|
|
||||||
return {
|
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 edgeType = edge.type || 'default';
|
||||||
|
|
||||||
const hasSourceHandleId = edge.source.includes('__');
|
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 EdgeComponent = props.edgeTypes[edgeType] || props.edgeTypes.default;
|
||||||
const sourceHandle = getHandle(sourceNode.__rg.handleBounds.source, sourceHandleId);
|
const sourceHandle = getHandle(
|
||||||
const targetHandle = getHandle(targetNode.__rg.handleBounds.target, targetHandleId);
|
sourceNode.__rg.handleBounds.source,
|
||||||
|
sourceHandleId
|
||||||
|
);
|
||||||
|
const targetHandle = getHandle(
|
||||||
|
targetNode.__rg.handleBounds.target,
|
||||||
|
targetHandleId
|
||||||
|
);
|
||||||
const sourcePosition = sourceHandle ? sourceHandle.position : 'bottom';
|
const sourcePosition = sourceHandle ? sourceHandle.position : 'bottom';
|
||||||
const targetPosition = targetHandle ? targetHandle.position : 'top';
|
const targetPosition = targetHandle ? targetHandle.position : 'top';
|
||||||
|
|
||||||
const { sourceX, sourceY, targetX, targetY } = getEdgePositions(
|
const { sourceX, sourceY, targetX, targetY } = getEdgePositions(
|
||||||
sourceNode, sourceHandle, sourcePosition,
|
sourceNode,
|
||||||
targetNode, targetHandle, targetPosition
|
sourceHandle,
|
||||||
|
sourcePosition,
|
||||||
|
targetNode,
|
||||||
|
targetHandle,
|
||||||
|
targetPosition
|
||||||
);
|
);
|
||||||
const selected = state.selectedElements
|
const selected = state.selectedElements
|
||||||
.filter(isEdge)
|
.filter(isEdge)
|
||||||
@@ -169,47 +219,61 @@ function renderEdge(edge: Edge, props: EdgeRendererProps, state: EdgeRendererSta
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const EdgeRenderer = memo(({
|
const EdgeRenderer = memo(
|
||||||
width, height, connectionLineStyle, connectionLineType, ...rest
|
({
|
||||||
}: EdgeRendererProps) => {
|
width,
|
||||||
const state: EdgeRendererState = useStoreState(s => ({
|
height,
|
||||||
nodes: s.nodes,
|
connectionLineStyle,
|
||||||
edges: s.edges,
|
connectionLineType,
|
||||||
transform: s.transform,
|
...rest
|
||||||
selectedElements: s.selectedElements,
|
}: EdgeRendererProps) => {
|
||||||
connectionSourceId: s.connectionSourceId,
|
const state: EdgeRendererState = useStoreState(s => ({
|
||||||
position: s.connectionPosition
|
nodes: s.nodes,
|
||||||
}));
|
edges: s.edges,
|
||||||
if (!width) {
|
transform: s.transform,
|
||||||
return null;
|
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';
|
EdgeRenderer.displayName = 'EdgeRenderer';
|
||||||
|
|
||||||
|
|||||||
@@ -4,25 +4,31 @@ import StraightEdge from '../../components/Edges/StraightEdge';
|
|||||||
import BezierEdge from '../../components/Edges/BezierEdge';
|
import BezierEdge from '../../components/Edges/BezierEdge';
|
||||||
import wrapEdge from '../../components/Edges/wrapEdge';
|
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 = {
|
const standardTypes: EdgeTypesType = {
|
||||||
default: wrapEdge((edgeTypes.default || BezierEdge) as ComponentType<EdgeWrapperProps>),
|
default: wrapEdge((edgeTypes.default || BezierEdge) as ComponentType<
|
||||||
straight: wrapEdge((edgeTypes.bezier || StraightEdge) as ComponentType<EdgeWrapperProps>)
|
EdgeCompProps
|
||||||
|
>),
|
||||||
|
straight: wrapEdge((edgeTypes.bezier || StraightEdge) as ComponentType<
|
||||||
|
EdgeCompProps
|
||||||
|
>),
|
||||||
};
|
};
|
||||||
|
|
||||||
const specialTypes: EdgeTypesType = Object
|
const wrappedTypes = {} as EdgeTypesType;
|
||||||
.keys(edgeTypes)
|
const specialTypes: EdgeTypesType = Object.keys(edgeTypes)
|
||||||
.filter(k => !['default', 'bezier'].includes(k))
|
.filter(k => !['default', 'bezier'].includes(k))
|
||||||
.reduce((res, key) => {
|
.reduce((res, key) => {
|
||||||
res[key] = wrapEdge((edgeTypes[key] || BezierEdge) as ComponentType<EdgeWrapperProps>);
|
res[key] = wrapEdge((edgeTypes[key] || BezierEdge) as ComponentType<
|
||||||
|
EdgeCompProps
|
||||||
|
>);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}, {});
|
}, wrappedTypes);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...standardTypes,
|
...standardTypes,
|
||||||
...specialTypes
|
...specialTypes,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,117 +9,153 @@ import BackgroundGrid from '../../components/BackgroundGrid';
|
|||||||
import useKeyPress from '../../hooks/useKeyPress';
|
import useKeyPress from '../../hooks/useKeyPress';
|
||||||
import useD3Zoom from '../../hooks/useD3Zoom';
|
import useD3Zoom from '../../hooks/useD3Zoom';
|
||||||
import useGlobalKeyHandler from '../../hooks/useGlobalKeyHandler';
|
import useGlobalKeyHandler from '../../hooks/useGlobalKeyHandler';
|
||||||
import useElementUpdater from '../../hooks/useElementUpdater'
|
import useElementUpdater from '../../hooks/useElementUpdater';
|
||||||
import { getDimensions } from '../../utils';
|
import { getDimensions } from '../../utils';
|
||||||
import { fitView, zoomIn, zoomOut } from '../../utils/graph';
|
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 {
|
export interface GraphViewProps {
|
||||||
elements: Elements,
|
elements: Elements;
|
||||||
onElementClick: () => void,
|
onElementClick: () => void;
|
||||||
onElementsRemove: (elements: Elements) => void,
|
onElementsRemove: (elements: Elements) => void;
|
||||||
onNodeDragStop: () => void,
|
onNodeDragStop: () => void;
|
||||||
onConnect: () => void,
|
onConnect: () => void;
|
||||||
onLoad: OnLoadFunc,
|
onLoad: OnLoadFunc;
|
||||||
onMove: () => void,
|
onMove: () => void;
|
||||||
selectionKeyCode: number,
|
selectionKeyCode: number;
|
||||||
nodeTypes: NodeTypesType,
|
nodeTypes: NodeTypesType;
|
||||||
edgeTypes: EdgeTypesType,
|
edgeTypes: EdgeTypesType;
|
||||||
connectionLineType: string,
|
connectionLineType: string;
|
||||||
connectionLineStyle: SVGAttributes<{}>,
|
connectionLineStyle: SVGAttributes<{}>;
|
||||||
deleteKeyCode: number,
|
deleteKeyCode: number;
|
||||||
showBackground: boolean,
|
showBackground: boolean;
|
||||||
backgroundGap: number,
|
backgroundGap: number;
|
||||||
backgroundColor: string,
|
backgroundColor: string;
|
||||||
backgroundType: GridType,
|
backgroundType: GridType;
|
||||||
};
|
snapToGrid: boolean;
|
||||||
|
snapGrid: [number, number];
|
||||||
|
}
|
||||||
|
|
||||||
const GraphView = memo(({
|
const GraphView = memo(
|
||||||
nodeTypes, edgeTypes, onMove, onLoad,
|
({
|
||||||
onElementClick, onNodeDragStop, connectionLineType, connectionLineStyle,
|
nodeTypes,
|
||||||
selectionKeyCode, onElementsRemove, deleteKeyCode, elements,
|
edgeTypes,
|
||||||
showBackground, backgroundGap, backgroundColor, backgroundType,
|
onMove,
|
||||||
onConnect
|
onLoad,
|
||||||
}: GraphViewProps) => {
|
onElementClick,
|
||||||
const zoomPane = useRef<HTMLDivElement>(null);
|
onNodeDragStop,
|
||||||
const rendererNode = useRef<HTMLDivElement>(null);
|
connectionLineType,
|
||||||
const state = useStoreState(s => ({
|
connectionLineStyle,
|
||||||
width: s.width,
|
selectionKeyCode,
|
||||||
height: s.height,
|
onElementsRemove,
|
||||||
nodes: s.nodes,
|
deleteKeyCode,
|
||||||
edges: s.edges,
|
elements,
|
||||||
d3Initialised: s.d3Initialised,
|
showBackground,
|
||||||
nodesSelectionActive: s.nodesSelectionActive
|
backgroundGap,
|
||||||
}));
|
backgroundColor,
|
||||||
const updateSize = useStoreActions(actions => actions.updateSize);
|
backgroundType,
|
||||||
const setNodesSelection = useStoreActions(actions => actions.setNodesSelection);
|
onConnect,
|
||||||
const setOnConnect = useStoreActions(a => a.setOnConnect);
|
snapToGrid,
|
||||||
const selectionKeyPressed = useKeyPress(selectionKeyCode);
|
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 onZoomPaneClick = () => setNodesSelection({ isActive: false });
|
||||||
const size = getDimensions(rendererNode.current);
|
|
||||||
updateSize(size);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
const updateDimensions = () => {
|
||||||
updateDimensions();
|
if (!rendererNode.current) {
|
||||||
setOnConnect(onConnect);
|
return;
|
||||||
window.onresize = updateDimensions;
|
}
|
||||||
|
|
||||||
return () => {
|
const size = getDimensions(rendererNode.current);
|
||||||
window.onresize = null;
|
updateSize(size);
|
||||||
};
|
};
|
||||||
}, []);
|
|
||||||
|
|
||||||
useD3Zoom(zoomPane, onMove, selectionKeyPressed);
|
useEffect(() => {
|
||||||
|
updateDimensions();
|
||||||
|
setOnConnect(onConnect);
|
||||||
|
window.onresize = updateDimensions;
|
||||||
|
|
||||||
useEffect(() => {
|
return () => {
|
||||||
if (state.d3Initialised) {
|
window.onresize = null;
|
||||||
onLoad({
|
};
|
||||||
fitView,
|
}, []);
|
||||||
zoomIn,
|
|
||||||
zoomOut
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [state.d3Initialised]);
|
|
||||||
|
|
||||||
useGlobalKeyHandler({ onElementsRemove, deleteKeyCode });
|
useD3Zoom(zoomPane, onMove, selectionKeyPressed);
|
||||||
useElementUpdater(elements);
|
|
||||||
|
|
||||||
return (
|
useEffect(() => {
|
||||||
<div className="react-flow__renderer" ref={rendererNode}>
|
if (state.d3Initialised) {
|
||||||
{showBackground && (
|
onLoad({
|
||||||
<BackgroundGrid
|
fitView,
|
||||||
gap={backgroundGap}
|
zoomIn,
|
||||||
color={backgroundColor}
|
zoomOut,
|
||||||
backgroundType={backgroundType}
|
});
|
||||||
|
}
|
||||||
|
}, [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}
|
||||||
/>
|
/>
|
||||||
)}
|
<EdgeRenderer
|
||||||
<NodeRenderer
|
width={state.width}
|
||||||
nodeTypes={nodeTypes}
|
height={state.height}
|
||||||
onElementClick={onElementClick}
|
edgeTypes={edgeTypes}
|
||||||
onNodeDragStop={onNodeDragStop}
|
onElementClick={onElementClick}
|
||||||
/>
|
connectionLineType={connectionLineType}
|
||||||
<EdgeRenderer
|
connectionLineStyle={connectionLineStyle}
|
||||||
width={state.width}
|
/>
|
||||||
height={state.height}
|
{selectionKeyPressed && <UserSelection />}
|
||||||
edgeTypes={edgeTypes}
|
{state.nodesSelectionActive && <NodesSelection />}
|
||||||
onElementClick={onElementClick}
|
<div
|
||||||
connectionLineType={connectionLineType}
|
className="react-flow__zoompane"
|
||||||
connectionLineStyle={connectionLineStyle}
|
onClick={onZoomPaneClick}
|
||||||
/>
|
ref={zoomPane}
|
||||||
{selectionKeyPressed && <UserSelection />}
|
/>
|
||||||
{state.nodesSelectionActive && <NodesSelection />}
|
</div>
|
||||||
<div
|
);
|
||||||
className="react-flow__zoompane"
|
}
|
||||||
onClick={onZoomPaneClick}
|
);
|
||||||
ref={zoomPane}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
GraphView.displayName = 'GraphView';
|
GraphView.displayName = 'GraphView';
|
||||||
|
|
||||||
|
|||||||
@@ -2,28 +2,40 @@ import React, { memo, ComponentType } from 'react';
|
|||||||
|
|
||||||
import { useStoreState } from '../../store/hooks';
|
import { useStoreState } from '../../store/hooks';
|
||||||
import { isNode } from '../../utils/graph';
|
import { isNode } from '../../utils/graph';
|
||||||
import { Node, Transform, NodeTypesType, NodeComponentProps, } from '../../types';
|
import {
|
||||||
|
Node,
|
||||||
|
Transform,
|
||||||
|
NodeTypesType,
|
||||||
|
NodeComponentProps,
|
||||||
|
} from '../../types';
|
||||||
|
|
||||||
interface NodeRendererProps {
|
interface NodeRendererProps {
|
||||||
nodeTypes: NodeTypesType;
|
nodeTypes: NodeTypesType;
|
||||||
onElementClick: () => void;
|
onElementClick: () => void;
|
||||||
onNodeDragStop: () => void;
|
onNodeDragStop: () => void;
|
||||||
};
|
}
|
||||||
|
|
||||||
interface NodeRendererState {
|
interface NodeRendererState {
|
||||||
nodes: Node[];
|
nodes: Node[];
|
||||||
transform: Transform;
|
transform: Transform;
|
||||||
selectedElements: any;
|
selectedElements: any;
|
||||||
};
|
}
|
||||||
|
|
||||||
function renderNode(node: Node, props: NodeRendererProps, state: NodeRendererState) {
|
function renderNode(
|
||||||
|
node: Node,
|
||||||
|
props: NodeRendererProps,
|
||||||
|
state: NodeRendererState
|
||||||
|
) {
|
||||||
const nodeType = node.type || 'default';
|
const nodeType = node.type || 'default';
|
||||||
|
|
||||||
if (!props.nodeTypes[nodeType]) {
|
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
|
const selected = state.selectedElements
|
||||||
.filter(isNode)
|
.filter(isNode)
|
||||||
.map((e: Node) => e.id)
|
.map((e: Node) => e.id)
|
||||||
@@ -33,7 +45,7 @@ function renderNode(node: Node, props: NodeRendererProps, state: NodeRendererSta
|
|||||||
<NodeComponent
|
<NodeComponent
|
||||||
key={node.id}
|
key={node.id}
|
||||||
id={node.id}
|
id={node.id}
|
||||||
type={node.type}
|
type={nodeType}
|
||||||
data={node.data}
|
data={node.data}
|
||||||
xPos={node.__rg.position.x}
|
xPos={node.__rg.position.x}
|
||||||
yPos={node.__rg.position.y}
|
yPos={node.__rg.position.y}
|
||||||
@@ -50,17 +62,16 @@ const NodeRenderer = memo((props: NodeRendererProps) => {
|
|||||||
const state: NodeRendererState = useStoreState(s => ({
|
const state: NodeRendererState = useStoreState(s => ({
|
||||||
nodes: s.nodes,
|
nodes: s.nodes,
|
||||||
transform: s.transform,
|
transform: s.transform,
|
||||||
selectedElements: s.selectedElements
|
selectedElements: s.selectedElements,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const { transform, nodes } = state;
|
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 (
|
return (
|
||||||
<div
|
<div className="react-flow__nodes" style={transformStyle}>
|
||||||
className="react-flow__nodes"
|
|
||||||
style={transformStyle}
|
|
||||||
>
|
|
||||||
{nodes.map(node => renderNode(node, props, state))}
|
{nodes.map(node => renderNode(node, props, state))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,24 +6,32 @@ import OutputNode from '../../components/Nodes/OutputNode';
|
|||||||
import wrapNode from '../../components/Nodes/wrapNode';
|
import wrapNode from '../../components/Nodes/wrapNode';
|
||||||
import { NodeTypesType, NodeComponentProps } from '../../types';
|
import { NodeTypesType, NodeComponentProps } from '../../types';
|
||||||
|
|
||||||
export function createNodeTypes(nodeTypes: NodeTypesType): NodeTypesType {
|
export function createNodeTypes(nodeTypes: NodeTypesType): NodeTypesType {
|
||||||
const standardTypes: NodeTypesType = {
|
const standardTypes: NodeTypesType = {
|
||||||
input: wrapNode((nodeTypes.input || InputNode) as ComponentType<NodeComponentProps>),
|
input: wrapNode((nodeTypes.input || InputNode) as ComponentType<
|
||||||
default: wrapNode((nodeTypes.default || DefaultNode) as ComponentType<NodeComponentProps>),
|
NodeComponentProps
|
||||||
output: wrapNode((nodeTypes.output || OutputNode) as ComponentType<NodeComponentProps>)
|
>),
|
||||||
|
default: wrapNode((nodeTypes.default || DefaultNode) as ComponentType<
|
||||||
|
NodeComponentProps
|
||||||
|
>),
|
||||||
|
output: wrapNode((nodeTypes.output || OutputNode) as ComponentType<
|
||||||
|
NodeComponentProps
|
||||||
|
>),
|
||||||
};
|
};
|
||||||
|
|
||||||
const specialTypes: NodeTypesType = Object
|
const wrappedTypes = {} as NodeTypesType;
|
||||||
.keys(nodeTypes)
|
const specialTypes: NodeTypesType = Object.keys(nodeTypes)
|
||||||
.filter(k => !['input', 'default', 'output'].includes(k))
|
.filter(k => !['input', 'default', 'output'].includes(k))
|
||||||
.reduce((res, key) => {
|
.reduce((res, key) => {
|
||||||
res[key] = wrapNode((nodeTypes[key] || DefaultNode) as ComponentType<NodeComponentProps>);
|
res[key] = wrapNode((nodeTypes[key] || DefaultNode) as ComponentType<
|
||||||
|
NodeComponentProps
|
||||||
|
>);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}, {});
|
}, wrappedTypes);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...standardTypes,
|
...standardTypes,
|
||||||
...specialTypes
|
...specialTypes,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useMemo, CSSProperties, ReactNode, SVGAttributes } from 'react';
|
import React, { useMemo, SVGAttributes, HTMLAttributes } from 'react';
|
||||||
import { StoreProvider } from 'easy-peasy';
|
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') {
|
if (nodeEnv !== 'production') {
|
||||||
const whyDidYouRender = require('@welldone-software/why-did-you-render');
|
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 StepEdge from '../../components/Edges/StepEdge';
|
||||||
import { createEdgeTypes } from '../EdgeRenderer/utils';
|
import { createEdgeTypes } from '../EdgeRenderer/utils';
|
||||||
import store from '../../store';
|
import store from '../../store';
|
||||||
import { Elements, NodeTypesType, EdgeTypesType, GridType, OnLoadFunc } from '../../types';
|
import {
|
||||||
|
Elements,
|
||||||
|
NodeTypesType,
|
||||||
|
EdgeTypesType,
|
||||||
|
GridType,
|
||||||
|
OnLoadFunc,
|
||||||
|
} from '../../types';
|
||||||
|
|
||||||
import '../../style.css';
|
import '../../style.css';
|
||||||
|
|
||||||
export interface ReactFlowProps {
|
export interface ReactFlowProps
|
||||||
elements: Elements,
|
extends Omit<HTMLAttributes<HTMLDivElement>, 'onLoad'> {
|
||||||
style?: CSSProperties,
|
elements: Elements;
|
||||||
className?: string,
|
onElementClick: () => void;
|
||||||
children?: ReactNode[],
|
onElementsRemove: (elements: Elements) => void;
|
||||||
onElementClick: () => void,
|
onNodeDragStop: () => void;
|
||||||
onElementsRemove: (elements: Elements) => void,
|
onConnect: () => void;
|
||||||
onNodeDragStop: () => void,
|
onLoad: OnLoadFunc;
|
||||||
onConnect: () => void,
|
onMove: () => void;
|
||||||
onLoad: OnLoadFunc,
|
nodeTypes: NodeTypesType;
|
||||||
onMove: () => void,
|
edgeTypes: EdgeTypesType;
|
||||||
nodeTypes: NodeTypesType,
|
connectionLineType: string;
|
||||||
edgeTypes: EdgeTypesType,
|
connectionLineStyle: SVGAttributes<{}>;
|
||||||
connectionLineType: string,
|
deleteKeyCode: number;
|
||||||
connectionLineStyle: SVGAttributes<{}>,
|
selectionKeyCode: number;
|
||||||
deleteKeyCode: number,
|
showBackground: boolean;
|
||||||
selectionKeyCode: number,
|
backgroundGap: number;
|
||||||
showBackground: boolean,
|
backgroundColor: string;
|
||||||
backgroundGap: number,
|
backgroundType: GridType;
|
||||||
backgroundColor: string,
|
snapToGrid: boolean;
|
||||||
backgroundType: GridType
|
snapGrid: [16, 16];
|
||||||
};
|
}
|
||||||
|
|
||||||
const ReactFlow = ({
|
const ReactFlow = ({
|
||||||
style, onElementClick, elements, children,
|
style,
|
||||||
nodeTypes, edgeTypes, onLoad, onMove,
|
onElementClick,
|
||||||
onElementsRemove, onConnect, onNodeDragStop, connectionLineType,
|
elements,
|
||||||
connectionLineStyle, deleteKeyCode, selectionKeyCode,
|
children,
|
||||||
showBackground, backgroundGap, backgroundType, backgroundColor
|
nodeTypes,
|
||||||
|
edgeTypes,
|
||||||
|
onLoad,
|
||||||
|
onMove,
|
||||||
|
onElementsRemove,
|
||||||
|
onConnect,
|
||||||
|
onNodeDragStop,
|
||||||
|
connectionLineType,
|
||||||
|
connectionLineStyle,
|
||||||
|
deleteKeyCode,
|
||||||
|
selectionKeyCode,
|
||||||
|
showBackground,
|
||||||
|
backgroundGap,
|
||||||
|
backgroundType,
|
||||||
|
backgroundColor,
|
||||||
|
snapToGrid,
|
||||||
|
snapGrid,
|
||||||
}: ReactFlowProps) => {
|
}: ReactFlowProps) => {
|
||||||
const nodeTypesParsed = useMemo(() => createNodeTypes(nodeTypes), []);
|
const nodeTypesParsed = useMemo(() => createNodeTypes(nodeTypes), []);
|
||||||
const edgeTypesParsed = useMemo(() => createEdgeTypes(edgeTypes), []);
|
const edgeTypesParsed = useMemo(() => createEdgeTypes(edgeTypes), []);
|
||||||
@@ -76,6 +98,8 @@ const ReactFlow = ({
|
|||||||
backgroundGap={backgroundGap}
|
backgroundGap={backgroundGap}
|
||||||
showBackground={showBackground}
|
showBackground={showBackground}
|
||||||
backgroundType={backgroundType}
|
backgroundType={backgroundType}
|
||||||
|
snapToGrid={snapToGrid}
|
||||||
|
snapGrid={snapGrid}
|
||||||
/>
|
/>
|
||||||
{children}
|
{children}
|
||||||
</StoreProvider>
|
</StoreProvider>
|
||||||
@@ -90,17 +114,17 @@ ReactFlow.defaultProps = {
|
|||||||
onElementsRemove: () => {},
|
onElementsRemove: () => {},
|
||||||
onNodeDragStop: () => {},
|
onNodeDragStop: () => {},
|
||||||
onConnect: () => {},
|
onConnect: () => {},
|
||||||
onLoad: () => {},
|
onLoad: () => {},
|
||||||
onMove: () => {},
|
onMove: () => {},
|
||||||
nodeTypes: {
|
nodeTypes: {
|
||||||
input: InputNode,
|
input: InputNode,
|
||||||
default: DefaultNode,
|
default: DefaultNode,
|
||||||
output: OutputNode
|
output: OutputNode,
|
||||||
},
|
},
|
||||||
edgeTypes: {
|
edgeTypes: {
|
||||||
default: BezierEdge,
|
default: BezierEdge,
|
||||||
straight: StraightEdge,
|
straight: StraightEdge,
|
||||||
step: StepEdge
|
step: StepEdge,
|
||||||
},
|
},
|
||||||
connectionLineType: 'bezier',
|
connectionLineType: 'bezier',
|
||||||
connectionLineStyle: {},
|
connectionLineStyle: {},
|
||||||
@@ -109,7 +133,9 @@ ReactFlow.defaultProps = {
|
|||||||
backgroundColor: '#eee',
|
backgroundColor: '#eee',
|
||||||
backgroundGap: 24,
|
backgroundGap: 24,
|
||||||
showBackground: true,
|
showBackground: true,
|
||||||
backgroundType: GridType.Dots
|
backgroundType: GridType.Dots,
|
||||||
|
snapToGrid: false,
|
||||||
|
snapGrid: [16, 16],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ReactFlow;
|
export default ReactFlow;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { createContext } from 'react';
|
|||||||
|
|
||||||
import { ElementId } from '../types';
|
import { ElementId } from '../types';
|
||||||
|
|
||||||
type ContextProps = ElementId | null;
|
type ContextProps = ElementId | null;
|
||||||
|
|
||||||
export const NodeIdContext = createContext<Partial<ContextProps>>(null);
|
export const NodeIdContext = createContext<Partial<ContextProps>>(null);
|
||||||
export const Provider = NodeIdContext.Provider;
|
export const Provider = NodeIdContext.Provider;
|
||||||
|
|||||||
Vendored
+3
-2
@@ -3,11 +3,12 @@ declare module '*.css' {
|
|||||||
export default content;
|
export default content;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SvgrComponent extends React.StatelessComponent<React.SVGAttributes<SVGElement>> {}
|
interface SvgrComponent
|
||||||
|
extends React.StatelessComponent<React.SVGAttributes<SVGElement>> {}
|
||||||
|
|
||||||
declare module '*.svg' {
|
declare module '*.svg' {
|
||||||
const svgUrl: string;
|
const svgUrl: string;
|
||||||
const svgComponent: SvgrComponent;
|
const svgComponent: SvgrComponent;
|
||||||
export default svgUrl;
|
export default svgUrl;
|
||||||
export { svgComponent as ReactComponent }
|
export { svgComponent as ReactComponent };
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-9
@@ -9,7 +9,11 @@ const d3ZoomInstance = d3Zoom
|
|||||||
.scaleExtent([0.5, 2])
|
.scaleExtent([0.5, 2])
|
||||||
.filter(() => !event.button);
|
.filter(() => !event.button);
|
||||||
|
|
||||||
export default (zoomPane: MutableRefObject<HTMLDivElement>, onMove: () => void, shiftPressed: boolean): void => {
|
export default (
|
||||||
|
zoomPane: MutableRefObject<Element | null>,
|
||||||
|
onMove: () => void,
|
||||||
|
shiftPressed: boolean
|
||||||
|
): void => {
|
||||||
const state = useStoreState(s => ({
|
const state = useStoreState(s => ({
|
||||||
transform: s.transform,
|
transform: s.transform,
|
||||||
d3Selection: s.d3Selection,
|
d3Selection: s.d3Selection,
|
||||||
@@ -20,8 +24,10 @@ export default (zoomPane: MutableRefObject<HTMLDivElement>, onMove: () => void,
|
|||||||
const updateTransform = useStoreActions(actions => actions.updateTransform);
|
const updateTransform = useStoreActions(actions => actions.updateTransform);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const selection = select(zoomPane.current).call(d3ZoomInstance);
|
if (zoomPane.current) {
|
||||||
initD3({ zoom: d3ZoomInstance, selection });
|
const selection = select(zoomPane.current).call(d3ZoomInstance);
|
||||||
|
initD3({ zoom: d3ZoomInstance, selection });
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -29,8 +35,11 @@ export default (zoomPane: MutableRefObject<HTMLDivElement>, onMove: () => void,
|
|||||||
d3ZoomInstance.on('zoom', null);
|
d3ZoomInstance.on('zoom', null);
|
||||||
} else {
|
} else {
|
||||||
d3ZoomInstance.on('zoom', () => {
|
d3ZoomInstance.on('zoom', () => {
|
||||||
if (event.sourceEvent && event.sourceEvent.target !== zoomPane.current) {
|
if (
|
||||||
return false;
|
event.sourceEvent &&
|
||||||
|
event.sourceEvent.target !== zoomPane.current
|
||||||
|
) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTransform(event.transform);
|
updateTransform(event.transform);
|
||||||
@@ -38,11 +47,11 @@ export default (zoomPane: MutableRefObject<HTMLDivElement>, onMove: () => void,
|
|||||||
onMove();
|
onMove();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (state.d3Selection) {
|
if (state.d3Selection && state.d3Zoom) {
|
||||||
// we need to restore the graph transform otherwise d3 zoom transform and graph transform are not synced
|
// we need to restore the graph transform otherwise d3 zoom transform and graph transform are not synced
|
||||||
const graphTransform = d3Zoom.zoomIdentity
|
const graphTransform = d3Zoom.zoomIdentity
|
||||||
.translate(state.transform[0], state.transform[1])
|
.translate(state.transform[0], state.transform[1])
|
||||||
.scale(state.transform[2]);
|
.scale(state.transform[2]);
|
||||||
|
|
||||||
state.d3Selection.call(state.d3Zoom.transform, graphTransform);
|
state.d3Selection.call(state.d3Zoom.transform, graphTransform);
|
||||||
}
|
}
|
||||||
@@ -52,4 +61,4 @@ export default (zoomPane: MutableRefObject<HTMLDivElement>, onMove: () => void,
|
|||||||
d3ZoomInstance.on('zoom', null);
|
d3ZoomInstance.on('zoom', null);
|
||||||
};
|
};
|
||||||
}, [shiftPressed]);
|
}, [shiftPressed]);
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const useElementUpdater = (elements: Elements): void => {
|
|||||||
const state = useStoreState(s => ({
|
const state = useStoreState(s => ({
|
||||||
nodes: s.nodes,
|
nodes: s.nodes,
|
||||||
edges: s.edges,
|
edges: s.edges,
|
||||||
transform: s.transform
|
transform: s.transform,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const setNodes = useStoreActions(a => a.setNodes);
|
const setNodes = useStoreActions(a => a.setNodes);
|
||||||
@@ -19,16 +19,17 @@ const useElementUpdater = (elements: Elements): void => {
|
|||||||
const nodes = elements.filter(isNode) as Node[];
|
const nodes = elements.filter(isNode) as Node[];
|
||||||
const edges = elements.filter(isEdge).map(e => parseElement(e)) as Edge[];
|
const edges = elements.filter(isEdge).map(e => parseElement(e)) as Edge[];
|
||||||
|
|
||||||
const nextNodes = nodes.map((propNode) => {
|
const nextNodes = nodes.map(propNode => {
|
||||||
const existingNode = state.nodes.find(n => n.id === propNode.id);
|
const existingNode = state.nodes.find(n => n.id === propNode.id);
|
||||||
|
|
||||||
if (existingNode) {
|
if (existingNode) {
|
||||||
const data = !isEqual(existingNode.data, propNode.data) ?
|
const data = !isEqual(existingNode.data, propNode.data)
|
||||||
{ ...existingNode.data, ...propNode.data } : existingNode.data;
|
? { ...existingNode.data, ...propNode.data }
|
||||||
|
: existingNode.data;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...existingNode,
|
...existingNode,
|
||||||
data
|
data,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,8 +47,6 @@ const useElementUpdater = (elements: Elements): void => {
|
|||||||
setEdges(edges);
|
setEdges(edges);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useElementUpdater;
|
export default useElementUpdater;
|
||||||
|
|||||||
@@ -8,10 +8,13 @@ import { Elements, Node } from '../types';
|
|||||||
interface HookParams {
|
interface HookParams {
|
||||||
deleteKeyCode: number;
|
deleteKeyCode: number;
|
||||||
onElementsRemove: (elements: Elements) => void;
|
onElementsRemove: (elements: Elements) => void;
|
||||||
};
|
}
|
||||||
|
|
||||||
export default ({ deleteKeyCode, onElementsRemove }: HookParams): void => {
|
export default ({ deleteKeyCode, onElementsRemove }: HookParams): void => {
|
||||||
const state = useStoreState(s => ({ selectedElements: s.selectedElements, edges: s.edges }))
|
const state = useStoreState(s => ({
|
||||||
|
selectedElements: s.selectedElements,
|
||||||
|
edges: s.edges,
|
||||||
|
}));
|
||||||
const setNodesSelection = useStoreActions(a => a.setNodesSelection);
|
const setNodesSelection = useStoreActions(a => a.setNodesSelection);
|
||||||
const deleteKeyPressed = useKeyPress(deleteKeyCode);
|
const deleteKeyPressed = useKeyPress(deleteKeyCode);
|
||||||
|
|
||||||
@@ -20,8 +23,11 @@ export default ({ deleteKeyCode, onElementsRemove }: HookParams): void => {
|
|||||||
let elementsToRemove = state.selectedElements;
|
let elementsToRemove = state.selectedElements;
|
||||||
|
|
||||||
// we also want to remove the edges if only one node is selected
|
// we also want to remove the edges if only one node is selected
|
||||||
if (state.selectedElements.length === 1 && !isEdge(state.selectedElements[0])) {
|
if (
|
||||||
const node = state.selectedElements[0] as unknown as Node;
|
state.selectedElements.length === 1 &&
|
||||||
|
!isEdge(state.selectedElements[0])
|
||||||
|
) {
|
||||||
|
const node = (state.selectedElements[0] as unknown) as Node;
|
||||||
const connectedEdges = getConnectedEdges([node], state.edges);
|
const connectedEdges = getConnectedEdges([node], state.edges);
|
||||||
elementsToRemove = [...state.selectedElements, ...connectedEdges];
|
elementsToRemove = [...state.selectedElements, ...connectedEdges];
|
||||||
}
|
}
|
||||||
@@ -29,7 +35,5 @@ export default ({ deleteKeyCode, onElementsRemove }: HookParams): void => {
|
|||||||
onElementsRemove(elementsToRemove);
|
onElementsRemove(elementsToRemove);
|
||||||
setNodesSelection({ isActive: false });
|
setNodesSelection({ isActive: false });
|
||||||
}
|
}
|
||||||
}, [deleteKeyPressed])
|
}, [deleteKeyPressed]);
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
|
|||||||
|
|
||||||
import { isInputDOMNode } from '../utils';
|
import { isInputDOMNode } from '../utils';
|
||||||
|
|
||||||
export default (keyCode: number) => {
|
export default (keyCode: number): boolean => {
|
||||||
const [keyPressed, setKeyPressed] = useState(false);
|
const [keyPressed, setKeyPressed] = useState(false);
|
||||||
|
|
||||||
function downHandler(evt: KeyboardEvent) {
|
function downHandler(evt: KeyboardEvent) {
|
||||||
@@ -28,4 +28,4 @@ export default (keyCode: number) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return keyPressed;
|
return keyPressed;
|
||||||
}
|
};
|
||||||
|
|||||||
+1
-1
@@ -10,5 +10,5 @@ export {
|
|||||||
isEdge,
|
isEdge,
|
||||||
removeElements,
|
removeElements,
|
||||||
addEdge,
|
addEdge,
|
||||||
getOutgoers
|
getOutgoers,
|
||||||
} from './utils/graph';
|
} from './utils/graph';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React, { CSSProperties } from 'react';
|
|||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
|
||||||
import { fitView, zoomIn, zoomOut } from '../../utils/graph';
|
import { fitView, zoomIn, zoomOut } from '../../utils/graph';
|
||||||
import PlusIcon from '../../../assets/icons/plus.svg';
|
import PlusIcon from '../../../assets/icons/plus.svg';
|
||||||
import MinusIcon from '../../../assets/icons/minus.svg';
|
import MinusIcon from '../../../assets/icons/minus.svg';
|
||||||
import FitviewIcon from '../../../assets/icons/fitview.svg';
|
import FitviewIcon from '../../../assets/icons/fitview.svg';
|
||||||
|
|
||||||
@@ -13,10 +13,7 @@ const baseStyle: CSSProperties = {
|
|||||||
left: 10,
|
left: 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ControlProps {
|
interface ControlProps extends React.HTMLAttributes<HTMLDivElement> {}
|
||||||
style?: CSSProperties;
|
|
||||||
className?: string
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ({ style, className }: ControlProps) => {
|
export default ({ style, className }: ControlProps) => {
|
||||||
const mapClasses: string = classnames('react-flow__controls', className);
|
const mapClasses: string = classnames('react-flow__controls', className);
|
||||||
@@ -26,7 +23,7 @@ export default ({ style, className }: ControlProps) => {
|
|||||||
className={mapClasses}
|
className={mapClasses}
|
||||||
style={{
|
style={{
|
||||||
...baseStyle,
|
...baseStyle,
|
||||||
...style
|
...style,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -7,25 +7,26 @@ import { Node } from '../../types';
|
|||||||
|
|
||||||
type StringFunc = (node: Node) => string;
|
type StringFunc = (node: Node) => string;
|
||||||
|
|
||||||
interface MiniMapProps {
|
interface MiniMapProps extends React.HTMLAttributes<HTMLCanvasElement> {
|
||||||
style?: CSSProperties;
|
|
||||||
className?: string | null;
|
|
||||||
bgColor?: string;
|
bgColor?: string;
|
||||||
nodeColor?: string | StringFunc;
|
nodeColor?: string | StringFunc;
|
||||||
};
|
}
|
||||||
|
|
||||||
const baseStyle: CSSProperties = {
|
const baseStyle: CSSProperties = {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
zIndex: 5,
|
zIndex: 5,
|
||||||
bottom: 10,
|
bottom: 10,
|
||||||
right: 10,
|
right: 10,
|
||||||
width: 200
|
width: 200,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default (
|
export default ({
|
||||||
{ style = {}, className, bgColor = '#f8f8f8', nodeColor = '#ddd' }: MiniMapProps
|
style = {},
|
||||||
) => {
|
className,
|
||||||
const canvasNode = useRef(null);
|
bgColor = '#f8f8f8',
|
||||||
|
nodeColor = '#ddd',
|
||||||
|
}: MiniMapProps) => {
|
||||||
|
const canvasNode = useRef<HTMLCanvasElement>(null);
|
||||||
const state = useStoreState(s => ({
|
const state = useStoreState(s => ({
|
||||||
width: s.width,
|
width: s.width,
|
||||||
height: s.height,
|
height: s.height,
|
||||||
@@ -34,45 +35,59 @@ export default (
|
|||||||
}));
|
}));
|
||||||
const mapClasses = classnames('react-flow__minimap', className);
|
const mapClasses = classnames('react-flow__minimap', className);
|
||||||
const nodePositions = state.nodes.map(n => n.__rg.position);
|
const nodePositions = state.nodes.map(n => n.__rg.position);
|
||||||
const width: number = +(style.width || baseStyle.width || 0);
|
const width: number = +(style.width || baseStyle.width || 0);
|
||||||
const height = (state.height / (state.width || 1)) * width;
|
const height = (state.height / (state.width || 1)) * width;
|
||||||
const bbox = { x: 0, y: 0, width: state.width, height: state.height };
|
const bbox = { x: 0, y: 0, width: state.width, height: state.height };
|
||||||
const scaleFactor = width / state.width;
|
const scaleFactor = width / state.width;
|
||||||
const nodeColorFunc = (nodeColor instanceof Function ? nodeColor: () => nodeColor) as StringFunc;
|
const nodeColorFunc = (nodeColor instanceof Function
|
||||||
|
? nodeColor
|
||||||
|
: () => nodeColor) as StringFunc;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (canvasNode && canvasNode.current) {
|
if (!canvasNode || !canvasNode.current) {
|
||||||
const ctx = canvasNode.current.getContext('2d');
|
return;
|
||||||
const nodesInside = getNodesInside(state.nodes, bbox, state.transform, true);
|
|
||||||
|
|
||||||
ctx.fillStyle = bgColor;
|
|
||||||
ctx.fillRect(0, 0, width, height);
|
|
||||||
|
|
||||||
nodesInside.forEach((n) => {
|
|
||||||
const pos = n.__rg.position;
|
|
||||||
const transformX = state.transform[0];
|
|
||||||
const transformY = state.transform[1];
|
|
||||||
const x = (pos.x * state.transform[2]) + transformX;
|
|
||||||
const y = (pos.y * state.transform[2]) + transformY;
|
|
||||||
|
|
||||||
ctx.fillStyle = nodeColorFunc(n);
|
|
||||||
|
|
||||||
ctx.fillRect(
|
|
||||||
(x * scaleFactor),
|
|
||||||
(y * scaleFactor),
|
|
||||||
n.__rg.width * scaleFactor * state.transform[2],
|
|
||||||
n.__rg.height * scaleFactor * state.transform[2]
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, [canvasNode.current, nodePositions, state.transform, height])
|
|
||||||
|
const ctx = canvasNode.current.getContext('2d');
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nodesInside = getNodesInside(
|
||||||
|
state.nodes,
|
||||||
|
bbox,
|
||||||
|
state.transform,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
ctx.fillStyle = bgColor;
|
||||||
|
ctx.fillRect(0, 0, width, height);
|
||||||
|
|
||||||
|
nodesInside.forEach(n => {
|
||||||
|
const pos = n.__rg.position;
|
||||||
|
const transformX = state.transform[0];
|
||||||
|
const transformY = state.transform[1];
|
||||||
|
const x = pos.x * state.transform[2] + transformX;
|
||||||
|
const y = pos.y * state.transform[2] + transformY;
|
||||||
|
|
||||||
|
ctx.fillStyle = nodeColorFunc(n);
|
||||||
|
|
||||||
|
ctx.fillRect(
|
||||||
|
x * scaleFactor,
|
||||||
|
y * scaleFactor,
|
||||||
|
n.__rg.width * scaleFactor * state.transform[2],
|
||||||
|
n.__rg.height * scaleFactor * state.transform[2]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}, [canvasNode.current, nodePositions, state.transform, height]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<canvas
|
<canvas
|
||||||
style={{
|
style={{
|
||||||
...baseStyle,
|
...baseStyle,
|
||||||
...style,
|
...style,
|
||||||
height
|
height,
|
||||||
}}
|
}}
|
||||||
width={width}
|
width={width}
|
||||||
height={height}
|
height={height}
|
||||||
@@ -80,4 +95,4 @@ export default (
|
|||||||
ref={canvasNode}
|
ref={canvasNode}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
export { default as MiniMap } from './MiniMap';
|
export { default as MiniMap } from './MiniMap';
|
||||||
export { default as Controls } from './Controls';
|
export { default as Controls } from './Controls';
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
import { createTypedHooks } from 'easy-peasy';
|
import { createTypedHooks } from 'easy-peasy';
|
||||||
|
|
||||||
import { StoreModel } from './index';
|
import { StoreModel } from './index';
|
||||||
|
|
||||||
const typedHooks = createTypedHooks<StoreModel>();
|
const typedHooks = createTypedHooks<StoreModel>();
|
||||||
|
|
||||||
|
|||||||
+96
-36
@@ -2,32 +2,44 @@ import { createStore, Action, action } from 'easy-peasy';
|
|||||||
import isEqual from 'fast-deep-equal';
|
import isEqual from 'fast-deep-equal';
|
||||||
import { Selection as D3Selection, ZoomBehavior } from 'd3';
|
import { Selection as D3Selection, ZoomBehavior } from 'd3';
|
||||||
|
|
||||||
import { getBoundingBox, getNodesInside, getConnectedEdges } from '../utils/graph';
|
|
||||||
import {
|
import {
|
||||||
ElementId, Elements, Transform, Node,
|
getBoundingBox,
|
||||||
Edge, Rect, Dimensions, XYPosition,
|
getNodesInside,
|
||||||
OnConnectFunc, SelectionRect, HandleElement
|
getConnectedEdges,
|
||||||
|
} from '../utils/graph';
|
||||||
|
import {
|
||||||
|
ElementId,
|
||||||
|
Elements,
|
||||||
|
Transform,
|
||||||
|
Node,
|
||||||
|
Edge,
|
||||||
|
Rect,
|
||||||
|
Dimensions,
|
||||||
|
XYPosition,
|
||||||
|
OnConnectFunc,
|
||||||
|
SelectionRect,
|
||||||
|
HandleElement,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
|
|
||||||
type TransformXYK = {
|
type TransformXYK = {
|
||||||
x: number,
|
x: number;
|
||||||
y: number,
|
y: number;
|
||||||
k: number
|
k: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
type NodePosUpdate = {
|
type NodePosUpdate = {
|
||||||
id: ElementId,
|
id: ElementId;
|
||||||
pos: XYPosition
|
pos: XYPosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
type NodeUpdate = {
|
type NodeUpdate = {
|
||||||
id: ElementId,
|
id: ElementId;
|
||||||
width: number,
|
width: number;
|
||||||
height: number,
|
height: number;
|
||||||
handleBounds: {
|
handleBounds: {
|
||||||
source: HandleElement,
|
source: HandleElement[] | null;
|
||||||
target: HandleElement
|
target: HandleElement[] | null;
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
type SelectionUpdate = {
|
type SelectionUpdate = {
|
||||||
@@ -40,6 +52,11 @@ type D3Init = {
|
|||||||
selection: D3Selection<Element, unknown, null, undefined>;
|
selection: D3Selection<Element, unknown, null, undefined>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type SetSnapGrid = {
|
||||||
|
snapToGrid: boolean;
|
||||||
|
snapGrid: [number, number];
|
||||||
|
};
|
||||||
|
|
||||||
export interface StoreModel {
|
export interface StoreModel {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
@@ -49,17 +66,20 @@ export interface StoreModel {
|
|||||||
selectedElements: Elements;
|
selectedElements: Elements;
|
||||||
selectedNodesBbox: Rect;
|
selectedNodesBbox: Rect;
|
||||||
|
|
||||||
d3Zoom: ZoomBehavior<Element, unknown>;
|
d3Zoom: ZoomBehavior<Element, unknown> | null;
|
||||||
d3Selection: D3Selection<Element, unknown, null, undefined>;
|
d3Selection: D3Selection<Element, unknown, null, undefined> | null;
|
||||||
d3Initialised: boolean;
|
d3Initialised: boolean;
|
||||||
|
|
||||||
nodesSelectionActive: boolean;
|
nodesSelectionActive: boolean;
|
||||||
selectionActive: boolean;
|
selectionActive: boolean;
|
||||||
selection: SelectionRect | null;
|
selection: SelectionRect | null;
|
||||||
|
|
||||||
connectionSourceId: ElementId | null;
|
connectionSourceId: ElementId | null;
|
||||||
connectionPosition: XYPosition;
|
connectionPosition: XYPosition;
|
||||||
|
|
||||||
|
snapToGrid: boolean;
|
||||||
|
snapGrid: [number, number];
|
||||||
|
|
||||||
onConnect: OnConnectFunc;
|
onConnect: OnConnectFunc;
|
||||||
|
|
||||||
setOnConnect: Action<StoreModel, OnConnectFunc>;
|
setOnConnect: Action<StoreModel, OnConnectFunc>;
|
||||||
@@ -68,7 +88,7 @@ export interface StoreModel {
|
|||||||
|
|
||||||
setEdges: Action<StoreModel, Edge[]>;
|
setEdges: Action<StoreModel, Edge[]>;
|
||||||
|
|
||||||
updateNodeData: Action<StoreModel, NodeUpdate>;
|
updateNodeData: Action<StoreModel, NodeUpdate>;
|
||||||
|
|
||||||
updateNodePos: Action<StoreModel, NodePosUpdate>;
|
updateNodePos: Action<StoreModel, NodePosUpdate>;
|
||||||
|
|
||||||
@@ -76,7 +96,7 @@ export interface StoreModel {
|
|||||||
|
|
||||||
setNodesSelection: Action<StoreModel, SelectionUpdate>;
|
setNodesSelection: Action<StoreModel, SelectionUpdate>;
|
||||||
|
|
||||||
setSelectedElements: Action<StoreModel, Elements | Node | Edge>
|
setSelectedElements: Action<StoreModel, Elements | Node | Edge>;
|
||||||
|
|
||||||
updateSelection: Action<StoreModel, SelectionRect>;
|
updateSelection: Action<StoreModel, SelectionRect>;
|
||||||
|
|
||||||
@@ -86,10 +106,12 @@ export interface StoreModel {
|
|||||||
|
|
||||||
initD3: Action<StoreModel, D3Init>;
|
initD3: Action<StoreModel, D3Init>;
|
||||||
|
|
||||||
|
setSnapGrid: Action<StoreModel, SetSnapGrid>;
|
||||||
|
|
||||||
setConnectionPosition: Action<StoreModel, XYPosition>;
|
setConnectionPosition: Action<StoreModel, XYPosition>;
|
||||||
|
|
||||||
setConnectionSourceId: Action<StoreModel, ElementId>;
|
setConnectionSourceId: Action<StoreModel, ElementId | null>;
|
||||||
};
|
}
|
||||||
|
|
||||||
const storeModel: StoreModel = {
|
const storeModel: StoreModel = {
|
||||||
width: 0,
|
width: 0,
|
||||||
@@ -111,6 +133,9 @@ const storeModel: StoreModel = {
|
|||||||
connectionSourceId: null,
|
connectionSourceId: null,
|
||||||
connectionPosition: { x: 0, y: 0 },
|
connectionPosition: { x: 0, y: 0 },
|
||||||
|
|
||||||
|
snapGrid: [16, 16],
|
||||||
|
snapToGrid: true,
|
||||||
|
|
||||||
onConnect: () => {},
|
onConnect: () => {},
|
||||||
|
|
||||||
setOnConnect: action((state, onConnect) => {
|
setOnConnect: action((state, onConnect) => {
|
||||||
@@ -126,22 +151,34 @@ const storeModel: StoreModel = {
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
updateNodeData: action((state, { id, ...data }) => {
|
updateNodeData: action((state, { id, ...data }) => {
|
||||||
state.nodes.forEach((n) => {
|
state.nodes.forEach(n => {
|
||||||
if (n.id === id) {
|
if (n.id === id) {
|
||||||
n.__rg = {
|
n.__rg = {
|
||||||
...n.__rg,
|
...n.__rg,
|
||||||
...data
|
...data,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|
||||||
updateNodePos: action((state, { id, pos }) => {
|
updateNodePos: action((state, { id, pos }) => {
|
||||||
state.nodes.forEach((n) => {
|
let position: XYPosition = pos;
|
||||||
|
|
||||||
|
if (state.snapToGrid) {
|
||||||
|
const transformedGridSizeX = state.snapGrid[0] * state.transform[2];
|
||||||
|
const transformedGridSizeY = state.snapGrid[1] * state.transform[2];
|
||||||
|
|
||||||
|
position = {
|
||||||
|
x: transformedGridSizeX * Math.round(pos.x / transformedGridSizeX),
|
||||||
|
y: transformedGridSizeY * Math.round(pos.y / transformedGridSizeY),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
state.nodes.forEach(n => {
|
||||||
if (n.id === id) {
|
if (n.id === id) {
|
||||||
n.__rg = {
|
n.__rg = {
|
||||||
...n.__rg,
|
...n.__rg,
|
||||||
position: pos
|
position,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -152,13 +189,17 @@ const storeModel: StoreModel = {
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
setNodesSelection: action((state, { isActive, selection }) => {
|
setNodesSelection: action((state, { isActive, selection }) => {
|
||||||
if (!isActive) {
|
if (!isActive || typeof selection === 'undefined') {
|
||||||
state.nodesSelectionActive = false;
|
state.nodesSelectionActive = false;
|
||||||
state.selectedElements = [];
|
state.selectedElements = [];
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const selectedNodes = getNodesInside(state.nodes, selection, state.transform);
|
const selectedNodes = getNodesInside(
|
||||||
|
state.nodes,
|
||||||
|
selection,
|
||||||
|
state.transform
|
||||||
|
);
|
||||||
const selectedNodesBbox = getBoundingBox(selectedNodes);
|
const selectedNodesBbox = getBoundingBox(selectedNodes);
|
||||||
|
|
||||||
state.selection = selection;
|
state.selection = selection;
|
||||||
@@ -169,21 +210,35 @@ const storeModel: StoreModel = {
|
|||||||
|
|
||||||
setSelectedElements: action((state, elements) => {
|
setSelectedElements: action((state, elements) => {
|
||||||
const selectedElementsArr = Array.isArray(elements) ? elements : [elements];
|
const selectedElementsArr = Array.isArray(elements) ? elements : [elements];
|
||||||
const selectedElementsUpdated = !isEqual(selectedElementsArr, state.selectedElements);
|
const selectedElementsUpdated = !isEqual(
|
||||||
const selectedElements = selectedElementsUpdated ? selectedElementsArr : state.selectedElements;
|
selectedElementsArr,
|
||||||
|
state.selectedElements
|
||||||
|
);
|
||||||
|
const selectedElements = selectedElementsUpdated
|
||||||
|
? selectedElementsArr
|
||||||
|
: state.selectedElements;
|
||||||
|
|
||||||
state.selectedElements = selectedElements;
|
state.selectedElements = selectedElements;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
updateSelection: action((state, selection) => {
|
updateSelection: action((state, selection) => {
|
||||||
const selectedNodes = getNodesInside(state.nodes, selection, state.transform);
|
const selectedNodes = getNodesInside(
|
||||||
|
state.nodes,
|
||||||
|
selection,
|
||||||
|
state.transform
|
||||||
|
);
|
||||||
const selectedEdges = getConnectedEdges(selectedNodes, state.edges);
|
const selectedEdges = getConnectedEdges(selectedNodes, state.edges);
|
||||||
|
|
||||||
const nextSelectedElements = [...selectedNodes, ...selectedEdges];
|
const nextSelectedElements = [...selectedNodes, ...selectedEdges];
|
||||||
const selectedElementsUpdated = !isEqual(nextSelectedElements, state.selectedElements);
|
const selectedElementsUpdated = !isEqual(
|
||||||
|
nextSelectedElements,
|
||||||
|
state.selectedElements
|
||||||
|
);
|
||||||
|
|
||||||
state.selection = selection;
|
state.selection = selection;
|
||||||
state.selectedElements = selectedElementsUpdated ? nextSelectedElements: state.selectedElements
|
state.selectedElements = selectedElementsUpdated
|
||||||
|
? nextSelectedElements
|
||||||
|
: state.selectedElements;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
updateTransform: action((state, transform) => {
|
updateTransform: action((state, transform) => {
|
||||||
@@ -207,7 +262,12 @@ const storeModel: StoreModel = {
|
|||||||
|
|
||||||
setConnectionSourceId: action((state, sourceId) => {
|
setConnectionSourceId: action((state, sourceId) => {
|
||||||
state.connectionSourceId = sourceId;
|
state.connectionSourceId = sourceId;
|
||||||
})
|
}),
|
||||||
|
|
||||||
|
setSnapGrid: action((state, { snapToGrid, snapGrid }) => {
|
||||||
|
state.snapToGrid = snapToGrid;
|
||||||
|
state.snapGrid = snapGrid;
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const store = createStore(storeModel);
|
const store = createStore(storeModel);
|
||||||
|
|||||||
+61
-66
@@ -2,136 +2,131 @@ import { CSSProperties, SVGAttributes } from 'react';
|
|||||||
|
|
||||||
export type ElementId = string;
|
export type ElementId = string;
|
||||||
|
|
||||||
export type Elements = Array<Node | Edge>;
|
export type Elements = Array<Node | Edge>;
|
||||||
|
|
||||||
export type Transform = [number, number, number];
|
export type Transform = [number, number, number];
|
||||||
|
|
||||||
export type Position = 'left' | 'top' | 'right' | 'bottom';
|
export type Position = 'left' | 'top' | 'right' | 'bottom';
|
||||||
|
|
||||||
export type XYPosition = {
|
export type XYPosition = {
|
||||||
x: number,
|
x: number;
|
||||||
y: number
|
y: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum GridType {
|
export enum GridType {
|
||||||
Lines = 'lines',
|
Lines = 'lines',
|
||||||
Dots = 'dots',
|
Dots = 'dots',
|
||||||
};
|
}
|
||||||
|
|
||||||
export type HandleType = 'source' | 'target';
|
export type HandleType = 'source' | 'target';
|
||||||
|
|
||||||
export type NodeTypesType = { [key: string]: React.ReactNode };
|
export type NodeTypesType = { [key: string]: React.ReactNode };
|
||||||
|
|
||||||
export type EdgeTypesType = NodeTypesType;
|
export type EdgeTypesType = NodeTypesType;
|
||||||
|
|
||||||
export interface Dimensions {
|
export interface Dimensions {
|
||||||
width: number,
|
width: number;
|
||||||
height: number
|
height: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Rect extends Dimensions {
|
export interface Rect extends Dimensions {
|
||||||
x: number,
|
x: number;
|
||||||
y: number
|
y: number;
|
||||||
};
|
}
|
||||||
|
|
||||||
export interface SelectionRect extends Rect {
|
export interface SelectionRect extends Rect {
|
||||||
startX: number;
|
startX: number;
|
||||||
startY: number;
|
startY: number;
|
||||||
draw: boolean
|
draw: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
export interface Node {
|
export interface Node {
|
||||||
id: ElementId,
|
id: ElementId;
|
||||||
position?: XYPosition,
|
position: XYPosition;
|
||||||
type?: string,
|
type?: string;
|
||||||
__rg?: any,
|
__rg?: any;
|
||||||
data?: any,
|
data?: any;
|
||||||
style?: CSSProperties
|
style?: CSSProperties;
|
||||||
};
|
}
|
||||||
|
|
||||||
export interface Edge {
|
export interface Edge {
|
||||||
id: ElementId,
|
id: ElementId;
|
||||||
type?: string,
|
type?: string;
|
||||||
source: ElementId,
|
source: ElementId;
|
||||||
target: ElementId,
|
target: ElementId;
|
||||||
style?: SVGAttributes<{}>
|
style?: SVGAttributes<{}>;
|
||||||
animated?: boolean
|
animated?: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
export interface EdgeProps {
|
export interface EdgeProps {
|
||||||
sourceX: number,
|
sourceX: number;
|
||||||
sourceY: number,
|
sourceY: number;
|
||||||
targetX: number,
|
targetX: number;
|
||||||
targetY: number,
|
targetY: number;
|
||||||
style?: SVGAttributes<{}>
|
style?: SVGAttributes<{}>;
|
||||||
};
|
}
|
||||||
|
|
||||||
export interface EdgeBezierProps extends EdgeProps{
|
export interface EdgeBezierProps extends EdgeProps {
|
||||||
sourcePosition: Position,
|
sourcePosition: Position;
|
||||||
targetPosition: Position
|
targetPosition: Position;
|
||||||
};
|
}
|
||||||
|
|
||||||
export interface NodeProps {
|
export interface NodeProps {
|
||||||
id: ElementId,
|
id: ElementId;
|
||||||
type: string,
|
type: string;
|
||||||
data: any;
|
data: any;
|
||||||
selected: boolean;
|
selected: boolean;
|
||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
};
|
}
|
||||||
|
|
||||||
export interface NodeComponentProps {
|
export interface NodeComponentProps {
|
||||||
id: ElementId,
|
id: ElementId;
|
||||||
type: string;
|
type: string;
|
||||||
data: any;
|
data: any;
|
||||||
selected?: boolean;
|
selected?: boolean;
|
||||||
transform?: Transform;
|
transform?: Transform;
|
||||||
xPos?: number;
|
xPos?: number;
|
||||||
yPos?: number;
|
yPos?: number;
|
||||||
onClick?: () => any;
|
onClick?: (node: Node) => void | undefined;
|
||||||
onNodeDragStop?: () => any;
|
onNodeDragStop?: () => any;
|
||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type FitViewParams = {
|
export type FitViewParams = {
|
||||||
padding: number
|
padding: number;
|
||||||
};
|
};
|
||||||
export type FitViewFunc = (fitViewOptions: FitViewParams) => void;
|
export type FitViewFunc = (fitViewOptions: FitViewParams) => void;
|
||||||
|
|
||||||
type OnLoadParams = {
|
type OnLoadParams = {
|
||||||
zoomIn: () => void;
|
zoomIn: () => void;
|
||||||
zoomOut: () => void;
|
zoomOut: () => void;
|
||||||
fitView: FitViewFunc
|
fitView: FitViewFunc;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type OnLoadFunc = (params: OnLoadParams) => void;
|
export type OnLoadFunc = (params: OnLoadParams) => void;
|
||||||
|
|
||||||
export type OnConnectParams = {
|
|
||||||
source: ElementId;
|
|
||||||
target: ElementId;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type OnConnectFunc = (params: OnConnectParams) => void;
|
|
||||||
|
|
||||||
export type Connection = {
|
export type Connection = {
|
||||||
source: ElementId;
|
source: ElementId | null;
|
||||||
target: ElementId;
|
target: ElementId | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type OnConnectFunc = (params: Connection) => void;
|
||||||
|
|
||||||
export interface HandleElement {
|
export interface HandleElement {
|
||||||
id?: ElementId;
|
id?: ElementId | null;
|
||||||
position: Position;
|
position: Position;
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
};
|
}
|
||||||
|
|
||||||
export interface EdgeWrapperProps {
|
export interface EdgeCompProps {
|
||||||
id: ElementId,
|
id: ElementId;
|
||||||
source: ElementId,
|
source: ElementId;
|
||||||
target: ElementId,
|
target: ElementId;
|
||||||
type: any,
|
type: any;
|
||||||
onClick?: (edge: Edge) => void
|
onClick?: (edge: Edge) => void;
|
||||||
animated?: boolean,
|
animated?: boolean;
|
||||||
selected?: boolean,
|
selected?: boolean;
|
||||||
};
|
}
|
||||||
|
|||||||
+127
-70
@@ -1,9 +1,18 @@
|
|||||||
import { zoomIdentity } from 'd3-zoom';
|
import { zoomIdentity } from 'd3-zoom';
|
||||||
|
|
||||||
import store from '../store';
|
import store from '../store';
|
||||||
import { ElementId, Node, Edge, Elements, Transform, XYPosition, Rect, FitViewParams } from '../types';
|
import {
|
||||||
|
ElementId,
|
||||||
|
Node,
|
||||||
|
Edge,
|
||||||
|
Elements,
|
||||||
|
Transform,
|
||||||
|
XYPosition,
|
||||||
|
Rect,
|
||||||
|
FitViewParams,
|
||||||
|
} from '../types';
|
||||||
|
|
||||||
export const isEdge = (element: Node | Edge): boolean =>
|
export const isEdge = (element: Node | Edge): boolean =>
|
||||||
element.hasOwnProperty('source') && element.hasOwnProperty('target');
|
element.hasOwnProperty('source') && element.hasOwnProperty('target');
|
||||||
|
|
||||||
export const isNode = (element: Node | Edge): boolean =>
|
export const isNode = (element: Node | Edge): boolean =>
|
||||||
@@ -14,14 +23,19 @@ export const getOutgoers = (node: Node, elements: Elements): Elements => {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const outgoerIds = elements.filter((e: Edge) => e.source === node.id).map((e: Edge) => e.target);
|
const outgoerIds = (elements as Edge[])
|
||||||
|
.filter(e => e.source === node.id)
|
||||||
|
.map(e => e.target);
|
||||||
return elements.filter(e => outgoerIds.includes(e.id));
|
return elements.filter(e => outgoerIds.includes(e.id));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const removeElements = (elementsToRemove: Elements, elements: Elements): Elements => {
|
export const removeElements = (
|
||||||
|
elementsToRemove: Elements,
|
||||||
|
elements: Elements
|
||||||
|
): Elements => {
|
||||||
const nodeIdsToRemove = elementsToRemove.map(n => n.id);
|
const nodeIdsToRemove = elementsToRemove.map(n => n.id);
|
||||||
|
|
||||||
return elements.filter((element) => {
|
return elements.filter(element => {
|
||||||
const edgeElement = element as Edge;
|
const edgeElement = element as Edge;
|
||||||
return !(
|
return !(
|
||||||
nodeIdsToRemove.includes(element.id) ||
|
nodeIdsToRemove.includes(element.id) ||
|
||||||
@@ -36,36 +50,45 @@ function getEdgeId(edgeParams: Edge): ElementId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const addEdge = (edgeParams: Edge, elements: Elements): Elements => {
|
export const addEdge = (edgeParams: Edge, elements: Elements): Elements => {
|
||||||
if (!edgeParams.source || !edgeParams.target) {
|
if (!edgeParams.source || !edgeParams.target) {
|
||||||
throw new Error('Can not create edge. An edge needs a source and a target');
|
throw new Error('Can not create edge. An edge needs a source and a target');
|
||||||
}
|
}
|
||||||
|
|
||||||
return elements.concat({
|
return elements.concat({
|
||||||
...edgeParams,
|
...edgeParams,
|
||||||
id: typeof edgeParams.id !== 'undefined' ? edgeParams.id : getEdgeId(edgeParams)
|
id:
|
||||||
|
typeof edgeParams.id !== 'undefined'
|
||||||
|
? edgeParams.id
|
||||||
|
: getEdgeId(edgeParams),
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const pointToRendererPoint = ({ x, y }: XYPosition, transform: Transform): XYPosition => {
|
const pointToRendererPoint = (
|
||||||
|
{ x, y }: XYPosition,
|
||||||
|
transform: Transform
|
||||||
|
): XYPosition => {
|
||||||
const rendererX = (x - transform[0]) * (1 / transform[2]);
|
const rendererX = (x - transform[0]) * (1 / transform[2]);
|
||||||
const rendererY = (y - transform[1]) * (1 / transform[2]);
|
const rendererY = (y - transform[1]) * (1 / transform[2]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
x: rendererX,
|
x: rendererX,
|
||||||
y: rendererY
|
y: rendererY,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const parseElement = (element: Node | Edge, transform?: Transform): Node | Edge => {
|
export const parseElement = (
|
||||||
|
element: Node | Edge,
|
||||||
|
transform: Transform = [0, 0, 1]
|
||||||
|
): Node | Edge => {
|
||||||
if (!element.id) {
|
if (!element.id) {
|
||||||
throw new Error('All elements (nodes and edges) need to have an id.',)
|
throw new Error('All elements (nodes and edges) need to have an id.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isEdge(element)) {
|
if (isEdge(element)) {
|
||||||
return {
|
return {
|
||||||
...element,
|
...element,
|
||||||
id: element.id.toString(),
|
id: element.id.toString(),
|
||||||
type: element.type || 'default'
|
type: element.type || 'default',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,76 +102,88 @@ export const parseElement = (element: Node | Edge, transform?: Transform): Node
|
|||||||
position: pointToRendererPoint(nodeElement.position, transform),
|
position: pointToRendererPoint(nodeElement.position, transform),
|
||||||
width: null,
|
width: null,
|
||||||
height: null,
|
height: null,
|
||||||
handleBounds : {}
|
handleBounds: {},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getBoundingBox = (nodes: Node[]): Rect => {
|
export const getBoundingBox = (nodes: Node[]): Rect => {
|
||||||
const bbox = nodes.reduce((res, node) => {
|
const bbox = nodes.reduce(
|
||||||
const { position } = node.__rg;
|
(res, node) => {
|
||||||
const x2 = position.x + node.__rg.width;
|
const { position } = node.__rg;
|
||||||
const y2 = position.y + node.__rg.height;
|
const x2 = position.x + node.__rg.width;
|
||||||
|
const y2 = position.y + node.__rg.height;
|
||||||
|
|
||||||
if (position.x < res.minX) {
|
if (position.x < res.minX) {
|
||||||
res.minX = position.x;
|
res.minX = position.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x2 > res.maxX) {
|
||||||
|
res.maxX = x2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (position.y < res.minY) {
|
||||||
|
res.minY = position.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y2 > res.maxY) {
|
||||||
|
res.maxY = y2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
minX: Number.MAX_VALUE,
|
||||||
|
minY: Number.MAX_VALUE,
|
||||||
|
maxX: 0,
|
||||||
|
maxY: 0,
|
||||||
}
|
}
|
||||||
|
);
|
||||||
if (x2 > res.maxX) {
|
|
||||||
res.maxX = x2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (position.y < res.minY) {
|
|
||||||
res.minY = position.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (y2 > res.maxY) {
|
|
||||||
res.maxY = y2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}, {
|
|
||||||
minX: Number.MAX_VALUE,
|
|
||||||
minY: Number.MAX_VALUE,
|
|
||||||
maxX: 0,
|
|
||||||
maxY: 0
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
x: bbox.minX,
|
x: bbox.minX,
|
||||||
y: bbox.minY,
|
y: bbox.minY,
|
||||||
width: bbox.maxX - bbox.minX,
|
width: bbox.maxX - bbox.minX,
|
||||||
height: bbox.maxY - bbox.minY
|
height: bbox.maxY - bbox.minY,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const graphPosToZoomedPos = (pos: XYPosition, transform: Transform): XYPosition => {
|
export const graphPosToZoomedPos = (
|
||||||
|
pos: XYPosition,
|
||||||
|
transform: Transform
|
||||||
|
): XYPosition => {
|
||||||
return {
|
return {
|
||||||
x: (pos.x * transform[2]) + transform[0],
|
x: pos.x * transform[2] + transform[0],
|
||||||
y: (pos.y * transform[2]) + transform[1]
|
y: pos.y * transform[2] + transform[1],
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export const getNodesInside = (nodes: Node[], bbox: Rect, transform: Transform = [0, 0, 1], partially: boolean = false): Node[] => {
|
export const getNodesInside = (
|
||||||
return nodes
|
nodes: Node[],
|
||||||
.filter(n => {
|
bbox: Rect,
|
||||||
const bboxPos = {
|
transform: Transform = [0, 0, 1],
|
||||||
x: (bbox.x - transform[0]) * (1 / transform[2]),
|
partially: boolean = false
|
||||||
y: (bbox.y - transform[1]) * (1 / transform[2])
|
): Node[] => {
|
||||||
};
|
return nodes.filter(n => {
|
||||||
const bboxWidth = bbox.width * (1 / transform[2]);
|
const bboxPos = {
|
||||||
const bboxHeight = bbox.height * (1 / transform[2]);
|
x: (bbox.x - transform[0]) * (1 / transform[2]),
|
||||||
const { position, width, height } = n.__rg;
|
y: (bbox.y - transform[1]) * (1 / transform[2]),
|
||||||
const nodeWidth = partially ? -width : width;
|
};
|
||||||
const nodeHeight = partially ? 0 : height;
|
const bboxWidth = bbox.width * (1 / transform[2]);
|
||||||
const offsetX = partially ? width : 0;
|
const bboxHeight = bbox.height * (1 / transform[2]);
|
||||||
const offsetY = partially ? height : 0;
|
const { position, width, height } = n.__rg;
|
||||||
|
const nodeWidth = partially ? -width : width;
|
||||||
|
const nodeHeight = partially ? 0 : height;
|
||||||
|
const offsetX = partially ? width : 0;
|
||||||
|
const offsetY = partially ? height : 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
(position.x + offsetX > bboxPos.x && (position.x + nodeWidth) < (bboxPos.x + bboxWidth)) &&
|
position.x + offsetX > bboxPos.x &&
|
||||||
(position.y + offsetY > bboxPos.y && (position.y + nodeHeight) < (bboxPos.y + bboxHeight))
|
position.x + nodeWidth < bboxPos.x + bboxWidth &&
|
||||||
);
|
(position.y + offsetY > bboxPos.y &&
|
||||||
});
|
position.y + nodeHeight < bboxPos.y + bboxHeight)
|
||||||
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getConnectedEdges = (nodes: Node[], edges: Edge[]): Edge[] => {
|
export const getConnectedEdges = (nodes: Node[], edges: Edge[]): Edge[] => {
|
||||||
@@ -167,23 +202,45 @@ export const getConnectedEdges = (nodes: Node[], edges: Edge[]): Edge[] => {
|
|||||||
|
|
||||||
export const fitView = ({ padding }: FitViewParams = { padding: 0 }): void => {
|
export const fitView = ({ padding }: FitViewParams = { padding: 0 }): void => {
|
||||||
const state = store.getState();
|
const state = store.getState();
|
||||||
|
|
||||||
|
if (!state.d3Selection || !state.d3Zoom) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const bounds = getBoundingBox(state.nodes);
|
const bounds = getBoundingBox(state.nodes);
|
||||||
const maxBoundsSize = Math.max(bounds.width, bounds.height);
|
const maxBoundsSize = Math.max(bounds.width, bounds.height);
|
||||||
const k = Math.min(state.width, state.height) / (maxBoundsSize + (maxBoundsSize * padding));
|
const k =
|
||||||
const boundsCenterX = bounds.x + (bounds.width / 2);
|
Math.min(state.width, state.height) /
|
||||||
const boundsCenterY = bounds.y + (bounds.height / 2);
|
(maxBoundsSize + maxBoundsSize * padding);
|
||||||
const transform = [(state.width / 2) - (boundsCenterX * k), (state.height / 2) - (boundsCenterY * k)];
|
const boundsCenterX = bounds.x + bounds.width / 2;
|
||||||
const fittedTransform = zoomIdentity.translate(transform[0], transform[1]).scale(k);
|
const boundsCenterY = bounds.y + bounds.height / 2;
|
||||||
|
const transform = [
|
||||||
|
state.width / 2 - boundsCenterX * k,
|
||||||
|
state.height / 2 - boundsCenterY * k,
|
||||||
|
];
|
||||||
|
const fittedTransform = zoomIdentity
|
||||||
|
.translate(transform[0], transform[1])
|
||||||
|
.scale(k);
|
||||||
|
|
||||||
state.d3Selection.call(state.d3Zoom.transform, fittedTransform);
|
state.d3Selection.call(state.d3Zoom.transform, fittedTransform);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const zoomIn = (): void => {
|
export const zoomIn = (): void => {
|
||||||
const state = store.getState();
|
const state = store.getState();
|
||||||
|
|
||||||
|
if (!state.d3Zoom || !state.d3Selection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
state.d3Zoom.scaleTo(state.d3Selection, state.transform[2] + 0.2);
|
state.d3Zoom.scaleTo(state.d3Selection, state.transform[2] + 0.2);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const zoomOut = (): void => {
|
export const zoomOut = (): void => {
|
||||||
const state = store.getState();
|
const state = store.getState();
|
||||||
|
|
||||||
|
if (!state.d3Zoom || !state.d3Selection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
state.d3Zoom.scaleTo(state.d3Selection, state.transform[2] - 0.2);
|
state.d3Zoom.scaleTo(state.d3Selection, state.transform[2] - 0.2);
|
||||||
};
|
};
|
||||||
|
|||||||
+7
-3
@@ -1,12 +1,16 @@
|
|||||||
import { DraggableEvent } from 'react-draggable';
|
import { DraggableEvent } from 'react-draggable';
|
||||||
import { MouseEvent as ReactMouseEvent } from 'react';
|
import { MouseEvent as ReactMouseEvent } from 'react';
|
||||||
|
|
||||||
export const isInputDOMNode = (e: ReactMouseEvent | DraggableEvent | KeyboardEvent) => {
|
export const isInputDOMNode = (
|
||||||
|
e: ReactMouseEvent | DraggableEvent | KeyboardEvent
|
||||||
|
) => {
|
||||||
const target = e.target as HTMLElement;
|
const target = e.target as HTMLElement;
|
||||||
return e && target && ['INPUT', 'SELECT', 'TEXTAREA'].includes(target.nodeName);
|
return (
|
||||||
|
e && target && ['INPUT', 'SELECT', 'TEXTAREA'].includes(target.nodeName)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDimensions = (node: HTMLDivElement) => ({
|
export const getDimensions = (node: HTMLDivElement) => ({
|
||||||
width: node.offsetWidth,
|
width: node.offsetWidth,
|
||||||
height: node.offsetHeight
|
height: node.offsetHeight,
|
||||||
});
|
});
|
||||||
|
|||||||
+11
-4
@@ -6,13 +6,20 @@
|
|||||||
"lib": ["es6", "dom", "es2016", "es2017"],
|
"lib": ["es6", "dom", "es2016", "es2017"],
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"forceConsistentCasingInFileNames": true,
|
"declaration": true,
|
||||||
"strictNullChecks": false,
|
"strict": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"strictFunctionTypes": true,
|
||||||
|
"strictPropertyInitialization": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"alwaysStrict": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"noImplicitAny": true,
|
"esModuleInterop": true
|
||||||
"suppressImplicitAnyIndexErrors": true
|
|
||||||
},
|
},
|
||||||
"include": ["src"],
|
"include": ["src"],
|
||||||
"exclude": ["node_modules", "build", "dist", "example", "rollup.config.js"]
|
"exclude": ["node_modules", "build", "dist", "example", "rollup.config.js"]
|
||||||
|
|||||||
Reference in New Issue
Block a user