@xyflow/system 0.0.20 → 0.0.22

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.
Files changed (64) hide show
  1. package/dist/esm/constants.d.ts +0 -1
  2. package/dist/esm/constants.d.ts.map +1 -1
  3. package/dist/esm/index.js +297 -188
  4. package/dist/esm/index.mjs +297 -188
  5. package/dist/esm/types/changes.d.ts +50 -0
  6. package/dist/esm/types/changes.d.ts.map +1 -0
  7. package/dist/esm/types/general.d.ts +3 -3
  8. package/dist/esm/types/general.d.ts.map +1 -1
  9. package/dist/esm/types/index.d.ts +1 -0
  10. package/dist/esm/types/index.d.ts.map +1 -1
  11. package/dist/esm/types/nodes.d.ts +21 -15
  12. package/dist/esm/types/nodes.d.ts.map +1 -1
  13. package/dist/esm/utils/edges/general.d.ts +5 -6
  14. package/dist/esm/utils/edges/general.d.ts.map +1 -1
  15. package/dist/esm/utils/edges/positions.d.ts +3 -3
  16. package/dist/esm/utils/edges/positions.d.ts.map +1 -1
  17. package/dist/esm/utils/general.d.ts +3 -3
  18. package/dist/esm/utils/general.d.ts.map +1 -1
  19. package/dist/esm/utils/graph.d.ts +16 -5
  20. package/dist/esm/utils/graph.d.ts.map +1 -1
  21. package/dist/esm/utils/store.d.ts +5 -5
  22. package/dist/esm/utils/store.d.ts.map +1 -1
  23. package/dist/esm/xydrag/XYDrag.d.ts +2 -2
  24. package/dist/esm/xydrag/XYDrag.d.ts.map +1 -1
  25. package/dist/esm/xydrag/utils.d.ts +3 -3
  26. package/dist/esm/xydrag/utils.d.ts.map +1 -1
  27. package/dist/esm/xyhandle/XYHandle.d.ts +2 -2
  28. package/dist/esm/xyhandle/XYHandle.d.ts.map +1 -1
  29. package/dist/esm/xyhandle/utils.d.ts +4 -4
  30. package/dist/esm/xyhandle/utils.d.ts.map +1 -1
  31. package/dist/esm/xypanzoom/XYPanZoom.d.ts.map +1 -1
  32. package/dist/esm/xypanzoom/filter.d.ts.map +1 -1
  33. package/dist/umd/constants.d.ts +0 -1
  34. package/dist/umd/constants.d.ts.map +1 -1
  35. package/dist/umd/index.js +1 -1
  36. package/dist/umd/types/changes.d.ts +50 -0
  37. package/dist/umd/types/changes.d.ts.map +1 -0
  38. package/dist/umd/types/general.d.ts +3 -3
  39. package/dist/umd/types/general.d.ts.map +1 -1
  40. package/dist/umd/types/index.d.ts +1 -0
  41. package/dist/umd/types/index.d.ts.map +1 -1
  42. package/dist/umd/types/nodes.d.ts +21 -15
  43. package/dist/umd/types/nodes.d.ts.map +1 -1
  44. package/dist/umd/utils/edges/general.d.ts +5 -6
  45. package/dist/umd/utils/edges/general.d.ts.map +1 -1
  46. package/dist/umd/utils/edges/positions.d.ts +3 -3
  47. package/dist/umd/utils/edges/positions.d.ts.map +1 -1
  48. package/dist/umd/utils/general.d.ts +3 -3
  49. package/dist/umd/utils/general.d.ts.map +1 -1
  50. package/dist/umd/utils/graph.d.ts +16 -5
  51. package/dist/umd/utils/graph.d.ts.map +1 -1
  52. package/dist/umd/utils/store.d.ts +5 -5
  53. package/dist/umd/utils/store.d.ts.map +1 -1
  54. package/dist/umd/xydrag/XYDrag.d.ts +2 -2
  55. package/dist/umd/xydrag/XYDrag.d.ts.map +1 -1
  56. package/dist/umd/xydrag/utils.d.ts +3 -3
  57. package/dist/umd/xydrag/utils.d.ts.map +1 -1
  58. package/dist/umd/xyhandle/XYHandle.d.ts +2 -2
  59. package/dist/umd/xyhandle/XYHandle.d.ts.map +1 -1
  60. package/dist/umd/xyhandle/utils.d.ts +4 -4
  61. package/dist/umd/xyhandle/utils.d.ts.map +1 -1
  62. package/dist/umd/xypanzoom/XYPanZoom.d.ts.map +1 -1
  63. package/dist/umd/xypanzoom/filter.d.ts.map +1 -1
  64. package/package.json +1 -1
package/dist/esm/index.js CHANGED
@@ -17,7 +17,6 @@ const errorMessages = {
17
17
  error011: (edgeType) => `Edge type "${edgeType}" not found. Using fallback type "default".`,
18
18
  error012: (id) => `Node with id "${id}" does not exist, it may have been removed. This can happen when a node is deleted before the "onNodeClick" handler is called.`,
19
19
  };
