@xyflow/system 0.0.29 → 0.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.js +281 -230
- package/dist/esm/index.mjs +282 -230
- package/dist/esm/types/general.d.ts +30 -11
- package/dist/esm/types/general.d.ts.map +1 -1
- package/dist/esm/types/handles.d.ts +4 -15
- package/dist/esm/types/handles.d.ts.map +1 -1
- package/dist/esm/types/nodes.d.ts +6 -5
- package/dist/esm/types/nodes.d.ts.map +1 -1
- package/dist/esm/types/utils.d.ts +6 -0
- package/dist/esm/types/utils.d.ts.map +1 -1
- package/dist/esm/utils/connections.d.ts +1 -0
- package/dist/esm/utils/connections.d.ts.map +1 -1
- package/dist/esm/utils/dom.d.ts +2 -2
- package/dist/esm/utils/dom.d.ts.map +1 -1
- package/dist/esm/utils/edges/general.d.ts +3 -3
- package/dist/esm/utils/edges/general.d.ts.map +1 -1
- package/dist/esm/utils/edges/positions.d.ts +3 -0
- package/dist/esm/utils/edges/positions.d.ts.map +1 -1
- package/dist/esm/utils/general.d.ts +4 -8
- package/dist/esm/utils/general.d.ts.map +1 -1
- package/dist/esm/utils/graph.d.ts +3 -7
- package/dist/esm/utils/graph.d.ts.map +1 -1
- package/dist/esm/utils/store.d.ts +2 -2
- package/dist/esm/utils/store.d.ts.map +1 -1
- package/dist/esm/xydrag/XYDrag.d.ts.map +1 -1
- package/dist/esm/xyhandle/XYHandle.d.ts +1 -46
- package/dist/esm/xyhandle/XYHandle.d.ts.map +1 -1
- package/dist/esm/xyhandle/types.d.ts +47 -0
- package/dist/esm/xyhandle/types.d.ts.map +1 -0
- package/dist/esm/xyhandle/utils.d.ts +5 -6
- package/dist/esm/xyhandle/utils.d.ts.map +1 -1
- package/dist/esm/xyminimap/index.d.ts.map +1 -1
- package/dist/esm/xyresizer/XYResizer.d.ts.map +1 -1
- package/dist/umd/index.js +1 -1
- package/dist/umd/types/general.d.ts +30 -11
- package/dist/umd/types/general.d.ts.map +1 -1
- package/dist/umd/types/handles.d.ts +4 -15
- package/dist/umd/types/handles.d.ts.map +1 -1
- package/dist/umd/types/nodes.d.ts +6 -5
- package/dist/umd/types/nodes.d.ts.map +1 -1
- package/dist/umd/types/utils.d.ts +6 -0
- package/dist/umd/types/utils.d.ts.map +1 -1
- package/dist/umd/utils/connections.d.ts +1 -0
- package/dist/umd/utils/connections.d.ts.map +1 -1
- package/dist/umd/utils/dom.d.ts +2 -2
- package/dist/umd/utils/dom.d.ts.map +1 -1
- package/dist/umd/utils/edges/general.d.ts +3 -3
- package/dist/umd/utils/edges/general.d.ts.map +1 -1
- package/dist/umd/utils/edges/positions.d.ts +3 -0
- package/dist/umd/utils/edges/positions.d.ts.map +1 -1
- package/dist/umd/utils/general.d.ts +4 -8
- package/dist/umd/utils/general.d.ts.map +1 -1
- package/dist/umd/utils/graph.d.ts +3 -7
- package/dist/umd/utils/graph.d.ts.map +1 -1
- package/dist/umd/utils/store.d.ts +2 -2
- package/dist/umd/utils/store.d.ts.map +1 -1
- package/dist/umd/xydrag/XYDrag.d.ts.map +1 -1
- package/dist/umd/xyhandle/XYHandle.d.ts +1 -46
- package/dist/umd/xyhandle/XYHandle.d.ts.map +1 -1
- package/dist/umd/xyhandle/types.d.ts +47 -0
- package/dist/umd/xyhandle/types.d.ts.map +1 -0
- package/dist/umd/xyhandle/utils.d.ts +5 -6
- package/dist/umd/xyhandle/utils.d.ts.map +1 -1
- package/dist/umd/xyminimap/index.d.ts.map +1 -1
- package/dist/umd/xyresizer/XYResizer.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/esm/index.js
CHANGED
|
@@ -39,6 +39,18 @@ var SelectionMode;
|
|
|
39
39
|
SelectionMode["Partial"] = "partial";
|
|
40
40
|
SelectionMode["Full"] = "full";
|
|
41
41
|
})(SelectionMode || (SelectionMode = {}));
|
|
42
|
+
const initialConnection = {
|
|
43
|
+
inProgress: false,
|
|
44
|
+
isValid: null,
|
|
45
|
+
from: null,
|
|
46
|
+
fromHandle: null,
|
|
47
|
+
fromPosition: null,
|
|
48
|
+
fromNode: null,
|
|
49
|
+
to: null,
|
|
50
|
+
toHandle: null,
|
|
51
|
+
toPosition: null,
|
|
52
|
+
toNode: null,
|
|
53
|
+
};
|
|
42
54
|
|
|
43
55
|
var ConnectionLineType;
|
|
44
56
|
(function (ConnectionLineType) {
|
|
@@ -61,6 +73,12 @@ var Position;
|
|
|
61
73
|
Position["Right"] = "right";
|
|
62
74
|
Position["Bottom"] = "bottom";
|
|
63
75
|
})(Position || (Position = {}));
|
|
76
|
+
const oppositePosition = {
|
|
77
|
+
[Position.Left]: Position.Right,
|
|
78
|
+
[Position.Right]: Position.Left,
|
|
79
|
+
[Position.Top]: Position.Bottom,
|
|
80
|
+
[Position.Bottom]: Position.Top,
|
|
81
|
+
};
|
|
64
82
|
|
|
65
83
|
/**
|
|
66
84
|
* @internal
|
|
@@ -101,6 +119,9 @@ function handleConnectionChange(a, b, cb) {
|
|
|
101
119
|
cb(diff);
|
|
102
120
|
}
|
|
103
121
|
}
|
|
122
|
+
function getConnectionStatus(isValid) {
|
|
123
|
+
return isValid === null ? null : isValid ? 'valid' : 'invalid';
|
|
124
|
+
}
|
|
104
125
|
|
|
105
126
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
106
127
|
/**
|
|
@@ -162,19 +183,12 @@ const getIncomers = (node, nodes, edges) => {
|
|
|
162
183
|
};
|
|
163
184
|
const getNodePositionWithOrigin = (node, nodeOrigin = [0, 0]) => {
|
|
164
185
|
const { width, height } = getNodeDimensions(node);
|
|
165
|
-
const
|
|
166
|
-
const origin = node.origin || nodeOrigin;
|
|
186
|
+
const origin = node.origin ?? nodeOrigin;
|
|
167
187
|
const offsetX = width * origin[0];
|
|
168
188
|
const offsetY = height * origin[1];
|
|
169
189
|
return {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
y: node.position.y - offsetY,
|
|
173
|
-
},
|
|
174
|
-
positionAbsolute: {
|
|
175
|
-
x: positionAbsolute.x - offsetX,
|
|
176
|
-
y: positionAbsolute.y - offsetY,
|
|
177
|
-
},
|
|
190
|
+
x: node.position.x - offsetX,
|
|
191
|
+
y: node.position.y - offsetY,
|
|
178
192
|
};
|
|
179
193
|
};
|
|
180
194
|
/**
|
|
@@ -199,16 +213,14 @@ const getNodesBounds = (nodes, params = { nodeOrigin: [0, 0] }) => {
|
|
|
199
213
|
* Determines a bounding box that contains all given nodes in an array
|
|
200
214
|
* @internal
|
|
201
215
|
*/
|
|
202
|
-
const getInternalNodesBounds = (nodeLookup, params = {
|
|
203
|
-
nodeOrigin: [0, 0],
|
|
204
|
-
}) => {
|
|
216
|
+
const getInternalNodesBounds = (nodeLookup, params = {}) => {
|
|
205
217
|
if (nodeLookup.size === 0) {
|
|
206
218
|
return { x: 0, y: 0, width: 0, height: 0 };
|
|
207
219
|
}
|
|
208
220
|
let box = { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity };
|
|
209
221
|
nodeLookup.forEach((node) => {
|
|
210
|
-
if (params.filter
|
|
211
|
-
const nodeBox = nodeToBox(node
|
|
222
|
+
if (params.filter === undefined || params.filter(node)) {
|
|
223
|
+
const nodeBox = nodeToBox(node);
|
|
212
224
|
box = getBoundsOfBoxes(box, nodeBox);
|
|
213
225
|
}
|
|
214
226
|
});
|
|
@@ -216,7 +228,7 @@ const getInternalNodesBounds = (nodeLookup, params = {
|
|
|
216
228
|
};
|
|
217
229
|
const getNodesInside = (nodes, rect, [tx, ty, tScale] = [0, 0, 1], partially = false,
|
|
218
230
|
// set excludeNonSelectableNodes if you want to pay attention to the nodes "selectable" attribute
|
|
219
|
-
excludeNonSelectableNodes = false
|
|
231
|
+
excludeNonSelectableNodes = false) => {
|
|
220
232
|
const paneRect = {
|
|
221
233
|
...pointToRendererPoint(rect, [tx, ty, tScale]),
|
|
222
234
|
width: rect.width / tScale,
|
|
@@ -230,7 +242,7 @@ excludeNonSelectableNodes = false, nodeOrigin = [0, 0]) => {
|
|
|
230
242
|
if ((excludeNonSelectableNodes && !selectable) || hidden) {
|
|
231
243
|
continue;
|
|
232
244
|
}
|
|
233
|
-
const overlappingArea = getOverlappingArea(paneRect, nodeToRect(node
|
|
245
|
+
const overlappingArea = getOverlappingArea(paneRect, nodeToRect(node));
|
|
234
246
|
const notInitialized = width === null || height === null;
|
|
235
247
|
const partiallyVisible = partially && overlappingArea > 0;
|
|
236
248
|
const area = (width ?? 0) * (height ?? 0);
|
|
@@ -254,17 +266,17 @@ const getConnectedEdges = (nodes, edges) => {
|
|
|
254
266
|
});
|
|
255
267
|
return edges.filter((edge) => nodeIds.has(edge.source) || nodeIds.has(edge.target));
|
|
256
268
|
};
|
|
257
|
-
function fitView({ nodeLookup, width, height, panZoom, minZoom, maxZoom
|
|
258
|
-
const filteredNodes =
|
|
269
|
+
function fitView({ nodeLookup, width, height, panZoom, minZoom, maxZoom }, options) {
|
|
270
|
+
const filteredNodes = new Map();
|
|
259
271
|
const optionNodeIds = options?.nodes ? new Set(options.nodes.map((node) => node.id)) : null;
|
|
260
272
|
nodeLookup.forEach((n) => {
|
|
261
273
|
const isVisible = n.measured.width && n.measured.height && (options?.includeHiddenNodes || !n.hidden);
|
|
262
274
|
if (isVisible && (!optionNodeIds || optionNodeIds.has(n.id))) {
|
|
263
|
-
filteredNodes.
|
|
275
|
+
filteredNodes.set(n.id, n);
|
|
264
276
|
}
|
|
265
277
|
});
|
|
266
|
-
if (filteredNodes.
|
|
267
|
-
const bounds =
|
|
278
|
+
if (filteredNodes.size > 0) {
|
|
279
|
+
const bounds = getInternalNodesBounds(filteredNodes);
|
|
268
280
|
const viewport = getViewportForBounds(bounds, width, height, options?.minZoom ?? minZoom, options?.maxZoom ?? maxZoom, options?.padding ?? 0.1);
|
|
269
281
|
panZoom.setViewport(viewport, { duration: options?.duration });
|
|
270
282
|
return true;
|
|
@@ -294,9 +306,8 @@ function clampNodeExtent(node, extent) {
|
|
|
294
306
|
function calculateNodePosition({ nodeId, nextPosition, nodeLookup, nodeOrigin = [0, 0], nodeExtent, onError, }) {
|
|
295
307
|
const node = nodeLookup.get(nodeId);
|
|
296
308
|
const parentNode = node.parentId ? nodeLookup.get(node.parentId) : undefined;
|
|
297
|
-
const { x: parentX, y: parentY } = parentNode
|
|
298
|
-
|
|
299
|
-
: { x: 0, y: 0 };
|
|
309
|
+
const { x: parentX, y: parentY } = parentNode ? parentNode.internals.positionAbsolute : { x: 0, y: 0 };
|
|
310
|
+
const origin = node.origin ?? nodeOrigin;
|
|
300
311
|
let currentExtent = clampNodeExtent(node, node.extent || nodeExtent);
|
|
301
312
|
if (node.extent === 'parent' && !node.expandParent) {
|
|
302
313
|
if (!parentNode) {
|
|
@@ -308,12 +319,9 @@ function calculateNodePosition({ nodeId, nextPosition, nodeLookup, nodeOrigin =
|
|
|
308
319
|
const parentWidth = parentNode.measured.width;
|
|
309
320
|
const parentHeight = parentNode.measured.height;
|
|
310
321
|
if (nodeWidth && nodeHeight && parentWidth && parentHeight) {
|
|
311
|
-
const currNodeOrigin = node.origin || nodeOrigin;
|
|
312
|
-
const extentX = parentX + nodeWidth * currNodeOrigin[0];
|
|
313
|
-
const extentY = parentY + nodeHeight * currNodeOrigin[1];
|
|
314
322
|
currentExtent = [
|
|
315
|
-
[
|
|
316
|
-
[
|
|
323
|
+
[parentX, parentY],
|
|
324
|
+
[parentX + parentWidth - nodeWidth, parentY + parentHeight - nodeHeight],
|
|
317
325
|
];
|
|
318
326
|
}
|
|
319
327
|
}
|
|
@@ -329,8 +337,9 @@ function calculateNodePosition({ nodeId, nextPosition, nodeLookup, nodeOrigin =
|
|
|
329
337
|
: nextPosition;
|
|
330
338
|
return {
|
|
331
339
|
position: {
|
|
332
|
-
|
|
333
|
-
|
|
340
|
+
// TODO: is there a better way to do this?
|
|
341
|
+
x: positionAbsolute.x - parentX + node.measured.width * origin[0],
|
|
342
|
+
y: positionAbsolute.y - parentY + node.measured.height * origin[1],
|
|
334
343
|
},
|
|
335
344
|
positionAbsolute,
|
|
336
345
|
};
|
|
@@ -430,21 +439,25 @@ const boxToRect = ({ x, y, x2, y2 }) => ({
|
|
|
430
439
|
height: y2 - y,
|
|
431
440
|
});
|
|
432
441
|
const nodeToRect = (node, nodeOrigin = [0, 0]) => {
|
|
433
|
-
const { x, y } =
|
|
442
|
+
const { x, y } = isInternalNodeBase(node)
|
|
443
|
+
? node.internals.positionAbsolute
|
|
444
|
+
: getNodePositionWithOrigin(node, nodeOrigin);
|
|
434
445
|
return {
|
|
435
446
|
x,
|
|
436
447
|
y,
|
|
437
|
-
width: node.measured?.width ?? node.width ?? 0,
|
|
438
|
-
height: node.measured?.height ?? node.height ?? 0,
|
|
448
|
+
width: node.measured?.width ?? node.width ?? node.initialWidth ?? 0,
|
|
449
|
+
height: node.measured?.height ?? node.height ?? node.initialHeight ?? 0,
|
|
439
450
|
};
|
|
440
451
|
};
|
|
441
452
|
const nodeToBox = (node, nodeOrigin = [0, 0]) => {
|
|
442
|
-
const { x, y } =
|
|
453
|
+
const { x, y } = isInternalNodeBase(node)
|
|
454
|
+
? node.internals.positionAbsolute
|
|
455
|
+
: getNodePositionWithOrigin(node, nodeOrigin);
|
|
443
456
|
return {
|
|
444
457
|
x,
|
|
445
458
|
y,
|
|
446
|
-
x2: x + (node.measured?.width ?? node.width ?? 0),
|
|
447
|
-
y2: y + (node.measured?.height ?? node.height ?? 0),
|
|
459
|
+
x2: x + (node.measured?.width ?? node.width ?? node.initialWidth ?? 0),
|
|
460
|
+
y2: y + (node.measured?.height ?? node.height ?? node.initialHeight ?? 0),
|
|
448
461
|
};
|
|
449
462
|
};
|
|
450
463
|
const getBoundsOfRects = (rect1, rect2) => boxToRect(getBoundsOfBoxes(rectToBox(rect1), rectToBox(rect2)));
|
|
@@ -463,15 +476,6 @@ const devWarn = (id, message) => {
|
|
|
463
476
|
console.warn(`[React Flow]: ${message} Help: https://reactflow.dev/error#${id}`);
|
|
464
477
|
}
|
|
465
478
|
};
|
|
466
|
-
const getPositionWithOrigin = ({ x, y, width, height, origin = [0, 0], }) => {
|
|
467
|
-
if (!width || !height || origin[0] < 0 || origin[1] < 0 || origin[0] > 1 || origin[1] > 1) {
|
|
468
|
-
return { x, y };
|
|
469
|
-
}
|
|
470
|
-
return {
|
|
471
|
-
x: x - width * origin[0],
|
|
472
|
-
y: y - height * origin[1],
|
|
473
|
-
};
|
|
474
|
-
};
|
|
475
479
|
const snapPosition = (position, snapGrid = [1, 1]) => {
|
|
476
480
|
return {
|
|
477
481
|
x: snapGrid[0] * Math.round(position.x / snapGrid[0]),
|
|
@@ -542,7 +546,7 @@ function nodeHasDimensions(node) {
|
|
|
542
546
|
* @param nodeOrigin
|
|
543
547
|
* @returns an internal node with an absolute position
|
|
544
548
|
*/
|
|
545
|
-
function evaluateAbsolutePosition(position,
|
|
549
|
+
function evaluateAbsolutePosition(position, dimensions = { width: 0, height: 0 }, parentId, nodeLookup, nodeOrigin) {
|
|
546
550
|
let nextParentId = parentId;
|
|
547
551
|
const positionAbsolute = { ...position };
|
|
548
552
|
while (nextParentId) {
|
|
@@ -550,10 +554,8 @@ function evaluateAbsolutePosition(position, parentId, nodeLookup, nodeOrigin = [
|
|
|
550
554
|
nextParentId = parent?.parentId;
|
|
551
555
|
if (parent) {
|
|
552
556
|
const origin = parent.origin || nodeOrigin;
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
positionAbsolute.x += parent.position.x - xOffset;
|
|
556
|
-
positionAbsolute.y += parent.position.y - yOffset;
|
|
557
|
+
positionAbsolute.x += parent.internals.positionAbsolute.x - (dimensions.width ?? 0) * origin[0];
|
|
558
|
+
positionAbsolute.y += parent.internals.positionAbsolute.y - (dimensions.height ?? 0) * origin[1];
|
|
557
559
|
}
|
|
558
560
|
}
|
|
559
561
|
return positionAbsolute;
|
|
@@ -596,23 +598,20 @@ const getEventPosition = (event, bounds) => {
|
|
|
596
598
|
// The handle bounds are calculated relative to the node element.
|
|
597
599
|
// We store them in the internals object of the node in order to avoid
|
|
598
600
|
// unnecessary recalculations.
|
|
599
|
-
const getHandleBounds = (
|
|
600
|
-
const handles = nodeElement.querySelectorAll(
|
|
601
|
+
const getHandleBounds = (type, nodeElement, nodeBounds, zoom, nodeId) => {
|
|
602
|
+
const handles = nodeElement.querySelectorAll(`.${type}`);
|
|
601
603
|
if (!handles || !handles.length) {
|
|
602
604
|
return null;
|
|
603
605
|
}
|
|
604
|
-
|
|
605
|
-
const nodeOffset = {
|
|
606
|
-
x: nodeBounds.left + nodeBounds.width * nodeOrigin[0],
|
|
607
|
-
y: nodeBounds.top + nodeBounds.height * nodeOrigin[1],
|
|
608
|
-
};
|
|
609
|
-
return handlesArray.map((handle) => {
|
|
606
|
+
return Array.from(handles).map((handle) => {
|
|
610
607
|
const handleBounds = handle.getBoundingClientRect();
|
|
611
608
|
return {
|
|
612
609
|
id: handle.getAttribute('data-handleid'),
|
|
610
|
+
type,
|
|
611
|
+
nodeId,
|
|
613
612
|
position: handle.getAttribute('data-handlepos'),
|
|
614
|
-
x: (handleBounds.left -
|
|
615
|
-
y: (handleBounds.top -
|
|
613
|
+
x: (handleBounds.left - nodeBounds.left) / zoom,
|
|
614
|
+
y: (handleBounds.top - nodeBounds.top) / zoom,
|
|
616
615
|
...getDimensions(handle),
|
|
617
616
|
};
|
|
618
617
|
});
|
|
@@ -778,14 +777,14 @@ const addEdge = (edgeParams, edges) => {
|
|
|
778
777
|
return edges.concat(edge);
|
|
779
778
|
};
|
|
780
779
|
/**
|
|
781
|
-
* A handy utility to
|
|
780
|
+
* A handy utility to reconnect an existing edge with new properties
|
|
782
781
|
* @param oldEdge - The edge you want to update
|
|
783
782
|
* @param newConnection - The new connection you want to update the edge with
|
|
784
783
|
* @param edges - The array of all current edges
|
|
785
784
|
* @param options.shouldReplaceId - should the id of the old edge be replaced with the new connection id
|
|
786
785
|
* @returns the updated edges array
|
|
787
786
|
*/
|
|
788
|
-
const
|
|
787
|
+
const reconnectEdge = (oldEdge, newConnection, edges, options = { shouldReplaceId: true }) => {
|
|
789
788
|
const { id: oldEdgeId, ...rest } = oldEdge;
|
|
790
789
|
if (!newConnection.source || !newConnection.target) {
|
|
791
790
|
devWarn('006', errorMessages['error006']());
|
|
@@ -1039,8 +1038,6 @@ function getEdgePosition(params) {
|
|
|
1039
1038
|
params.connectionMode === ConnectionMode.Strict
|
|
1040
1039
|
? targetHandleBounds?.target ?? []
|
|
1041
1040
|
: (targetHandleBounds?.target ?? []).concat(targetHandleBounds?.source ?? []), params.targetHandle);
|
|
1042
|
-
const sourcePosition = sourceHandle?.position || Position.Bottom;
|
|
1043
|
-
const targetPosition = targetHandle?.position || Position.Top;
|
|
1044
1041
|
if (!sourceHandle || !targetHandle) {
|
|
1045
1042
|
params.onError?.('008', errorMessages['error008'](!sourceHandle ? 'source' : 'target', {
|
|
1046
1043
|
id: params.id,
|
|
@@ -1049,13 +1046,15 @@ function getEdgePosition(params) {
|
|
|
1049
1046
|
}));
|
|
1050
1047
|
return null;
|
|
1051
1048
|
}
|
|
1052
|
-
const
|
|
1053
|
-
const
|
|
1049
|
+
const sourcePosition = sourceHandle?.position || Position.Bottom;
|
|
1050
|
+
const targetPosition = targetHandle?.position || Position.Top;
|
|
1051
|
+
const source = getHandlePosition(sourceNode, sourceHandle, sourcePosition);
|
|
1052
|
+
const target = getHandlePosition(targetNode, targetHandle, targetPosition);
|
|
1054
1053
|
return {
|
|
1055
|
-
sourceX,
|
|
1056
|
-
sourceY,
|
|
1057
|
-
targetX,
|
|
1058
|
-
targetY,
|
|
1054
|
+
sourceX: source.x,
|
|
1055
|
+
sourceY: source.y,
|
|
1056
|
+
targetX: target.x,
|
|
1057
|
+
targetY: target.y,
|
|
1059
1058
|
sourcePosition,
|
|
1060
1059
|
targetPosition,
|
|
1061
1060
|
};
|
|
@@ -1081,19 +1080,23 @@ function toHandleBounds(handles) {
|
|
|
1081
1080
|
target,
|
|
1082
1081
|
};
|
|
1083
1082
|
}
|
|
1084
|
-
function getHandlePosition(
|
|
1083
|
+
function getHandlePosition(node, handle, fallbackPosition = Position.Left, center = false) {
|
|
1085
1084
|
const x = (handle?.x ?? 0) + node.internals.positionAbsolute.x;
|
|
1086
1085
|
const y = (handle?.y ?? 0) + node.internals.positionAbsolute.y;
|
|
1087
1086
|
const { width, height } = handle ?? getNodeDimensions(node);
|
|
1087
|
+
if (center) {
|
|
1088
|
+
return { x: x + width / 2, y: y + height / 2 };
|
|
1089
|
+
}
|
|
1090
|
+
const position = handle?.position ?? fallbackPosition;
|
|
1088
1091
|
switch (position) {
|
|
1089
1092
|
case Position.Top:
|
|
1090
|
-
return
|
|
1093
|
+
return { x: x + width / 2, y };
|
|
1091
1094
|
case Position.Right:
|
|
1092
|
-
return
|
|
1095
|
+
return { x: x + width, y: y + height / 2 };
|
|
1093
1096
|
case Position.Bottom:
|
|
1094
|
-
return
|
|
1097
|
+
return { x: x + width / 2, y: y + height };
|
|
1095
1098
|
case Position.Left:
|
|
1096
|
-
return
|
|
1099
|
+
return { x, y: y + height / 2 };
|
|
1097
1100
|
}
|
|
1098
1101
|
}
|
|
1099
1102
|
function getHandle(bounds, handleId) {
|
|
@@ -1174,95 +1177,98 @@ function getNodeToolbarTransform(nodeRect, viewport, position, offset, align) {
|
|
|
1174
1177
|
return `translate(${pos[0]}px, ${pos[1]}px) translate(${shift[0]}%, ${shift[1]}%)`;
|
|
1175
1178
|
}
|
|
1176
1179
|
|
|
1177
|
-
|
|
1180
|
+
const defaultOptions = {
|
|
1178
1181
|
nodeOrigin: [0, 0],
|
|
1179
1182
|
elevateNodesOnSelect: true,
|
|
1180
1183
|
defaults: {},
|
|
1181
|
-
}
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1184
|
+
};
|
|
1185
|
+
const adoptUserNodesDefaultOptions = {
|
|
1186
|
+
...defaultOptions,
|
|
1187
|
+
checkEquality: true,
|
|
1188
|
+
};
|
|
1189
|
+
function updateAbsolutePositions(nodeLookup, parentLookup, options) {
|
|
1190
|
+
const _options = { ...defaultOptions, ...options };
|
|
1191
|
+
for (const node of nodeLookup.values()) {
|
|
1192
|
+
if (!node.parentId) {
|
|
1186
1193
|
continue;
|
|
1187
1194
|
}
|
|
1188
|
-
|
|
1189
|
-
throw new Error(`Parent node ${parentId} not found`);
|
|
1190
|
-
}
|
|
1191
|
-
const parentNode = nodeLookup.get(parentId);
|
|
1192
|
-
const { x, y, z } = calculateXYZPosition(node, nodeLookup, {
|
|
1193
|
-
...node.position,
|
|
1194
|
-
z: (isNumeric(node.zIndex) ? node.zIndex : 0) + (node.selected ? selectedNodeZ : 0),
|
|
1195
|
-
}, parentNode?.origin ?? options.nodeOrigin);
|
|
1196
|
-
const currPosition = node.internals.positionAbsolute;
|
|
1197
|
-
const positionChanged = x !== currPosition.x || y !== currPosition.y;
|
|
1198
|
-
if (positionChanged || z !== node.internals.z) {
|
|
1199
|
-
node.internals = {
|
|
1200
|
-
...node.internals,
|
|
1201
|
-
positionAbsolute: positionChanged ? { x, y } : currPosition,
|
|
1202
|
-
z,
|
|
1203
|
-
};
|
|
1204
|
-
}
|
|
1195
|
+
updateChildPosition(node, nodeLookup, parentLookup, _options);
|
|
1205
1196
|
}
|
|
1206
1197
|
}
|
|
1207
|
-
function adoptUserNodes(nodes, nodeLookup, parentLookup, options
|
|
1208
|
-
|
|
1209
|
-
elevateNodesOnSelect: true,
|
|
1210
|
-
defaults: {},
|
|
1211
|
-
checkEquality: true,
|
|
1212
|
-
}) {
|
|
1198
|
+
function adoptUserNodes(nodes, nodeLookup, parentLookup, options) {
|
|
1199
|
+
const _options = { ...adoptUserNodesDefaultOptions, ...options };
|
|
1213
1200
|
const tmpLookup = new Map(nodeLookup);
|
|
1214
1201
|
nodeLookup.clear();
|
|
1215
1202
|
parentLookup.clear();
|
|
1216
1203
|
const selectedNodeZ = options?.elevateNodesOnSelect ? 1000 : 0;
|
|
1217
|
-
|
|
1204
|
+
for (const userNode of nodes) {
|
|
1218
1205
|
let internalNode = tmpLookup.get(userNode.id);
|
|
1219
|
-
if (
|
|
1206
|
+
if (_options.checkEquality && userNode === internalNode?.internals.userNode) {
|
|
1220
1207
|
nodeLookup.set(userNode.id, internalNode);
|
|
1221
1208
|
}
|
|
1222
1209
|
else {
|
|
1223
1210
|
internalNode = {
|
|
1224
|
-
...
|
|
1211
|
+
..._options.defaults,
|
|
1225
1212
|
...userNode,
|
|
1226
1213
|
measured: {
|
|
1227
1214
|
width: userNode.measured?.width,
|
|
1228
1215
|
height: userNode.measured?.height,
|
|
1229
1216
|
},
|
|
1230
1217
|
internals: {
|
|
1231
|
-
positionAbsolute: userNode.
|
|
1218
|
+
positionAbsolute: getNodePositionWithOrigin(userNode, _options.nodeOrigin),
|
|
1232
1219
|
handleBounds: internalNode?.internals.handleBounds,
|
|
1233
|
-
z: (
|
|
1220
|
+
z: calculateZ(userNode, selectedNodeZ),
|
|
1234
1221
|
userNode,
|
|
1235
1222
|
},
|
|
1236
1223
|
};
|
|
1237
1224
|
nodeLookup.set(userNode.id, internalNode);
|
|
1238
1225
|
}
|
|
1239
1226
|
if (userNode.parentId) {
|
|
1240
|
-
|
|
1241
|
-
if (childNodes) {
|
|
1242
|
-
childNodes.push(internalNode);
|
|
1243
|
-
}
|
|
1244
|
-
else {
|
|
1245
|
-
parentLookup.set(userNode.parentId, [internalNode]);
|
|
1246
|
-
}
|
|
1227
|
+
updateChildPosition(internalNode, nodeLookup, parentLookup, options);
|
|
1247
1228
|
}
|
|
1248
|
-
});
|
|
1249
|
-
if (parentLookup.size > 0) {
|
|
1250
|
-
updateAbsolutePositions(nodeLookup, options);
|
|
1251
1229
|
}
|
|
1252
1230
|
}
|
|
1253
|
-
function
|
|
1254
|
-
|
|
1255
|
-
|
|
1231
|
+
function updateChildPosition(node, nodeLookup, parentLookup, options) {
|
|
1232
|
+
const _options = { ...defaultOptions, ...options };
|
|
1233
|
+
const parentId = node.parentId;
|
|
1234
|
+
const parentNode = nodeLookup.get(parentId);
|
|
1235
|
+
if (!parentNode) {
|
|
1236
|
+
throw new Error(`Parent node ${parentId} not found`);
|
|
1237
|
+
}
|
|
1238
|
+
// update the parentLookup
|
|
1239
|
+
const childNodes = parentLookup.get(parentId);
|
|
1240
|
+
if (childNodes) {
|
|
1241
|
+
childNodes.set(node.id, node);
|
|
1242
|
+
}
|
|
1243
|
+
else {
|
|
1244
|
+
parentLookup.set(parentId, new Map([[node.id, node]]));
|
|
1245
|
+
}
|
|
1246
|
+
const selectedNodeZ = options?.elevateNodesOnSelect ? 1000 : 0;
|
|
1247
|
+
const { x, y, z } = calculateChildXYZ(node, parentNode, _options.nodeOrigin, selectedNodeZ);
|
|
1248
|
+
const currPosition = node.internals.positionAbsolute;
|
|
1249
|
+
const positionChanged = x !== currPosition.x || y !== currPosition.y;
|
|
1250
|
+
if (positionChanged || z !== node.internals.z) {
|
|
1251
|
+
node.internals = {
|
|
1252
|
+
...node.internals,
|
|
1253
|
+
positionAbsolute: positionChanged ? { x, y } : currPosition,
|
|
1254
|
+
z,
|
|
1255
|
+
};
|
|
1256
1256
|
}
|
|
1257
|
-
const parent = nodeLookup.get(node.parentId);
|
|
1258
|
-
const parentPosition = getNodePositionWithOrigin(parent, nodeOrigin).position;
|
|
1259
|
-
return calculateXYZPosition(parent, nodeLookup, {
|
|
1260
|
-
x: (result.x ?? 0) + parentPosition.x,
|
|
1261
|
-
y: (result.y ?? 0) + parentPosition.y,
|
|
1262
|
-
z: (parent.internals.z ?? 0) > (result.z ?? 0) ? parent.internals.z ?? 0 : result.z ?? 0,
|
|
1263
|
-
}, parent.origin || nodeOrigin);
|
|
1264
1257
|
}
|
|
1265
|
-
function
|
|
1258
|
+
function calculateZ(node, selectedNodeZ) {
|
|
1259
|
+
return (isNumeric(node.zIndex) ? node.zIndex : 0) + (node.selected ? selectedNodeZ : 0);
|
|
1260
|
+
}
|
|
1261
|
+
function calculateChildXYZ(childNode, parentNode, nodeOrigin, selectedNodeZ) {
|
|
1262
|
+
const position = getNodePositionWithOrigin(childNode, nodeOrigin);
|
|
1263
|
+
const childZ = calculateZ(childNode, selectedNodeZ);
|
|
1264
|
+
const parentZ = parentNode.internals.z ?? 0;
|
|
1265
|
+
return {
|
|
1266
|
+
x: parentNode.internals.positionAbsolute.x + position.x,
|
|
1267
|
+
y: parentNode.internals.positionAbsolute.y + position.y,
|
|
1268
|
+
z: parentZ > childZ ? parentZ : childZ,
|
|
1269
|
+
};
|
|
1270
|
+
}
|
|
1271
|
+
function handleExpandParent(children, nodeLookup, parentLookup, nodeOrigin = [0, 0]) {
|
|
1266
1272
|
const changes = [];
|
|
1267
1273
|
const parentExpansions = new Map();
|
|
1268
1274
|
// determine the expanded rectangle the child nodes would take for each parent
|
|
@@ -1271,31 +1277,36 @@ function handleExpandParent(children, nodeLookup, parentLookup, nodeOrigin) {
|
|
|
1271
1277
|
if (!parent) {
|
|
1272
1278
|
continue;
|
|
1273
1279
|
}
|
|
1274
|
-
const parentRect = parentExpansions.get(child.parentId)?.expandedRect ?? nodeToRect(parent
|
|
1280
|
+
const parentRect = parentExpansions.get(child.parentId)?.expandedRect ?? nodeToRect(parent);
|
|
1275
1281
|
const expandedRect = getBoundsOfRects(parentRect, child.rect);
|
|
1276
1282
|
parentExpansions.set(child.parentId, { expandedRect, parent });
|
|
1277
1283
|
}
|
|
1278
1284
|
if (parentExpansions.size > 0) {
|
|
1279
1285
|
parentExpansions.forEach(({ expandedRect, parent }, parentId) => {
|
|
1280
1286
|
// determine the position & dimensions of the parent
|
|
1281
|
-
const
|
|
1287
|
+
const positionAbsolute = parent.internals.positionAbsolute;
|
|
1282
1288
|
const dimensions = getNodeDimensions(parent);
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
const
|
|
1286
|
-
|
|
1289
|
+
const origin = parent.origin ?? nodeOrigin;
|
|
1290
|
+
// determine how much the parent expands in width and position
|
|
1291
|
+
const xChange = expandedRect.x < positionAbsolute.x ? Math.round(Math.abs(positionAbsolute.x - expandedRect.x)) : 0;
|
|
1292
|
+
const yChange = expandedRect.y < positionAbsolute.y ? Math.round(Math.abs(positionAbsolute.y - expandedRect.y)) : 0;
|
|
1293
|
+
const newWidth = Math.max(dimensions.width, Math.round(expandedRect.width));
|
|
1294
|
+
const newHeight = Math.max(dimensions.height, Math.round(expandedRect.height));
|
|
1295
|
+
const widthChange = (newWidth - dimensions.width) * origin[0];
|
|
1296
|
+
const heightChange = (newHeight - dimensions.height) * origin[1];
|
|
1297
|
+
// We need to correct the position of the parent node if the origin is not [0,0]
|
|
1298
|
+
if (xChange > 0 || yChange > 0 || widthChange || heightChange) {
|
|
1287
1299
|
changes.push({
|
|
1288
1300
|
id: parentId,
|
|
1289
1301
|
type: 'position',
|
|
1290
1302
|
position: {
|
|
1291
|
-
x: position.x - xChange,
|
|
1292
|
-
y: position.y - yChange,
|
|
1303
|
+
x: parent.position.x - xChange + widthChange,
|
|
1304
|
+
y: parent.position.y - yChange + heightChange,
|
|
1293
1305
|
},
|
|
1294
1306
|
});
|
|
1295
1307
|
// We move all child nodes in the oppsite direction
|
|
1296
1308
|
// so the x,y changes of the parent do not move the children
|
|
1297
|
-
|
|
1298
|
-
childNodes?.forEach((childNode) => {
|
|
1309
|
+
parentLookup.get(parentId)?.forEach((childNode) => {
|
|
1299
1310
|
if (!children.some((child) => child.id === childNode.id)) {
|
|
1300
1311
|
changes.push({
|
|
1301
1312
|
id: childNode.id,
|
|
@@ -1308,14 +1319,15 @@ function handleExpandParent(children, nodeLookup, parentLookup, nodeOrigin) {
|
|
|
1308
1319
|
}
|
|
1309
1320
|
});
|
|
1310
1321
|
}
|
|
1311
|
-
|
|
1322
|
+
// We need to correct the dimensions of the parent node if the origin is not [0,0]
|
|
1323
|
+
if (dimensions.width < expandedRect.width || dimensions.height < expandedRect.height || xChange || yChange) {
|
|
1312
1324
|
changes.push({
|
|
1313
1325
|
id: parentId,
|
|
1314
1326
|
type: 'dimensions',
|
|
1315
1327
|
setAttributes: true,
|
|
1316
1328
|
dimensions: {
|
|
1317
|
-
width:
|
|
1318
|
-
height:
|
|
1329
|
+
width: newWidth + (xChange ? origin[0] * xChange - widthChange : 0),
|
|
1330
|
+
height: newHeight + (yChange ? origin[1] * yChange - heightChange : 0),
|
|
1319
1331
|
},
|
|
1320
1332
|
});
|
|
1321
1333
|
}
|
|
@@ -1334,16 +1346,19 @@ function updateNodeInternals(updates, nodeLookup, parentLookup, domNode, nodeOri
|
|
|
1334
1346
|
const { m22: zoom } = new window.DOMMatrixReadOnly(style.transform);
|
|
1335
1347
|
// in this array we collect nodes, that might trigger changes (like expanding parent)
|
|
1336
1348
|
const parentExpandChildren = [];
|
|
1337
|
-
updates.
|
|
1349
|
+
for (const update of updates.values()) {
|
|
1338
1350
|
const node = nodeLookup.get(update.id);
|
|
1339
|
-
if (node
|
|
1351
|
+
if (!node) {
|
|
1352
|
+
continue;
|
|
1353
|
+
}
|
|
1354
|
+
if (node.hidden) {
|
|
1340
1355
|
node.internals = {
|
|
1341
1356
|
...node.internals,
|
|
1342
1357
|
handleBounds: undefined,
|
|
1343
1358
|
};
|
|
1344
1359
|
updatedInternals = true;
|
|
1345
1360
|
}
|
|
1346
|
-
else
|
|
1361
|
+
else {
|
|
1347
1362
|
const dimensions = getDimensions(update.nodeElement);
|
|
1348
1363
|
const dimensionChanged = node.measured.width !== dimensions.width || node.measured.height !== dimensions.height;
|
|
1349
1364
|
const doUpdate = !!(dimensions.width &&
|
|
@@ -1354,11 +1369,15 @@ function updateNodeInternals(updates, nodeLookup, parentLookup, domNode, nodeOri
|
|
|
1354
1369
|
node.measured = dimensions;
|
|
1355
1370
|
node.internals = {
|
|
1356
1371
|
...node.internals,
|
|
1372
|
+
positionAbsolute: getNodePositionWithOrigin(node, nodeOrigin),
|
|
1357
1373
|
handleBounds: {
|
|
1358
|
-
source: getHandleBounds('
|
|
1359
|
-
target: getHandleBounds('
|
|
1374
|
+
source: getHandleBounds('source', update.nodeElement, nodeBounds, zoom, node.id),
|
|
1375
|
+
target: getHandleBounds('target', update.nodeElement, nodeBounds, zoom, node.id),
|
|
1360
1376
|
},
|
|
1361
1377
|
};
|
|
1378
|
+
if (node.parentId) {
|
|
1379
|
+
updateChildPosition(node, nodeLookup, parentLookup, { nodeOrigin });
|
|
1380
|
+
}
|
|
1362
1381
|
updatedInternals = true;
|
|
1363
1382
|
if (dimensionChanged) {
|
|
1364
1383
|
changes.push({
|
|
@@ -1376,7 +1395,7 @@ function updateNodeInternals(updates, nodeLookup, parentLookup, domNode, nodeOri
|
|
|
1376
1395
|
}
|
|
1377
1396
|
}
|
|
1378
1397
|
}
|
|
1379
|
-
}
|
|
1398
|
+
}
|
|
1380
1399
|
if (parentExpandChildren.length > 0) {
|
|
1381
1400
|
const parentExpandChanges = handleExpandParent(parentExpandChildren, nodeLookup, parentLookup, nodeOrigin);
|
|
1382
1401
|
changes.push(...parentExpandChanges);
|
|
@@ -1536,7 +1555,7 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
|
|
|
1536
1555
|
let hasChange = false;
|
|
1537
1556
|
let nodesBox = { x: 0, y: 0, x2: 0, y2: 0 };
|
|
1538
1557
|
if (dragItems.size > 1 && nodeExtent) {
|
|
1539
|
-
const rect = getInternalNodesBounds(dragItems
|
|
1558
|
+
const rect = getInternalNodesBounds(dragItems);
|
|
1540
1559
|
nodesBox = rectToBox(rect);
|
|
1541
1560
|
}
|
|
1542
1561
|
for (const [id, dragItem] of dragItems) {
|
|
@@ -1719,18 +1738,18 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
|
|
|
1719
1738
|
// this functions collects all handles and adds an absolute position
|
|
1720
1739
|
// so that we can later find the closest handle to the mouse position
|
|
1721
1740
|
function getHandles(node, handleBounds, type, currentHandle) {
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
});
|
|
1741
|
+
let excludedHandle = null;
|
|
1742
|
+
const handles = (handleBounds[type] || []).reduce((res, handle) => {
|
|
1743
|
+
if (node.id === currentHandle.nodeId && type === currentHandle.handleType && handle.id === currentHandle.handleId) {
|
|
1744
|
+
excludedHandle = handle;
|
|
1745
|
+
}
|
|
1746
|
+
else {
|
|
1747
|
+
const handleXY = getHandlePosition(node, handle, handle.position, true);
|
|
1748
|
+
res.push({ ...handle, ...handleXY });
|
|
1731
1749
|
}
|
|
1732
1750
|
return res;
|
|
1733
1751
|
}, []);
|
|
1752
|
+
return [handles, excludedHandle];
|
|
1734
1753
|
}
|
|
1735
1754
|
function getClosestHandle(pos, connectionRadius, handles) {
|
|
1736
1755
|
let closestHandles = [];
|
|
@@ -1758,15 +1777,17 @@ function getClosestHandle(pos, connectionRadius, handles) {
|
|
|
1758
1777
|
}
|
|
1759
1778
|
function getHandleLookup({ nodeLookup, nodeId, handleId, handleType, }) {
|
|
1760
1779
|
const connectionHandles = [];
|
|
1761
|
-
|
|
1780
|
+
const currentHandle = { nodeId, handleId, handleType };
|
|
1781
|
+
let excludedHandle = null;
|
|
1782
|
+
for (const node of nodeLookup.values()) {
|
|
1762
1783
|
if (node.internals.handleBounds) {
|
|
1763
|
-
const
|
|
1764
|
-
const
|
|
1765
|
-
|
|
1784
|
+
const [sourceHandles, excludedSource] = getHandles(node, node.internals.handleBounds, 'source', currentHandle);
|
|
1785
|
+
const [targetHandles, excludedTarget] = getHandles(node, node.internals.handleBounds, 'target', currentHandle);
|
|
1786
|
+
excludedHandle = excludedHandle ? excludedHandle : excludedSource ?? excludedTarget;
|
|
1766
1787
|
connectionHandles.push(...sourceHandles, ...targetHandles);
|
|
1767
1788
|
}
|
|
1768
1789
|
}
|
|
1769
|
-
return connectionHandles;
|
|
1790
|
+
return [connectionHandles, excludedHandle];
|
|
1770
1791
|
}
|
|
1771
1792
|
function getHandleType(edgeUpdaterType, handleDomNode) {
|
|
1772
1793
|
if (edgeUpdaterType) {
|
|
@@ -1780,20 +1801,19 @@ function getHandleType(edgeUpdaterType, handleDomNode) {
|
|
|
1780
1801
|
}
|
|
1781
1802
|
return null;
|
|
1782
1803
|
}
|
|
1783
|
-
function
|
|
1784
|
-
let
|
|
1804
|
+
function isConnectionValid(isInsideConnectionRadius, isHandleValid) {
|
|
1805
|
+
let isValid = null;
|
|
1785
1806
|
if (isHandleValid) {
|
|
1786
|
-
|
|
1807
|
+
isValid = true;
|
|
1787
1808
|
}
|
|
1788
1809
|
else if (isInsideConnectionRadius && !isHandleValid) {
|
|
1789
|
-
|
|
1810
|
+
isValid = false;
|
|
1790
1811
|
}
|
|
1791
|
-
return
|
|
1812
|
+
return isValid;
|
|
1792
1813
|
}
|
|
1793
1814
|
|
|
1794
1815
|
const alwaysValid = () => true;
|
|
1795
|
-
|
|
1796
|
-
function onPointerDown(event, { connectionMode, connectionRadius, handleId, nodeId, edgeUpdaterType, isTarget, domNode, nodeLookup, lib, autoPanOnConnect, flowId, panBy, cancelConnection, onConnectStart, onConnect, onConnectEnd, isValidConnection = alwaysValid, onEdgeUpdateEnd, updateConnection, getTransform, getConnectionStartHandle, }) {
|
|
1816
|
+
function onPointerDown(event, { connectionMode, connectionRadius, handleId, nodeId, edgeUpdaterType, isTarget, domNode, nodeLookup, lib, autoPanOnConnect, flowId, panBy, cancelConnection, onConnectStart, onConnect, onConnectEnd, isValidConnection = alwaysValid, onReconnectEnd, updateConnection, getTransform, getFromHandle, }) {
|
|
1797
1817
|
// when xyflow is used inside a shadow root we can't use document
|
|
1798
1818
|
const doc = getHostForElement(event.target);
|
|
1799
1819
|
let autoPanId = 0;
|
|
@@ -1805,12 +1825,12 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
|
|
|
1805
1825
|
if (!containerBounds || !handleType) {
|
|
1806
1826
|
return;
|
|
1807
1827
|
}
|
|
1808
|
-
let
|
|
1828
|
+
let position = getEventPosition(event, containerBounds);
|
|
1809
1829
|
let autoPanStarted = false;
|
|
1810
1830
|
let connection = null;
|
|
1811
1831
|
let isValid = false;
|
|
1812
1832
|
let handleDomNode = null;
|
|
1813
|
-
const handleLookup = getHandleLookup({
|
|
1833
|
+
const [handleLookup, fromHandleInternal] = getHandleLookup({
|
|
1814
1834
|
nodeLookup,
|
|
1815
1835
|
nodeId,
|
|
1816
1836
|
handleId,
|
|
@@ -1821,31 +1841,42 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
|
|
|
1821
1841
|
if (!autoPanOnConnect || !containerBounds) {
|
|
1822
1842
|
return;
|
|
1823
1843
|
}
|
|
1824
|
-
const [x, y] = calcAutoPan(
|
|
1844
|
+
const [x, y] = calcAutoPan(position, containerBounds);
|
|
1825
1845
|
panBy({ x, y });
|
|
1826
1846
|
autoPanId = requestAnimationFrame(autoPan);
|
|
1827
1847
|
}
|
|
1828
1848
|
// Stays the same for all consecutive pointermove events
|
|
1829
|
-
|
|
1849
|
+
const fromHandle = {
|
|
1850
|
+
...fromHandleInternal,
|
|
1830
1851
|
nodeId,
|
|
1831
|
-
handleId,
|
|
1832
1852
|
type: handleType,
|
|
1853
|
+
position: fromHandleInternal.position,
|
|
1833
1854
|
};
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1855
|
+
const fromNodeInternal = nodeLookup.get(nodeId);
|
|
1856
|
+
const from = getHandlePosition(fromNodeInternal, fromHandle, Position.Left, true);
|
|
1857
|
+
const newConnection = {
|
|
1858
|
+
inProgress: true,
|
|
1859
|
+
isValid: null,
|
|
1860
|
+
from,
|
|
1861
|
+
fromHandle,
|
|
1862
|
+
fromPosition: fromHandle.position,
|
|
1863
|
+
fromNode: fromNodeInternal.internals.userNode,
|
|
1864
|
+
to: position,
|
|
1865
|
+
toHandle: null,
|
|
1866
|
+
toPosition: oppositePosition[fromHandle.position],
|
|
1867
|
+
toNode: null,
|
|
1868
|
+
};
|
|
1869
|
+
updateConnection(newConnection);
|
|
1870
|
+
let previousConnection = newConnection;
|
|
1841
1871
|
onConnectStart?.(event, { nodeId, handleId, handleType });
|
|
1842
1872
|
function onPointerMove(event) {
|
|
1843
|
-
if (!
|
|
1873
|
+
if (!getFromHandle() || !fromHandle) {
|
|
1844
1874
|
onPointerUp(event);
|
|
1875
|
+
return;
|
|
1845
1876
|
}
|
|
1846
1877
|
const transform = getTransform();
|
|
1847
|
-
|
|
1848
|
-
closestHandle = getClosestHandle(pointToRendererPoint(
|
|
1878
|
+
position = getEventPosition(event, containerBounds);
|
|
1879
|
+
closestHandle = getClosestHandle(pointToRendererPoint(position, transform, false, [1, 1]), connectionRadius, handleLookup);
|
|
1849
1880
|
if (!autoPanStarted) {
|
|
1850
1881
|
autoPan();
|
|
1851
1882
|
autoPanStarted = true;
|
|
@@ -1860,21 +1891,34 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
|
|
|
1860
1891
|
doc,
|
|
1861
1892
|
lib,
|
|
1862
1893
|
flowId,
|
|
1894
|
+
handleLookup,
|
|
1863
1895
|
});
|
|
1864
1896
|
handleDomNode = result.handleDomNode;
|
|
1865
1897
|
connection = result.connection;
|
|
1866
|
-
isValid = result.isValid;
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
}
|
|
1898
|
+
isValid = isConnectionValid(!!closestHandle, result.isValid);
|
|
1899
|
+
const newConnection = {
|
|
1900
|
+
// from stays the same
|
|
1901
|
+
...previousConnection,
|
|
1902
|
+
isValid,
|
|
1903
|
+
to: closestHandle && isValid
|
|
1904
|
+
? rendererPointToPoint({ x: closestHandle.x, y: closestHandle.y }, transform)
|
|
1905
|
+
: position,
|
|
1906
|
+
toHandle: result.toHandle,
|
|
1907
|
+
toPosition: isValid && result.toHandle ? result.toHandle.position : oppositePosition[fromHandle.position],
|
|
1908
|
+
toNode: result.toHandle ? nodeLookup.get(result.toHandle.nodeId).internals.userNode : null,
|
|
1909
|
+
};
|
|
1910
|
+
// we don't want to trigger an update when the connection
|
|
1911
|
+
// is snapped to the same handle as before
|
|
1912
|
+
if (isValid &&
|
|
1913
|
+
closestHandle &&
|
|
1914
|
+
previousConnection.toHandle &&
|
|
1915
|
+
newConnection.toHandle &&
|
|
1916
|
+
previousConnection.toHandle.nodeId === newConnection.toHandle.nodeId &&
|
|
1917
|
+
previousConnection.toHandle.id === newConnection.toHandle.id) {
|
|
1918
|
+
return;
|
|
1919
|
+
}
|
|
1920
|
+
updateConnection(newConnection);
|
|
1921
|
+
previousConnection = newConnection;
|
|
1878
1922
|
}
|
|
1879
1923
|
function onPointerUp(event) {
|
|
1880
1924
|
if ((closestHandle || handleDomNode) && connection && isValid) {
|
|
@@ -1884,7 +1928,7 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
|
|
|
1884
1928
|
// in order to get the latest state of onConnectEnd
|
|
1885
1929
|
onConnectEnd?.(event);
|
|
1886
1930
|
if (edgeUpdaterType) {
|
|
1887
|
-
|
|
1931
|
+
onReconnectEnd?.(event);
|
|
1888
1932
|
}
|
|
1889
1933
|
cancelConnection();
|
|
1890
1934
|
cancelAnimationFrame(autoPanId);
|
|
@@ -1892,7 +1936,6 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
|
|
|
1892
1936
|
isValid = false;
|
|
1893
1937
|
connection = null;
|
|
1894
1938
|
handleDomNode = null;
|
|
1895
|
-
connectionStartHandle = null;
|
|
1896
1939
|
doc.removeEventListener('mousemove', onPointerMove);
|
|
1897
1940
|
doc.removeEventListener('mouseup', onPointerUp);
|
|
1898
1941
|
doc.removeEventListener('touchmove', onPointerMove);
|
|
@@ -1904,7 +1947,7 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
|
|
|
1904
1947
|
doc.addEventListener('touchend', onPointerUp);
|
|
1905
1948
|
}
|
|
1906
1949
|
// checks if and returns connection in fom of an object { source: 123, target: 312 }
|
|
1907
|
-
function isValidHandle(event, { handle, connectionMode, fromNodeId, fromHandleId, fromType, doc, lib, flowId, isValidConnection = alwaysValid, }) {
|
|
1950
|
+
function isValidHandle(event, { handle, connectionMode, fromNodeId, fromHandleId, fromType, doc, lib, flowId, isValidConnection = alwaysValid, handleLookup, }) {
|
|
1908
1951
|
const isTarget = fromType === 'target';
|
|
1909
1952
|
const handleDomNode = handle
|
|
1910
1953
|
? doc.querySelector(`.${lib}-flow__handle[data-id="${flowId}-${handle?.nodeId}-${handle?.id}-${handle?.type}"]`)
|
|
@@ -1918,7 +1961,7 @@ function isValidHandle(event, { handle, connectionMode, fromNodeId, fromHandleId
|
|
|
1918
1961
|
handleDomNode: handleToCheck,
|
|
1919
1962
|
isValid: false,
|
|
1920
1963
|
connection: null,
|
|
1921
|
-
|
|
1964
|
+
toHandle: null,
|
|
1922
1965
|
};
|
|
1923
1966
|
if (handleToCheck) {
|
|
1924
1967
|
const handleType = getHandleType(undefined, handleToCheck);
|
|
@@ -1942,13 +1985,14 @@ function isValidHandle(event, { handle, connectionMode, fromNodeId, fromHandleId
|
|
|
1942
1985
|
(connectionMode === ConnectionMode.Strict
|
|
1943
1986
|
? (isTarget && handleType === 'source') || (!isTarget && handleType === 'target')
|
|
1944
1987
|
: handleNodeId !== fromNodeId || handleId !== fromHandleId);
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1988
|
+
result.isValid = isValid && isValidConnection(connection);
|
|
1989
|
+
if (handleLookup) {
|
|
1990
|
+
const toHandle = handleLookup.find((h) => h.id === handleId && h.nodeId === handleNodeId && h.type === handleType);
|
|
1991
|
+
if (toHandle) {
|
|
1992
|
+
result.toHandle = {
|
|
1993
|
+
...toHandle,
|
|
1994
|
+
};
|
|
1995
|
+
}
|
|
1952
1996
|
}
|
|
1953
1997
|
}
|
|
1954
1998
|
return result;
|
|
@@ -1961,6 +2005,7 @@ const XYHandle = {
|
|
|
1961
2005
|
function XYMinimap({ domNode, panZoom, getTransform, getViewScale }) {
|
|
1962
2006
|
const selection = select(domNode);
|
|
1963
2007
|
function update({ translateExtent, width, height, zoomStep = 10, pannable = true, zoomable = true, inversePan = false, }) {
|
|
2008
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1964
2009
|
const zoomHandler = (event) => {
|
|
1965
2010
|
const transform = getTransform();
|
|
1966
2011
|
if (event.sourceEvent.type !== 'wheel' || !panZoom) {
|
|
@@ -1973,6 +2018,7 @@ function XYMinimap({ domNode, panZoom, getTransform, getViewScale }) {
|
|
|
1973
2018
|
panZoom.scaleTo(nextZoom);
|
|
1974
2019
|
};
|
|
1975
2020
|
let panStart = [0, 0];
|
|
2021
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1976
2022
|
const panStartHandler = (event) => {
|
|
1977
2023
|
if (event.sourceEvent.type === 'mousedown' || event.sourceEvent.type === 'touchstart') {
|
|
1978
2024
|
panStart = [
|
|
@@ -1981,6 +2027,7 @@ function XYMinimap({ domNode, panZoom, getTransform, getViewScale }) {
|
|
|
1981
2027
|
];
|
|
1982
2028
|
}
|
|
1983
2029
|
};
|
|
2030
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1984
2031
|
const panHandler = (event) => {
|
|
1985
2032
|
const transform = getTransform();
|
|
1986
2033
|
if ((event.sourceEvent.type !== 'mousemove' && event.sourceEvent.type !== 'touchmove') || !panZoom) {
|
|
@@ -2009,8 +2056,10 @@ function XYMinimap({ domNode, panZoom, getTransform, getViewScale }) {
|
|
|
2009
2056
|
};
|
|
2010
2057
|
const zoomAndPanHandler = zoom()
|
|
2011
2058
|
.on('start', panStartHandler)
|
|
2059
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2012
2060
|
// @ts-ignore
|
|
2013
2061
|
.on('zoom', pannable ? panHandler : null)
|
|
2062
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2014
2063
|
// @ts-ignore
|
|
2015
2064
|
.on('zoom.wheel', zoomable ? zoomHandler : null);
|
|
2016
2065
|
selection.call(zoomAndPanHandler, {});
|
|
@@ -2649,8 +2698,8 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
|
|
|
2649
2698
|
}
|
|
2650
2699
|
const { xSnapped, ySnapped } = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });
|
|
2651
2700
|
prevValues = {
|
|
2652
|
-
width: node.measured
|
|
2653
|
-
height: node.measured
|
|
2701
|
+
width: node.measured.width ?? 0,
|
|
2702
|
+
height: node.measured.height ?? 0,
|
|
2654
2703
|
x: node.position.x ?? 0,
|
|
2655
2704
|
y: node.position.y ?? 0,
|
|
2656
2705
|
};
|
|
@@ -2661,11 +2710,9 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
|
|
|
2661
2710
|
aspectRatio: prevValues.width / prevValues.height,
|
|
2662
2711
|
};
|
|
2663
2712
|
parentNode = undefined;
|
|
2664
|
-
if (node.extent === 'parent' || node.expandParent) {
|
|
2713
|
+
if (node.parentId && (node.extent === 'parent' || node.expandParent)) {
|
|
2665
2714
|
parentNode = nodeLookup.get(node.parentId);
|
|
2666
|
-
|
|
2667
|
-
parentExtent = nodeToParentExtent(parentNode);
|
|
2668
|
-
}
|
|
2715
|
+
parentExtent = parentNode && node.extent === 'parent' ? nodeToParentExtent(parentNode) : undefined;
|
|
2669
2716
|
}
|
|
2670
2717
|
// Collect all child nodes to correct their relative positions when top/left changes
|
|
2671
2718
|
// Determine largest minimal extent the parent node is allowed to resize to
|
|
@@ -2712,22 +2759,13 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
|
|
|
2712
2759
|
if (!isXPosChange && !isYPosChange && !isWidthChange && !isHeightChange) {
|
|
2713
2760
|
return;
|
|
2714
2761
|
}
|
|
2715
|
-
if (isXPosChange || isYPosChange || nodeOrigin[0] === 1 || nodeOrigin[1]
|
|
2762
|
+
if (isXPosChange || isYPosChange || nodeOrigin[0] === 1 || nodeOrigin[1] === 1) {
|
|
2716
2763
|
change.x = isXPosChange ? x : prevValues.x;
|
|
2717
2764
|
change.y = isYPosChange ? y : prevValues.y;
|
|
2718
2765
|
prevValues.x = change.x;
|
|
2719
2766
|
prevValues.y = change.y;
|
|
2720
|
-
//
|
|
2721
|
-
|
|
2722
|
-
if (change.x && change.x < 0) {
|
|
2723
|
-
prevValues.x = 0;
|
|
2724
|
-
startValues.x = startValues.x - change.x;
|
|
2725
|
-
}
|
|
2726
|
-
if (change.y && change.y < 0) {
|
|
2727
|
-
prevValues.y = 0;
|
|
2728
|
-
startValues.y = startValues.y - change.y;
|
|
2729
|
-
}
|
|
2730
|
-
}
|
|
2767
|
+
// when top/left changes, correct the relative positions of child nodes
|
|
2768
|
+
// so that they stay in the same position
|
|
2731
2769
|
if (childNodes.length > 0) {
|
|
2732
2770
|
const xChange = x - prevX;
|
|
2733
2771
|
const yChange = y - prevY;
|
|
@@ -2746,6 +2784,19 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
|
|
|
2746
2784
|
prevValues.width = change.width;
|
|
2747
2785
|
prevValues.height = change.height;
|
|
2748
2786
|
}
|
|
2787
|
+
// Fix expandParent when resizing from top/left
|
|
2788
|
+
if (parentNode && node.expandParent) {
|
|
2789
|
+
const xLimit = nodeOrigin[0] * (change.width ?? 0);
|
|
2790
|
+
if (change.x && change.x < xLimit) {
|
|
2791
|
+
prevValues.x = xLimit;
|
|
2792
|
+
startValues.x = startValues.x - (change.x - xLimit);
|
|
2793
|
+
}
|
|
2794
|
+
const yLimit = nodeOrigin[1] * (change.height ?? 0);
|
|
2795
|
+
if (change.y && change.y < yLimit) {
|
|
2796
|
+
prevValues.y = yLimit;
|
|
2797
|
+
startValues.y = startValues.y - (change.y - yLimit);
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2749
2800
|
const direction = getResizeDirection({
|
|
2750
2801
|
width: prevValues.width,
|
|
2751
2802
|
prevWidth,
|
|
@@ -2777,4 +2828,4 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
|
|
|
2777
2828
|
};
|
|
2778
2829
|
}
|
|
2779
2830
|
|
|
2780
|
-
export { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, ResizeControlVariant, SelectionMode, XYDrag, XYHandle, XYMinimap, XYPanZoom, XYResizer, XY_RESIZER_HANDLE_POSITIONS, XY_RESIZER_LINE_POSITIONS, addEdge, adoptUserNodes, areConnectionMapsEqual, boxToRect, calcAutoPan, calculateNodePosition, clamp, clampPosition, createMarkerIds, devWarn, elementSelectionKeys, errorMessages, evaluateAbsolutePosition, fitView, getBezierEdgeCenter, getBezierPath, getBoundsOfBoxes, getBoundsOfRects, getConnectedEdges, getDimensions, getEdgeCenter, getEdgePosition, getElementsToRemove, getElevatedEdgeZIndex, getEventPosition, getHandleBounds, getHostForElement, getIncomers, getInternalNodesBounds, getMarkerId, getNodeDimensions, getNodePositionWithOrigin, getNodeToolbarTransform, getNodesBounds, getNodesInside, getOutgoers, getOverlappingArea, getPointerPosition,
|
|
2831
|
+
export { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, ResizeControlVariant, SelectionMode, XYDrag, XYHandle, XYMinimap, XYPanZoom, XYResizer, XY_RESIZER_HANDLE_POSITIONS, XY_RESIZER_LINE_POSITIONS, addEdge, adoptUserNodes, areConnectionMapsEqual, boxToRect, calcAutoPan, calculateNodePosition, clamp, clampPosition, createMarkerIds, devWarn, elementSelectionKeys, errorMessages, evaluateAbsolutePosition, fitView, getBezierEdgeCenter, getBezierPath, getBoundsOfBoxes, getBoundsOfRects, getConnectedEdges, getConnectionStatus, getDimensions, getEdgeCenter, getEdgePosition, getElementsToRemove, getElevatedEdgeZIndex, getEventPosition, getHandleBounds, getHandlePosition, getHostForElement, getIncomers, getInternalNodesBounds, getMarkerId, getNodeDimensions, getNodePositionWithOrigin, getNodeToolbarTransform, getNodesBounds, getNodesInside, getOutgoers, getOverlappingArea, getPointerPosition, getSmoothStepPath, getStraightPath, getViewportForBounds, handleConnectionChange, handleExpandParent, infiniteExtent, initialConnection, isCoordinateExtent, isEdgeBase, isEdgeVisible, isInputDOMNode, isInternalNodeBase, isMacOs, isMouseEvent, isNodeBase, isNumeric, isRectObject, nodeHasDimensions, nodeToBox, nodeToRect, oppositePosition, panBy, pointToRendererPoint, reconnectEdge, rectToBox, rendererPointToPoint, shallowNodeData, snapPosition, updateAbsolutePositions, updateConnectionLookup, updateNodeInternals };
|