@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.mjs
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,35 @@ 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.type === newConnection.toHandle.type &&
|
|
1917
|
+
previousConnection.toHandle.nodeId === newConnection.toHandle.nodeId &&
|
|
1918
|
+
previousConnection.toHandle.id === newConnection.toHandle.id) {
|
|
1919
|
+
return;
|
|
1920
|
+
}
|
|
1921
|
+
updateConnection(newConnection);
|
|
1922
|
+
previousConnection = newConnection;
|
|
1878
1923
|
}
|
|
1879
1924
|
function onPointerUp(event) {
|
|
1880
1925
|
if ((closestHandle || handleDomNode) && connection && isValid) {
|
|
@@ -1884,7 +1929,7 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
|
|
|
1884
1929
|
// in order to get the latest state of onConnectEnd
|
|
1885
1930
|
onConnectEnd?.(event);
|
|
1886
1931
|
if (edgeUpdaterType) {
|
|
1887
|
-
|
|
1932
|
+
onReconnectEnd?.(event);
|
|
1888
1933
|
}
|
|
1889
1934
|
cancelConnection();
|
|
1890
1935
|
cancelAnimationFrame(autoPanId);
|
|
@@ -1892,7 +1937,6 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
|
|
|
1892
1937
|
isValid = false;
|
|
1893
1938
|
connection = null;
|
|
1894
1939
|
handleDomNode = null;
|
|
1895
|
-
connectionStartHandle = null;
|
|
1896
1940
|
doc.removeEventListener('mousemove', onPointerMove);
|
|
1897
1941
|
doc.removeEventListener('mouseup', onPointerUp);
|
|
1898
1942
|
doc.removeEventListener('touchmove', onPointerMove);
|
|
@@ -1904,7 +1948,7 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
|
|
|
1904
1948
|
doc.addEventListener('touchend', onPointerUp);
|
|
1905
1949
|
}
|
|
1906
1950
|
// 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, }) {
|
|
1951
|
+
function isValidHandle(event, { handle, connectionMode, fromNodeId, fromHandleId, fromType, doc, lib, flowId, isValidConnection = alwaysValid, handleLookup, }) {
|
|
1908
1952
|
const isTarget = fromType === 'target';
|
|
1909
1953
|
const handleDomNode = handle
|
|
1910
1954
|
? doc.querySelector(`.${lib}-flow__handle[data-id="${flowId}-${handle?.nodeId}-${handle?.id}-${handle?.type}"]`)
|
|
@@ -1918,7 +1962,7 @@ function isValidHandle(event, { handle, connectionMode, fromNodeId, fromHandleId
|
|
|
1918
1962
|
handleDomNode: handleToCheck,
|
|
1919
1963
|
isValid: false,
|
|
1920
1964
|
connection: null,
|
|
1921
|
-
|
|
1965
|
+
toHandle: null,
|
|
1922
1966
|
};
|
|
1923
1967
|
if (handleToCheck) {
|
|
1924
1968
|
const handleType = getHandleType(undefined, handleToCheck);
|
|
@@ -1942,13 +1986,14 @@ function isValidHandle(event, { handle, connectionMode, fromNodeId, fromHandleId
|
|
|
1942
1986
|
(connectionMode === ConnectionMode.Strict
|
|
1943
1987
|
? (isTarget && handleType === 'source') || (!isTarget && handleType === 'target')
|
|
1944
1988
|
: handleNodeId !== fromNodeId || handleId !== fromHandleId);
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1989
|
+
result.isValid = isValid && isValidConnection(connection);
|
|
1990
|
+
if (handleLookup) {
|
|
1991
|
+
const toHandle = handleLookup.find((h) => h.id === handleId && h.nodeId === handleNodeId && h.type === handleType);
|
|
1992
|
+
if (toHandle) {
|
|
1993
|
+
result.toHandle = {
|
|
1994
|
+
...toHandle,
|
|
1995
|
+
};
|
|
1996
|
+
}
|
|
1952
1997
|
}
|
|
1953
1998
|
}
|
|
1954
1999
|
return result;
|
|
@@ -1961,6 +2006,7 @@ const XYHandle = {
|
|
|
1961
2006
|
function XYMinimap({ domNode, panZoom, getTransform, getViewScale }) {
|
|
1962
2007
|
const selection = select(domNode);
|
|
1963
2008
|
function update({ translateExtent, width, height, zoomStep = 10, pannable = true, zoomable = true, inversePan = false, }) {
|
|
2009
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1964
2010
|
const zoomHandler = (event) => {
|
|
1965
2011
|
const transform = getTransform();
|
|
1966
2012
|
if (event.sourceEvent.type !== 'wheel' || !panZoom) {
|
|
@@ -1973,6 +2019,7 @@ function XYMinimap({ domNode, panZoom, getTransform, getViewScale }) {
|
|
|
1973
2019
|
panZoom.scaleTo(nextZoom);
|
|
1974
2020
|
};
|
|
1975
2021
|
let panStart = [0, 0];
|
|
2022
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1976
2023
|
const panStartHandler = (event) => {
|
|
1977
2024
|
if (event.sourceEvent.type === 'mousedown' || event.sourceEvent.type === 'touchstart') {
|
|
1978
2025
|
panStart = [
|
|
@@ -1981,6 +2028,7 @@ function XYMinimap({ domNode, panZoom, getTransform, getViewScale }) {
|
|
|
1981
2028
|
];
|
|
1982
2029
|
}
|
|
1983
2030
|
};
|
|
2031
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1984
2032
|
const panHandler = (event) => {
|
|
1985
2033
|
const transform = getTransform();
|
|
1986
2034
|
if ((event.sourceEvent.type !== 'mousemove' && event.sourceEvent.type !== 'touchmove') || !panZoom) {
|
|
@@ -2009,8 +2057,10 @@ function XYMinimap({ domNode, panZoom, getTransform, getViewScale }) {
|
|
|
2009
2057
|
};
|
|
2010
2058
|
const zoomAndPanHandler = zoom()
|
|
2011
2059
|
.on('start', panStartHandler)
|
|
2060
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2012
2061
|
// @ts-ignore
|
|
2013
2062
|
.on('zoom', pannable ? panHandler : null)
|
|
2063
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2014
2064
|
// @ts-ignore
|
|
2015
2065
|
.on('zoom.wheel', zoomable ? zoomHandler : null);
|
|
2016
2066
|
selection.call(zoomAndPanHandler, {});
|
|
@@ -2649,8 +2699,8 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
|
|
|
2649
2699
|
}
|
|
2650
2700
|
const { xSnapped, ySnapped } = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });
|
|
2651
2701
|
prevValues = {
|
|
2652
|
-
width: node.measured
|
|
2653
|
-
height: node.measured
|
|
2702
|
+
width: node.measured.width ?? 0,
|
|
2703
|
+
height: node.measured.height ?? 0,
|
|
2654
2704
|
x: node.position.x ?? 0,
|
|
2655
2705
|
y: node.position.y ?? 0,
|
|
2656
2706
|
};
|
|
@@ -2661,11 +2711,9 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
|
|
|
2661
2711
|
aspectRatio: prevValues.width / prevValues.height,
|
|
2662
2712
|
};
|
|
2663
2713
|
parentNode = undefined;
|
|
2664
|
-
if (node.extent === 'parent' || node.expandParent) {
|
|
2714
|
+
if (node.parentId && (node.extent === 'parent' || node.expandParent)) {
|
|
2665
2715
|
parentNode = nodeLookup.get(node.parentId);
|
|
2666
|
-
|
|
2667
|
-
parentExtent = nodeToParentExtent(parentNode);
|
|
2668
|
-
}
|
|
2716
|
+
parentExtent = parentNode && node.extent === 'parent' ? nodeToParentExtent(parentNode) : undefined;
|
|
2669
2717
|
}
|
|
2670
2718
|
// Collect all child nodes to correct their relative positions when top/left changes
|
|
2671
2719
|
// Determine largest minimal extent the parent node is allowed to resize to
|
|
@@ -2712,22 +2760,13 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
|
|
|
2712
2760
|
if (!isXPosChange && !isYPosChange && !isWidthChange && !isHeightChange) {
|
|
2713
2761
|
return;
|
|
2714
2762
|
}
|
|
2715
|
-
if (isXPosChange || isYPosChange || nodeOrigin[0] === 1 || nodeOrigin[1]
|
|
2763
|
+
if (isXPosChange || isYPosChange || nodeOrigin[0] === 1 || nodeOrigin[1] === 1) {
|
|
2716
2764
|
change.x = isXPosChange ? x : prevValues.x;
|
|
2717
2765
|
change.y = isYPosChange ? y : prevValues.y;
|
|
2718
2766
|
prevValues.x = change.x;
|
|
2719
2767
|
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
|
-
}
|
|
2768
|
+
// when top/left changes, correct the relative positions of child nodes
|
|
2769
|
+
// so that they stay in the same position
|
|
2731
2770
|
if (childNodes.length > 0) {
|
|
2732
2771
|
const xChange = x - prevX;
|
|
2733
2772
|
const yChange = y - prevY;
|
|
@@ -2746,6 +2785,19 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
|
|
|
2746
2785
|
prevValues.width = change.width;
|
|
2747
2786
|
prevValues.height = change.height;
|
|
2748
2787
|
}
|
|
2788
|
+
// Fix expandParent when resizing from top/left
|
|
2789
|
+
if (parentNode && node.expandParent) {
|
|
2790
|
+
const xLimit = nodeOrigin[0] * (change.width ?? 0);
|
|
2791
|
+
if (change.x && change.x < xLimit) {
|
|
2792
|
+
prevValues.x = xLimit;
|
|
2793
|
+
startValues.x = startValues.x - (change.x - xLimit);
|
|
2794
|
+
}
|
|
2795
|
+
const yLimit = nodeOrigin[1] * (change.height ?? 0);
|
|
2796
|
+
if (change.y && change.y < yLimit) {
|
|
2797
|
+
prevValues.y = yLimit;
|
|
2798
|
+
startValues.y = startValues.y - (change.y - yLimit);
|
|
2799
|
+
}
|
|
2800
|
+
}
|
|
2749
2801
|
const direction = getResizeDirection({
|
|
2750
2802
|
width: prevValues.width,
|
|
2751
2803
|
prevWidth,
|
|
@@ -2777,4 +2829,4 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
|
|
|
2777
2829
|
};
|
|
2778
2830
|
}
|
|
2779
2831
|
|
|
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,
|
|
2832
|
+
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 };
|