20
- const internalsSymbol = Symbol.for('internals');
21
20
  const infiniteExtent = [
22
21
  [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],
23
22
  [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
@@ -120,6 +119,7 @@ const isEdgeBase = (element) => 'id' in element && 'source' in element && 'targe
120
119
  * @returns A boolean indicating whether the element is an Node
121
120
  */
122
121
  const isNodeBase = (element) => 'id' in element && 'position' in element && !('source' in element) && !('target' in element);
122
+ const isInternalNodeBase = (element) => 'id' in element && 'internals' in element && !('source' in element) && !('target' in element);
123
123
  /**
124
124
  * Pass in a node, and get connected nodes where edge.source === node.id
125
125
  * @public
@@ -182,10 +182,10 @@ const getNodePositionWithOrigin = (node, nodeOrigin = [0, 0]) => {
182
182
  };
183
183
  return {
184
184
  position,
185
- positionAbsolute: node.computed?.positionAbsolute
185
+ positionAbsolute: 'internals' in node
186
186
  ? {
187
- x: node.computed.positionAbsolute.x - offsetX,
188
- y: node.computed.positionAbsolute.y - offsetY,
187
+ x: node.internals.positionAbsolute.x - offsetX,
188
+ y: node.internals.positionAbsolute.y - offsetY,
189
189
  }
190
190
  : position,
191
191
  };
@@ -199,6 +199,7 @@ const getNodePositionWithOrigin = (node, nodeOrigin = [0, 0]) => {
199
199
  * @param params.useRelativePosition - Whether to use the relative or absolute node positions
200
200
  * @returns Bounding box enclosing all nodes
201
201
  */
202
+ // @todo how to handle this if users do not have absolute positions?
202
203
  const getNodesBounds = (nodes, params = { nodeOrigin: [0, 0], useRelativePosition: false }) => {
203
204
  if (nodes.length === 0) {
204
205
  return { x: 0, y: 0, width: 0, height: 0 };
@@ -212,7 +213,30 @@ const getNodesBounds = (nodes, params = { nodeOrigin: [0, 0], useRelativePositio
212
213
  }, { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity });
213
214
  return boxToRect(box);
214
215
  };
215
- const getNodesInside = (nodes, rect, [tx, ty, tScale] = [0, 0, 1], partially = false,
216
+ /**
217
+ * Determines a bounding box that contains all given nodes in an array
218
+ * @internal
219
+ */
220
+ const getInternalNodesBounds = (nodeLookup, params = {
221
+ nodeOrigin: [0, 0],
222
+ useRelativePosition: false,
223
+ }) => {
224
+ if (nodeLookup.size === 0) {
225
+ return { x: 0, y: 0, width: 0, height: 0 };
226
+ }
227
+ let box = { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity };
228
+ nodeLookup.forEach((node) => {
229
+ if (params.filter == undefined || params.filter(node)) {
230
+ const nodePos = getNodePositionWithOrigin(node, node.origin || params.nodeOrigin);
231
+ box = getBoundsOfBoxes(box, rectToBox({
232
+ ...nodePos[params.useRelativePosition ? 'position' : 'positionAbsolute'],
233
+ ...getNodeDimensions(node),
234
+ }));
235
+ }
236
+ });
237
+ return boxToRect(box);
238
+ };
239
+ const getNodesInside = (nodeLookup, rect, [tx, ty, tScale] = [0, 0, 1], partially = false,
216
240
  // set excludeNonSelectableNodes if you want to pay attention to the nodes "selectable" attribute
217
241
  excludeNonSelectableNodes = false, nodeOrigin = [0, 0]) => {
218
242
  const paneRect = {
@@ -220,12 +244,13 @@ excludeNonSelectableNodes = false, nodeOrigin = [0, 0]) => {
220
244
  width: rect.width / tScale,
221
245
  height: rect.height / tScale,
222
246
  };
223
- const visibleNodes = nodes.reduce((res, node) => {
224
- const { computed, selectable = true, hidden = false } = node;
225
- const width = computed?.width ?? node.width ?? node.initialWidth ?? null;
226
- const height = computed?.height ?? node.height ?? node.initialHeight ?? null;
247
+ const visibleNodes = [];
248
+ for (const [, node] of nodeLookup) {
249
+ const { measured, selectable = true, hidden = false } = node;
250
+ const width = measured.width ?? node.width ?? node.initialWidth ?? null;
251
+ const height = measured.height ?? node.height ?? node.initialHeight ?? null;
227
252
  if ((excludeNonSelectableNodes && !selectable) || hidden) {
228
- return res;
253
+ continue;
229
254
  }
230
255
  const overlappingArea = getOverlappingArea(paneRect, nodeToRect(node, nodeOrigin));
231
256
  const notInitialized = width === null || height === null;
@@ -233,10 +258,9 @@ excludeNonSelectableNodes = false, nodeOrigin = [0, 0]) => {
233
258
  const area = (width ?? 0) * (height ?? 0);
234
259
  const isVisible = notInitialized || partiallyVisible || overlappingArea >= area;
235
260
  if (isVisible || node.dragging) {
236
- res.push(node);
261
+ visibleNodes.push(node);
237
262
  }
238
- return res;
239
- }, []);
263
+ }
240
264
  return visibleNodes;
241
265
  };
242
266
  /**
@@ -252,13 +276,14 @@ const getConnectedEdges = (nodes, edges) => {
252
276
  });
253
277
  return edges.filter((edge) => nodeIds.has(edge.source) || nodeIds.has(edge.target));
254
278
  };
255
- function fitView({ nodes, width, height, panZoom, minZoom, maxZoom, nodeOrigin = [0, 0] }, options) {
256
- const filteredNodes = nodes.filter((n) => {
257
- const isVisible = n.computed?.width && n.computed?.height && (options?.includeHiddenNodes || !n.hidden);
258
- if (options?.nodes?.length) {
259
- return isVisible && options?.nodes.some((optionNode) => optionNode.id === n.id);
279
+ function fitView({ nodeLookup, width, height, panZoom, minZoom, maxZoom, nodeOrigin = [0, 0] }, options) {
280
+ const filteredNodes = [];
281
+ nodeLookup.forEach((n) => {
282
+ const isVisible = n.measured.width && n.measured.height && (options?.includeHiddenNodes || !n.hidden);
283
+ if (isVisible &&
284
+ (!options?.nodes || (options?.nodes.length && options?.nodes.some((optionNode) => optionNode.id === n.id)))) {
285
+ filteredNodes.push(n);
260
286
  }
261
- return isVisible;
262
287
  });
263
288
  if (filteredNodes.length > 0) {
264
289
  const bounds = getNodesBounds(filteredNodes, { nodeOrigin });
@@ -280,7 +305,7 @@ function clampNodeExtent(node, extent) {
280
305
  if (!extent || extent === 'parent') {
281
306
  return extent;
282
307
  }
283
- return [extent[0], [extent[1][0] - (node.computed?.width ?? 0), extent[1][1] - (node.computed?.height ?? 0)]];
308
+ return [extent[0], [extent[1][0] - (node.measured?.width ?? 0), extent[1][1] - (node.measured?.height ?? 0)]];
284
309
  }
285
310
  /**
286
311
  * This function calculates the next position of a node, taking into account the node's extent, parent node, and origin.
@@ -290,7 +315,7 @@ function clampNodeExtent(node, extent) {
290
315
  */
291
316
  function calculateNodePosition({ nodeId, nextPosition, nodeLookup, nodeOrigin = [0, 0], nodeExtent, onError, }) {
292
317
  const node = nodeLookup.get(nodeId);
293
- const parentNode = node.parentNode ? nodeLookup.get(node.parentNode) : undefined;
318
+ const parentNode = node.parentId ? nodeLookup.get(node.parentId) : undefined;
294
319
  const { x: parentX, y: parentY } = parentNode
295
320
  ? getNodePositionWithOrigin(parentNode, parentNode.origin || nodeOrigin).positionAbsolute
296
321
  : { x: 0, y: 0 };
@@ -300,10 +325,10 @@ function calculateNodePosition({ nodeId, nextPosition, nodeLookup, nodeOrigin =
300
325
  onError?.('005', errorMessages['error005']());
301
326
  }
302
327
  else {
303
- const nodeWidth = node.computed?.width;
304
- const nodeHeight = node.computed?.height;
305
- const parentWidth = parentNode?.computed?.width;
306
- const parentHeight = parentNode?.computed?.height;
328
+ const nodeWidth = node.measured.width;
329
+ const nodeHeight = node.measured.height;
330
+ const parentWidth = parentNode.measured.width;
331
+ const parentHeight = parentNode.measured.height;
307
332
  if (nodeWidth && nodeHeight && parentWidth && parentHeight) {
308
333
  const currNodeOrigin = node.origin || nodeOrigin;
309
334
  const extentX = parentX + nodeWidth * currNodeOrigin[0];
@@ -350,7 +375,7 @@ async function getElementsToRemove({ nodesToRemove = [], edgesToRemove = [], nod
350
375
  continue;
351
376
  }
352
377
  const isIncluded = nodeIds.includes(node.id);
353
- const parentHit = !isIncluded && node.parentNode && matchingNodes.find((n) => n.id === node.parentNode);
378
+ const parentHit = !isIncluded && node.parentId && matchingNodes.find((n) => n.id === node.parentId);
354
379
  if (isIncluded || parentHit) {
355
380
  matchingNodes.push(node);
356
381
  }
@@ -430,16 +455,16 @@ const nodeToRect = (node, nodeOrigin = [0, 0]) => {
430
455
  const { positionAbsolute } = getNodePositionWithOrigin(node, node.origin || nodeOrigin);
431
456
  return {
432
457
  ...positionAbsolute,
433
- width: node.computed?.width ?? node.width ?? 0,
434
- height: node.computed?.height ?? node.height ?? 0,
458
+ width: node.measured?.width ?? node.width ?? 0,
459
+ height: node.measured?.height ?? node.height ?? 0,
435
460
  };
436
461
  };
437
462
  const nodeToBox = (node, nodeOrigin = [0, 0]) => {
438
463
  const { positionAbsolute } = getNodePositionWithOrigin(node, node.origin || nodeOrigin);
439
464
  return {
440
465
  ...positionAbsolute,
441
- x2: positionAbsolute.x + (node.computed?.width ?? node.width ?? 0),
442
- y2: positionAbsolute.y + (node.computed?.height ?? node.height ?? 0),
466
+ x2: positionAbsolute.x + (node.measured?.width ?? node.width ?? 0),
467
+ y2: positionAbsolute.y + (node.measured?.height ?? node.height ?? 0),
443
468
  };
444
469
  };
445
470
  const getBoundsOfRects = (rect1, rect2) => boxToRect(getBoundsOfBoxes(rectToBox(rect1), rectToBox(rect2)));
@@ -519,13 +544,13 @@ function isCoordinateExtent(extent) {
519
544
  }
520
545
  function getNodeDimensions(node) {
521
546
  return {
522
- width: node.computed?.width ?? node.width ?? node.initialWidth ?? 0,
523
- height: node.computed?.height ?? node.height ?? node.initialHeight ?? 0,
547
+ width: node.measured?.width ?? node.width ?? node.initialWidth ?? 0,
548
+ height: node.measured?.height ?? node.height ?? node.initialHeight ?? 0,
524
549
  };
525
550
  }
526
551
  function nodeHasDimensions(node) {
527
- return ((node.computed?.width ?? node.width ?? node.initialWidth) !== undefined &&
528
- (node.computed?.height ?? node.height ?? node.initialHeight) !== undefined);
552
+ return ((node.measured?.width ?? node.width ?? node.initialWidth) !== undefined &&
553
+ (node.measured?.height ?? node.height ?? node.initialHeight) !== undefined);
529
554
  }
530
555
 
531
556
  function getPointerPosition(event, { snapGrid = [0, 0], snapToGrid = false, transform }) {
@@ -688,7 +713,7 @@ function getElevatedEdgeZIndex({ sourceNode, targetNode, selected = false, zInde
688
713
  return zIndex;
689
714
  }
690
715
  const edgeOrConnectedNodeSelected = selected || targetNode.selected || sourceNode.selected;
691
- const selectedZIndex = Math.max(sourceNode[internalsSymbol]?.z || 0, targetNode[internalsSymbol]?.z || 0, 1000);
716
+ const selectedZIndex = Math.max(sourceNode.internals.z || 0, targetNode.internals.z || 0, 1000);
692
717
  return zIndex + (edgeOrConnectedNodeSelected ? selectedZIndex : 0);
693
718
  }
694
719
  function isEdgeVisible({ sourceNode, targetNode, width, height, transform }) {
@@ -993,16 +1018,17 @@ function getSmoothStepPath({ sourceX, sourceY, sourcePosition = Position.Bottom,
993
1018
  }
994
1019
 
995
1020
  function isNodeInitialized(node) {
996
- return (!!(node?.[internalsSymbol]?.handleBounds || node?.handles?.length) &&
997
- !!(node?.computed?.width || node?.width || node?.initialWidth));
1021
+ return (node &&
1022
+ !!(node.internals.handleBounds || node.handles?.length) &&
1023
+ !!(node.measured.width || node.width || node.initialWidth));
998
1024
  }
999
1025
  function getEdgePosition(params) {
1000
1026
  const { sourceNode, targetNode } = params;
1001
1027
  if (!isNodeInitialized(sourceNode) || !isNodeInitialized(targetNode)) {
1002
1028
  return null;
1003
1029
  }
1004
- const sourceHandleBounds = sourceNode[internalsSymbol]?.handleBounds || toHandleBounds(sourceNode.handles);
1005
- const targetHandleBounds = targetNode[internalsSymbol]?.handleBounds || toHandleBounds(targetNode.handles);
1030
+ const sourceHandleBounds = sourceNode.internals.handleBounds || toHandleBounds(sourceNode.handles);
1031
+ const targetHandleBounds = targetNode.internals.handleBounds || toHandleBounds(targetNode.handles);
1006
1032
  const sourceHandle = getHandle(sourceHandleBounds?.source ?? [], params.sourceHandle);
1007
1033
  const targetHandle = getHandle(
1008
1034
  // when connection type is loose we can define all handles as sources and connect source -> source
@@ -1052,8 +1078,8 @@ function toHandleBounds(handles) {
1052
1078
  };
1053
1079
  }
1054
1080
  function getHandlePosition(position, node, handle = null) {
1055
- const x = (handle?.x ?? 0) + (node.computed?.positionAbsolute?.x ?? 0);
1056
- const y = (handle?.y ?? 0) + (node.computed?.positionAbsolute?.y ?? 0);
1081
+ const x = (handle?.x ?? 0) + (node.internals.positionAbsolute?.x ?? 0);
1082
+ const y = (handle?.y ?? 0) + (node.internals.positionAbsolute?.y ?? 0);
1057
1083
  const { width, height } = handle ?? getNodeDimensions(node);
1058
1084
  switch (position) {
1059
1085
  case Position.Top:
@@ -1144,111 +1170,176 @@ function getNodeToolbarTransform(nodeRect, viewport, position, offset, align) {
1144
1170
  return `translate(${pos[0]}px, ${pos[1]}px) translate(${shift[0]}%, ${shift[1]}%)`;
1145
1171
  }
1146
1172
 
1147
- function updateAbsolutePositions(nodes, nodeLookup, nodeOrigin = [0, 0], parentNodes) {
1148
- return nodes.map((node) => {
1149
- if (node.parentNode && !nodeLookup.has(node.parentNode)) {
1150
- throw new Error(`Parent node ${node.parentNode} not found`);
1151
- }
1152
- if (node.parentNode || parentNodes?.[node.id]) {
1153
- const parentNode = node.parentNode ? nodeLookup.get(node.parentNode) : null;
1154
- const { x, y, z } = calculateXYZPosition(node, nodes, nodeLookup, {
1173
+ function updateAbsolutePositions(nodeLookup, options = {
1174
+ nodeOrigin: [0, 0],
1175
+ elevateNodesOnSelect: true,
1176
+ defaults: {},
1177
+ }, parentNodeIds) {
1178
+ const selectedNodeZ = options?.elevateNodesOnSelect ? 1000 : 0;
1179
+ for (const [id, node] of nodeLookup) {
1180
+ const parentId = node.parentId;
1181
+ if (parentId && !nodeLookup.has(parentId)) {
1182
+ throw new Error(`Parent node ${parentId} not found`);
1183
+ }
1184
+ if (parentId || node.internals.isParent || parentNodeIds?.has(id)) {
1185
+ const parentNode = parentId ? nodeLookup.get(parentId) : null;
1186
+ const { x, y, z } = calculateXYZPosition(node, nodeLookup, {
1155
1187
  ...node.position,
1156
- z: node[internalsSymbol]?.z ?? 0,
1157
- }, parentNode?.origin || nodeOrigin);
1158
- const positionChanged = x !== node.computed?.positionAbsolute?.x || y !== node.computed?.positionAbsolute?.y;
1159
- node.computed.positionAbsolute = positionChanged
1160
- ? {
1161
- x,
1162
- y,
1163
- }
1164
- : node.computed?.positionAbsolute;
1165
- node[internalsSymbol].z = z;
1166
- if (parentNodes?.[node.id]) {
1167
- node[internalsSymbol].isParent = true;
1188
+ z: (isNumeric(node.zIndex) ? node.zIndex : 0) + (node.selected ? selectedNodeZ : 0),
1189
+ }, parentNode?.origin || options.nodeOrigin);
1190
+ const currPosition = node.internals.positionAbsolute;
1191
+ const positionChanged = x !== currPosition.x || y !== currPosition.y;
1192
+ node.internals.positionAbsolute = positionChanged ? { x, y } : currPosition;
1193
+ node.internals.z = z;
1194
+ if (parentNodeIds !== undefined) {
1195
+ node.internals.isParent = !!parentNodeIds?.has(id);
1168
1196
  }
1197
+ nodeLookup.set(id, node);
1169
1198
  }
1170
- return node;
1171
- });
1199
+ }
1172
1200
  }
1173
- function adoptUserProvidedNodes(nodes, nodeLookup, options = {
1201
+ function adoptUserNodes(nodes, nodeLookup, options = {
1174
1202
  nodeOrigin: [0, 0],
1175
1203
  elevateNodesOnSelect: true,
1176
1204
  defaults: {},
1177
1205
  }) {
1178
1206
  const tmpLookup = new Map(nodeLookup);
1179
1207
  nodeLookup.clear();
1180
- const parentNodes = {};
1181
1208
  const selectedNodeZ = options?.elevateNodesOnSelect ? 1000 : 0;
1182
- const nextNodes = nodes.map((n) => {
1183
- const currentStoreNode = tmpLookup.get(n.id);
1184
- if (n === currentStoreNode?.[internalsSymbol]?.userProvidedNode) {
1185
- nodeLookup.set(n.id, currentStoreNode);
1186
- return currentStoreNode;
1187
- }
1188
- const node = {
1189
- ...options.defaults,
1190
- ...n,
1191
- computed: {
1192
- positionAbsolute: n.position,
1193
- width: n.computed?.width,
1194
- height: n.computed?.height,
1195
- },
1196
- };
1197
- const z = (isNumeric(n.zIndex) ? n.zIndex : 0) + (n.selected ? selectedNodeZ : 0);
1198
- const currInternals = n?.[internalsSymbol] || currentStoreNode?.[internalsSymbol];
1199
- if (node.parentNode) {
1200
- parentNodes[node.parentNode] = true;
1201
- }
1202
- Object.defineProperty(node, internalsSymbol, {
1203
- enumerable: false,
1204
- value: {
1205
- handleBounds: currInternals?.handleBounds,
1206
- z,
1207
- userProvidedNode: n,
1208
- },
1209
- });
1210
- nodeLookup.set(node.id, node);
1211
- return node;
1209
+ const parentNodeIds = new Set();
1210
+ nodes.forEach((userNode) => {
1211
+ const currentStoreNode = tmpLookup.get(userNode.id);
1212
+ if (userNode.parentId) {
1213
+ parentNodeIds.add(userNode.parentId);
1214
+ }
1215
+ if (userNode === currentStoreNode?.internals.userNode) {
1216
+ nodeLookup.set(userNode.id, currentStoreNode);
1217
+ }
1218
+ else {
1219
+ nodeLookup.set(userNode.id, {
1220
+ ...options.defaults,
1221
+ ...userNode,
1222
+ measured: {
1223
+ width: userNode.measured?.width,
1224
+ height: userNode.measured?.height,
1225
+ },
1226
+ internals: {
1227
+ positionAbsolute: userNode.position,
1228
+ handleBounds: currentStoreNode?.internals?.handleBounds,
1229
+ z: (isNumeric(userNode.zIndex) ? userNode.zIndex : 0) + (userNode.selected ? selectedNodeZ : 0),
1230
+ userNode,
1231
+ isParent: false,
1232
+ },
1233
+ });
1234
+ }
1212
1235
  });
1213
- const nodesWithPositions = updateAbsolutePositions(nextNodes, nodeLookup, options.nodeOrigin, parentNodes);
1214
- return nodesWithPositions;
1236
+ if (parentNodeIds.size > 0) {
1237
+ updateAbsolutePositions(nodeLookup, options, parentNodeIds);
1238
+ }
1215
1239
  }
1216
- function calculateXYZPosition(node, nodes, nodeLookup, result, nodeOrigin) {
1217
- if (!node.parentNode) {
1240
+ function calculateXYZPosition(node, nodeLookup, result, nodeOrigin = [0, 0]) {
1241
+ if (!node.parentId) {
1218
1242
  return result;
1219
1243
  }
1220
- const parentNode = nodeLookup.get(node.parentNode);
1244
+ const parentNode = nodeLookup.get(node.parentId);
1221
1245
  const { position: parentNodePosition } = getNodePositionWithOrigin(parentNode, parentNode?.origin || nodeOrigin);
1222
- return calculateXYZPosition(parentNode, nodes, nodeLookup, {
1246
+ return calculateXYZPosition(parentNode, nodeLookup, {
1223
1247
  x: (result.x ?? 0) + parentNodePosition.x,
1224
1248
  y: (result.y ?? 0) + parentNodePosition.y,
1225
- z: (parentNode[internalsSymbol]?.z ?? 0) > (result.z ?? 0) ? parentNode[internalsSymbol]?.z ?? 0 : result.z ?? 0,
1249
+ z: (parentNode.internals.z ?? 0) > (result.z ?? 0) ? parentNode.internals.z ?? 0 : result.z ?? 0,
1226
1250
  }, parentNode.origin || nodeOrigin);
1227
1251
  }
1228
- function updateNodeDimensions(updates, nodes, nodeLookup, domNode, nodeOrigin, onUpdate) {
1252
+ function handleParentExpand(nodes, nodeLookup) {
1253
+ const changes = [];
1254
+ const chilNodeRects = new Map();
1255
+ nodes.forEach((node) => {
1256
+ const parentId = node.parentId;
1257
+ if (node.expandParent && parentId) {
1258
+ const parentNode = nodeLookup.get(parentId);
1259
+ if (parentNode) {
1260
+ const parentRect = chilNodeRects.get(parentId) || nodeToRect(parentNode, node.origin);
1261
+ const expandedRect = getBoundsOfRects(parentRect, nodeToRect(node, node.origin));
1262
+ chilNodeRects.set(parentId, expandedRect);
1263
+ }
1264
+ }
1265
+ });
1266
+ if (chilNodeRects.size > 0) {
1267
+ chilNodeRects.forEach((rect, id) => {
1268
+ const origParent = nodeLookup.get(id);
1269
+ const { position } = getNodePositionWithOrigin(origParent, origParent.origin);
1270
+ const dimensions = getNodeDimensions(origParent);
1271
+ if (rect.x < position.x || rect.y < position.y) {
1272
+ const xChange = Math.round(Math.abs(position.x - rect.x));
1273
+ const yChange = Math.round(Math.abs(position.y - rect.y));
1274
+ changes.push({
1275
+ id,
1276
+ type: 'position',
1277
+ position: {
1278
+ x: position.x - xChange,
1279
+ y: position.y - yChange,
1280
+ },
1281
+ });
1282
+ changes.push({
1283
+ id,
1284
+ type: 'dimensions',
1285
+ resizing: true,
1286
+ dimensions: {
1287
+ width: dimensions.width + xChange,
1288
+ height: dimensions.height + yChange,
1289
+ },
1290
+ });
1291
+ // @todo we need to reset child node positions if < 0
1292
+ }
1293
+ else if (dimensions.width < rect.width || dimensions.height < rect.height) {
1294
+ changes.push({
1295
+ id,
1296
+ type: 'dimensions',
1297
+ resizing: true,
1298
+ dimensions: {
1299
+ width: Math.max(dimensions.width, rect.width),
1300
+ height: Math.max(dimensions.height, rect.height),
1301
+ },
1302
+ });
1303
+ }
1304
+ });
1305
+ }
1306
+ return changes;
1307
+ }
1308
+ function updateNodeDimensions(updates, nodeLookup, domNode, nodeOrigin) {
1229
1309
  const viewportNode = domNode?.querySelector('.xyflow__viewport');
1230
1310
  if (!viewportNode) {
1231
- return null;
1311
+ return [];
1232
1312
  }
1313
+ const changes = [];
1233
1314
  const style = window.getComputedStyle(viewportNode);
1234
1315
  const { m22: zoom } = new window.DOMMatrixReadOnly(style.transform);
1235
- const nextNodes = nodes.map((node) => {
1236
- const update = updates.get(node.id);
1237
- if (update) {
1316
+ // in this array we collect nodes, that might trigger changes (like expanding parent)
1317
+ const triggerChangeNodes = [];
1318
+ updates.forEach((update) => {
1319
+ const node = nodeLookup.get(update.id);
1320
+ if (node?.hidden) {
1321
+ nodeLookup.set(node.id, {
1322
+ ...node,
1323
+ internals: {
1324
+ ...node.internals,
1325
+ handleBounds: undefined,
1326
+ },
1327
+ });
1328
+ }
1329
+ else if (node) {
1238
1330
  const dimensions = getDimensions(update.nodeElement);
1239
1331
  const doUpdate = !!(dimensions.width &&
1240
1332
  dimensions.height &&
1241
- (node.computed?.width !== dimensions.width || node.computed?.height !== dimensions.height || update.forceUpdate));
1333
+ (node.measured?.width !== dimensions.width || node.measured?.height !== dimensions.height || update.force));
1242
1334
  if (doUpdate) {
1243
- onUpdate?.(node.id, dimensions);
1244
1335
  const newNode = {
1245
1336
  ...node,
1246
- computed: {
1247
- ...node.computed,
1337
+ measured: {
1338
+ ...node.measured,
1248
1339
  ...dimensions,
1249
1340
  },
1250
- [internalsSymbol]: {
1251
- ...node[internalsSymbol],
1341
+ internals: {
1342
+ ...node.internals,
1252
1343
  handleBounds: {
1253
1344
  source: getHandleBounds('.source', update.nodeElement, zoom, node.origin || nodeOrigin),
1254
1345
  target: getHandleBounds('.target', update.nodeElement, zoom, node.origin || nodeOrigin),
@@ -1256,12 +1347,22 @@ function updateNodeDimensions(updates, nodes, nodeLookup, domNode, nodeOrigin, o
1256
1347
  },
1257
1348
  };
1258
1349
  nodeLookup.set(node.id, newNode);
1259
- return newNode;
1350
+ changes.push({
1351
+ id: newNode.id,
1352
+ type: 'dimensions',
1353
+ dimensions,
1354
+ });
1355
+ if (newNode.expandParent) {
1356
+ triggerChangeNodes.push(newNode);
1357
+ }
1260
1358
  }
1261
1359
  }
1262
- return node;
1263
1360
  });
1264
- return nextNodes;
1361
+ if (triggerChangeNodes.length > 0) {
1362
+ const parentExpandChanges = handleParentExpand(triggerChangeNodes, nodeLookup);
1363
+ changes.push(...parentExpandChanges);
1364
+ }
1365
+ return changes;
1265
1366
  }
1266
1367
  function panBy({ delta, panZoom, transform, translateExtent, width, height, }) {
1267
1368
  if (!panZoom || (!delta.x && !delta.y)) {
@@ -1315,18 +1416,18 @@ function shallowNodeData(a, b) {
1315
1416
  function wrapSelectionDragFunc(selectionFunc) {
1316
1417
  return (event, _, nodes) => selectionFunc?.(event, nodes);
1317
1418
  }
1318
- function isParentSelected(node, nodes) {
1319
- if (!node.parentNode) {
1419
+ function isParentSelected(node, nodeLookup) {
1420
+ if (!node.parentId) {
1320
1421
  return false;
1321
1422
  }
1322
- const parentNode = nodes.find((node) => node.id === node.parentNode);
1423
+ const parentNode = nodeLookup.get(node.parentId);
1323
1424
  if (!parentNode) {
1324
1425
  return false;
1325
1426
  }
1326
1427
  if (parentNode.selected) {
1327
1428
  return true;
1328
1429
  }
1329
- return isParentSelected(parentNode, nodes);
1430
+ return isParentSelected(parentNode, nodeLookup);
1330
1431
  }
1331
1432
  function hasSelector(target, selector, domNode) {
1332
1433
  let current = target;
@@ -1340,32 +1441,35 @@ function hasSelector(target, selector, domNode) {
1340
1441
  return false;
1341
1442
  }
1342
1443
  // looks for all selected nodes and created a NodeDragItem for each of them
1343
- function getDragItems(nodes, nodesDraggable, mousePos, nodeId) {
1344
- return nodes
1345
- .filter((n) => (n.selected || n.id === nodeId) &&
1346
- (!n.parentNode || !isParentSelected(n, nodes)) &&
1347
- (n.draggable || (nodesDraggable && typeof n.draggable === 'undefined')))
1348
- .map((n) => ({
1349
- id: n.id,
1350
- position: n.position || { x: 0, y: 0 },
1351
- distance: {
1352
- x: mousePos.x - (n.computed?.positionAbsolute?.x ?? 0),
1353
- y: mousePos.y - (n.computed?.positionAbsolute?.y ?? 0),
1354
- },
1355
- delta: {
1356
- x: 0,
1357
- y: 0,
1358
- },
1359
- extent: n.extent,
1360
- parentNode: n.parentNode,
1361
- origin: n.origin,
1362
- expandParent: n.expandParent,
1363
- computed: {
1364
- positionAbsolute: n.computed?.positionAbsolute || { x: 0, y: 0 },
1365
- width: n.computed?.width || 0,
1366
- height: n.computed?.height || 0,
1367
- },
1368
- }));
1444
+ function getDragItems(nodeLookup, nodesDraggable, mousePos, nodeId) {
1445
+ const dragItems = [];
1446
+ for (const [id, node] of nodeLookup) {
1447
+ if ((node.selected || node.id === nodeId) &&
1448
+ (!node.parentId || !isParentSelected(node, nodeLookup)) &&
1449
+ (node.draggable || (nodesDraggable && typeof node.draggable === 'undefined'))) {
1450
+ const internalNode = nodeLookup.get(id);
1451
+ dragItems.push({
1452
+ id: internalNode.id,
1453
+ position: internalNode.position || { x: 0, y: 0 },
1454
+ distance: {
1455
+ x: mousePos.x - (internalNode.internals.positionAbsolute?.x ?? 0),
1456
+ y: mousePos.y - (internalNode.internals.positionAbsolute?.y ?? 0),
1457
+ },
1458
+ extent: internalNode.extent,
1459
+ parentId: internalNode.parentId,
1460
+ origin: internalNode.origin,
1461
+ expandParent: internalNode.expandParent,
1462
+ internals: {
1463
+ positionAbsolute: internalNode.internals.positionAbsolute || { x: 0, y: 0 },
1464
+ },
1465
+ measured: {
1466
+ width: internalNode.measured.width || 0,
1467
+ height: internalNode.measured.height || 0,
1468
+ },
1469
+ });
1470
+ }
1471
+ }
1472
+ return dragItems;
1369
1473
  }
1370
1474
  // returns two params:
1371
1475
  // 1. the dragged node (or the first of the list, if we are dragging a node selection)
@@ -1376,9 +1480,8 @@ function getEventHandlerParams({ nodeId, dragItems, nodeLookup, }) {
1376
1480
  return {
1377
1481
  ...node,
1378
1482
  position: n.position,
1379
- computed: {
1380
- ...n.computed,
1381
- positionAbsolute: n.computed.positionAbsolute,
1483
+ measured: {
1484
+ ...n.measured,
1382
1485
  },
1383
1486
  };
1384
1487
  });
@@ -1414,17 +1517,20 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
1414
1517
  }
1415
1518
  // if there is selection with multiple nodes and a node extent is set, we need to adjust the node extent for each node
1416
1519
  // based on its position so that the node stays at it's position relative to the selection.
1417
- const adjustedNodeExtent = [
1520
+ let adjustedNodeExtent = [
1418
1521
  [nodeExtent[0][0], nodeExtent[0][1]],
1419
1522
  [nodeExtent[1][0], nodeExtent[1][1]],
1420
1523
  ];
1421
1524
  if (dragItems.length > 1 && nodeExtent && !n.extent) {
1422
- adjustedNodeExtent[0][0] = n.computed.positionAbsolute.x - nodesBox.x + nodeExtent[0][0];
1423
- adjustedNodeExtent[1][0] =
1424
- n.computed.positionAbsolute.x + (n.computed?.width ?? 0) - nodesBox.x2 + nodeExtent[1][0];
1425
- adjustedNodeExtent[0][1] = n.computed.positionAbsolute.y - nodesBox.y + nodeExtent[0][1];
1426
- adjustedNodeExtent[1][1] =
1427
- n.computed.positionAbsolute.y + (n.computed?.height ?? 0) - nodesBox.y2 + nodeExtent[1][1];
1525
+ const { positionAbsolute } = n.internals;
1526
+ const x1 = positionAbsolute.x - nodesBox.x + nodeExtent[0][0];
1527
+ const x2 = positionAbsolute.x + (n.measured?.width ?? 0) - nodesBox.x2 + nodeExtent[1][0];
1528
+ const y1 = positionAbsolute.y - nodesBox.y + nodeExtent[0][1];
1529
+ const y2 = positionAbsolute.y + (n.measured?.height ?? 0) - nodesBox.y2 + nodeExtent[1][1];
1530
+ adjustedNodeExtent = [
1531
+ [x1, y1],
1532
+ [x2, y2],
1533
+ ];
1428
1534
  }
1429
1535
  const { position, positionAbsolute } = calculateNodePosition({
1430
1536
  nodeId: n.id,
@@ -1437,7 +1543,7 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
1437
1543
  // we want to make sure that we only fire a change event when there is a change
1438
1544
  hasChange = hasChange || n.position.x !== position.x || n.position.y !== position.y;
1439
1545
  n.position = position;
1440
- n.computed.positionAbsolute = positionAbsolute;
1546
+ n.internals.positionAbsolute = positionAbsolute;
1441
1547
  return n;
1442
1548
  });
1443
1549
  if (!hasChange) {
@@ -1474,7 +1580,7 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
1474
1580
  autoPanId = requestAnimationFrame(autoPan);
1475
1581
  }
1476
1582
  function startDrag(event) {
1477
- const { nodes, nodeLookup, multiSelectionActive, nodesDraggable, transform, snapGrid, snapToGrid, selectNodesOnDrag, onNodeDragStart, onSelectionDragStart, unselectNodesAndEdges, } = getStoreItems();
1583
+ const { nodeLookup, multiSelectionActive, nodesDraggable, transform, snapGrid, snapToGrid, selectNodesOnDrag, onNodeDragStart, onSelectionDragStart, unselectNodesAndEdges, } = getStoreItems();
1478
1584
  dragStarted = true;
1479
1585
  if ((!selectNodesOnDrag || !isSelectable) && !multiSelectionActive && nodeId) {
1480
1586
  if (!nodeLookup.get(nodeId)?.selected) {
@@ -1487,7 +1593,7 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
1487
1593
  }
1488
1594
  const pointerPos = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });
1489
1595
  lastPos = pointerPos;
1490
- dragItems = getDragItems(nodes, nodesDraggable, pointerPos, nodeId);
1596
+ dragItems = getDragItems(nodeLookup, nodesDraggable, pointerPos, nodeId);
1491
1597
  if (dragItems.length > 0 && (onDragStart || onNodeDragStart || (!nodeId && onSelectionDragStart))) {
1492
1598
  const [currentNode, currentNodes] = getEventHandlerParams({
1493
1599
  nodeId,
@@ -1587,8 +1693,8 @@ function getHandles(node, handleBounds, type, currentHandle) {
1587
1693
  id: h.id || null,
1588
1694
  type,
1589
1695
  nodeId: node.id,
1590
- x: (node.computed?.positionAbsolute?.x ?? 0) + h.x + h.width / 2,
1591
- y: (node.computed?.positionAbsolute?.y ?? 0) + h.y + h.height / 2,
1696
+ x: (node.internals.positionAbsolute.x ?? 0) + h.x + h.width / 2,
1697
+ y: (node.internals.positionAbsolute.y ?? 0) + h.y + h.height / 2,
1592
1698
  });
1593
1699
  }
1594
1700
  return res;
@@ -1618,20 +1724,17 @@ function getClosestHandle(pos, connectionRadius, handles) {
1618
1724
  : // if multiple handles are layouted on top of each other we take the one with type = target because it's more likely that the user wants to connect to this one
1619
1725
  closestHandles.find((handle) => handle.type === 'target') || closestHandles[0];
1620
1726
  }
1621
- function getHandleLookup({ nodes, nodeId, handleId, handleType }) {
1622
- return nodes.reduce((res, node) => {
1623
- if (node[internalsSymbol]) {
1624
- const { handleBounds } = node[internalsSymbol];
1625
- let sourceHandles = [];
1626
- let targetHandles = [];
1627
- if (handleBounds) {
1628
- sourceHandles = getHandles(node, handleBounds, 'source', `${nodeId}-${handleId}-${handleType}`);
1629
- targetHandles = getHandles(node, handleBounds, 'target', `${nodeId}-${handleId}-${handleType}`);
1630
- }
1631
- res.push(...sourceHandles, ...targetHandles);
1727
+ function getHandleLookup({ nodeLookup, nodeId, handleId, handleType, }) {
1728
+ const connectionHandles = [];
1729
+ for (const [, node] of nodeLookup) {
1730
+ if (node.internals.handleBounds) {
1731
+ const id = `${nodeId}-${handleId}-${handleType}`;
1732
+ const sourceHandles = getHandles(node, node.internals.handleBounds, 'source', id);
1733
+ const targetHandles = getHandles(node, node.internals.handleBounds, 'target', id);
1734
+ connectionHandles.push(...sourceHandles, ...targetHandles);
1632
1735
  }
1633
- return res;
1634
- }, []);
1736
+ }
1737
+ return connectionHandles;
1635
1738
  }
1636
1739
  function getHandleType(edgeUpdaterType, handleDomNode) {
1637
1740
  if (edgeUpdaterType) {
@@ -1658,7 +1761,7 @@ function getConnectionStatus(isInsideConnectionRadius, isHandleValid) {
1658
1761
 
1659
1762
  const alwaysValid = () => true;
1660
1763
  let connectionStartHandle = null;
1661
- function onPointerDown(event, { connectionMode, connectionRadius, handleId, nodeId, edgeUpdaterType, isTarget, domNode, nodes, lib, autoPanOnConnect, flowId, panBy, cancelConnection, onConnectStart, onConnect, onConnectEnd, isValidConnection = alwaysValid, onEdgeUpdateEnd, updateConnection, getTransform, getConnectionStartHandle, }) {
1764
+ 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, }) {
1662
1765
  // when xyflow is used inside a shadow root we can't use document
1663
1766
  const doc = getHostForElement(event.target);
1664
1767
  let autoPanId = 0;
@@ -1676,7 +1779,7 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
1676
1779
  let isValid = false;
1677
1780
  let handleDomNode = null;
1678
1781
  const handleLookup = getHandleLookup({
1679
- nodes,
1782
+ nodeLookup,
1680
1783
  nodeId,
1681
1784
  handleId,
1682
1785
  handleType,
@@ -2021,10 +2124,6 @@ function createFilter({ zoomActivationKeyPressed, zoomOnScroll, zoomOnPinch, pan
2021
2124
  if (userSelectionActive) {
2022
2125
  return false;
2023
2126
  }
2024
- // if zoom on double click is disabled, we prevent the double click event
2025
- if (!zoomOnDoubleClick && event.type === 'dblclick') {
2026
- return false;
2027
- }
2028
2127
  // if the target element is inside an element with the nowheel class, we prevent zooming
2029
2128
  if (isWrappedWithClass(event, noWheelClassName) && event.type === 'wheel') {
2030
2129
  return false;
@@ -2080,6 +2179,7 @@ function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPan
2080
2179
  [bbox.width, bbox.height],
2081
2180
  ], translateExtent);
2082
2181
  const d3ZoomHandler = d3Selection.on('wheel.zoom');
2182
+ const d3DblClickZoomHandler = d3Selection.on('dblclick.zoom');
2083
2183
  d3ZoomInstance.wheelDelta(wheelDelta);
2084
2184
  function setTransform(transform, options) {
2085
2185
  if (d3Selection) {
@@ -2152,6 +2252,15 @@ function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPan
2152
2252
  lib,
2153
2253
  });
2154
2254
  d3ZoomInstance.filter(filter);
2255
+ // We cannot add zoomOnDoubleClick to the filter above because
2256
+ // double tapping on touch screens circumvents the filter and
2257
+ // dblclick.zoom is fired on the selection directly
2258
+ if (zoomOnDoubleClick) {
2259
+ d3Selection.on('dblclick.zoom', d3DblClickZoomHandler);
2260
+ }
2261
+ else {
2262
+ d3Selection.on('dblclick.zoom', null);
2263
+ }
2155
2264
  }
2156
2265
  function destroy() {
2157
2266
  d3ZoomInstance.on('zoom', null);
@@ -2462,14 +2571,14 @@ const initChange = {
2462
2571
  function nodeToParentExtent(node) {
2463
2572
  return [
2464
2573
  [0, 0],
2465
- [node.computed.width, node.computed.height],
2574
+ [node.measured.width, node.measured.height],
2466
2575
  ];
2467
2576
  }
2468
2577
  function nodeToChildExtent(child, parent, nodeOrigin) {
2469
2578
  const x = parent.position.x + child.position.x;
2470
2579
  const y = parent.position.y + child.position.y;
2471
- const width = child.computed.width ?? 0;
2472
- const height = child.computed.height ?? 0;
2580
+ const width = child.measured.width ?? 0;
2581
+ const height = child.measured.height ?? 0;
2473
2582
  const originOffsetX = nodeOrigin[0] * width;
2474
2583
  const originOffsetY = nodeOrigin[1] * height;
2475
2584
  return [
@@ -2495,8 +2604,8 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange }) {
2495
2604
  if (node) {
2496
2605
  const { xSnapped, ySnapped } = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });
2497
2606
  prevValues = {
2498
- width: node.computed?.width ?? 0,
2499
- height: node.computed?.height ?? 0,
2607
+ width: node.measured?.width ?? 0,
2608
+ height: node.measured?.height ?? 0,
2500
2609
  x: node.position.x ?? 0,
2501
2610
  y: node.position.y ?? 0,
2502
2611
  };
@@ -2508,7 +2617,7 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange }) {
2508
2617
  };
2509
2618
  parentNode = undefined;
2510
2619
  if (node.extent === 'parent' || node.expandParent) {
2511
- parentNode = nodeLookup.get(node.parentNode);
2620
+ parentNode = nodeLookup.get(node.parentId);
2512
2621
  if (parentNode && node.extent === 'parent') {
2513
2622
  parentExtent = nodeToParentExtent(parentNode);
2514
2623
  }
@@ -2518,7 +2627,7 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange }) {
2518
2627
  childNodes = [];
2519
2628
  childExtent = undefined;
2520
2629
  for (const [childId, child] of nodeLookup) {
2521
- if (child.parentNode === nodeId) {
2630
+ if (child.parentId === nodeId) {
2522
2631
  childNodes.push({
2523
2632
  id: childId,
2524
2633
  position: { ...child.position },
@@ -2626,4 +2735,4 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange }) {
2626
2735
  };
2627
2736
  }
2628
2737
 
2629
- export { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, ResizeControlVariant, SelectionMode, XYDrag, XYHandle, XYMinimap, XYPanZoom, XYResizer, XY_RESIZER_HANDLE_POSITIONS, XY_RESIZER_LINE_POSITIONS, addEdge, adoptUserProvidedNodes, areConnectionMapsEqual, boxToRect, calcAutoPan, calculateNodePosition, clamp, clampPosition, createMarkerIds, devWarn, elementSelectionKeys, errorMessages, fitView, getBezierEdgeCenter, getBezierPath, getBoundsOfBoxes, getBoundsOfRects, getConnectedEdges, getDimensions, getEdgeCenter, getEdgePosition, getElementsToRemove, getElevatedEdgeZIndex, getEventPosition, getHandleBounds, getHostForElement, getIncomers, getMarkerId, getNodeDimensions, getNodePositionWithOrigin, getNodeToolbarTransform, getNodesBounds, getNodesInside, getOutgoers, getOverlappingArea, getPointerPosition, getPositionWithOrigin, getSmoothStepPath, getStraightPath, getViewportForBounds, handleConnectionChange, infiniteExtent, internalsSymbol, isCoordinateExtent, isEdgeBase, isEdgeVisible, isInputDOMNode, isMacOs, isMouseEvent, isNodeBase, isNumeric, isRectObject, nodeHasDimensions, nodeToBox, nodeToRect, panBy, pointToRendererPoint, rectToBox, rendererPointToPoint, shallowNodeData, snapPosition, updateAbsolutePositions, updateConnectionLookup, updateEdge, updateNodeDimensions };
2738
+ 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, 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, getPositionWithOrigin, getSmoothStepPath, getStraightPath, getViewportForBounds, handleConnectionChange, handleParentExpand, infiniteExtent, isCoordinateExtent, isEdgeBase, isEdgeVisible, isInputDOMNode, isInternalNodeBase, isMacOs, isMouseEvent, isNodeBase, isNumeric, isRectObject, nodeHasDimensions, nodeToBox, nodeToRect, panBy, pointToRendererPoint, rectToBox, rendererPointToPoint, shallowNodeData, snapPosition, updateAbsolutePositions, updateConnectionLookup, updateEdge, updateNodeDimensions };