@yh-ui/flow 1.0.51 → 1.0.53

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.
@@ -1,4 +1,5 @@
1
1
  import { ref } from "vue";
2
+ import { getNodeAbsolutePosition } from "../utils/custom-types.mjs";
2
3
  export function useAlignment(options) {
3
4
  const { nodes, snapThreshold = 10 } = options;
4
5
  const horizontalSnapLines = ref([]);
@@ -8,25 +9,44 @@ export function useAlignment(options) {
8
9
  if (!node) {
9
10
  return { x: position.x, y: position.y, snappedX: false, snappedY: false };
10
11
  }
11
- const nodeWidth = node.width || 200;
12
- const nodeHeight = node.height || 50;
12
+ const nodeWidth = node.measured?.width ?? node.width ?? 200;
13
+ const nodeHeight = node.measured?.height ?? node.height ?? 50;
13
14
  const otherNodes = nodes.value.filter((n) => n.id !== nodeId);
14
15
  let snappedX = false;
15
16
  let snappedY = false;
16
- const dragYPositions = [position.y, position.y + nodeHeight / 2, position.y + nodeHeight];
17
+ const nodeMap = new Map(nodes.value.map((n) => [n.id, n]));
18
+ const absPosOffset = { x: 0, y: 0 };
19
+ if (node.parentId) {
20
+ const parent = nodeMap.get(node.parentId);
21
+ if (parent) {
22
+ const parentAbsPos = getNodeAbsolutePosition(parent, nodeMap);
23
+ absPosOffset.x = parentAbsPos.x;
24
+ absPosOffset.y = parentAbsPos.y;
25
+ }
26
+ }
27
+ const proposedAbsPos = {
28
+ x: position.x + absPosOffset.x,
29
+ y: position.y + absPosOffset.y
30
+ };
31
+ const dragYPositions = [
32
+ proposedAbsPos.y,
33
+ proposedAbsPos.y + nodeHeight / 2,
34
+ proposedAbsPos.y + nodeHeight
35
+ ];
17
36
  for (const otherNode of otherNodes) {
18
- const otherHeight = otherNode.height || 50;
37
+ const otherHeight = otherNode.measured?.height ?? otherNode.height ?? 50;
38
+ const otherAbsPos = getNodeAbsolutePosition(otherNode, nodeMap);
19
39
  const otherYPositions = [
20
- otherNode.position.y,
21
- otherNode.position.y + otherHeight / 2,
22
- otherNode.position.y + otherHeight
40
+ otherAbsPos.y,
41
+ otherAbsPos.y + otherHeight / 2,
42
+ otherAbsPos.y + otherHeight
23
43
  ];
24
44
  for (let i = 0; i < dragYPositions.length; i++) {
25
45
  for (const otherY of otherYPositions) {
26
46
  if (Math.abs(dragYPositions[i] - otherY) < snapThreshold) {
27
- if (i === 0) position.y = otherY;
28
- else if (i === 1) position.y = otherY - nodeHeight / 2;
29
- else position.y = otherY - nodeHeight;
47
+ if (i === 0) proposedAbsPos.y = otherY;
48
+ else if (i === 1) proposedAbsPos.y = otherY - nodeHeight / 2;
49
+ else proposedAbsPos.y = otherY - nodeHeight;
30
50
  snappedY = true;
31
51
  break;
32
52
  }
@@ -35,20 +55,25 @@ export function useAlignment(options) {
35
55
  }
36
56
  if (snappedY) break;
37
57
  }
38
- const dragXPositions = [position.x, position.x + nodeWidth / 2, position.x + nodeWidth];
58
+ const dragXPositions = [
59
+ proposedAbsPos.x,
60
+ proposedAbsPos.x + nodeWidth / 2,
61
+ proposedAbsPos.x + nodeWidth
62
+ ];
39
63
  for (const otherNode of otherNodes) {
40
- const otherWidth = otherNode.width || 200;
64
+ const otherWidth = otherNode.measured?.width ?? otherNode.width ?? 200;
65
+ const otherAbsPos = getNodeAbsolutePosition(otherNode, nodeMap);
41
66
  const otherXPositions = [
42
- otherNode.position.x,
43
- otherNode.position.x + otherWidth / 2,
44
- otherNode.position.x + otherWidth
67
+ otherAbsPos.x,
68
+ otherAbsPos.x + otherWidth / 2,
69
+ otherAbsPos.x + otherWidth
45
70
  ];
46
71
  for (let i = 0; i < dragXPositions.length; i++) {
47
72
  for (const otherX of otherXPositions) {
48
73
  if (Math.abs(dragXPositions[i] - otherX) < snapThreshold) {
49
- if (i === 0) position.x = otherX;
50
- else if (i === 1) position.x = otherX - nodeWidth / 2;
51
- else position.x = otherX - otherWidth;
74
+ if (i === 0) proposedAbsPos.x = otherX;
75
+ else if (i === 1) proposedAbsPos.x = otherX - nodeWidth / 2;
76
+ else proposedAbsPos.x = otherX - nodeWidth;
52
77
  snappedX = true;
53
78
  break;
54
79
  }
@@ -56,7 +81,12 @@ export function useAlignment(options) {
56
81
  if (snappedX) break;
57
82
  }
58
83
  }
59
- return { x: position.x, y: position.y, snappedX, snappedY };
84
+ return {
85
+ x: proposedAbsPos.x - absPosOffset.x,
86
+ y: proposedAbsPos.y - absPosOffset.y,
87
+ snappedX,
88
+ snappedY
89
+ };
60
90
  };
61
91
  const snapToAlignment = (nodeId, position) => {
62
92
  const snapResult = getAlignmentSnap(nodeId, position);
@@ -19,7 +19,9 @@ function useKeyboard(options = {}) {
19
19
  if (!enabled) return;
20
20
  const key = event.key;
21
21
  const ctrl = event.ctrlKey || event.metaKey;
22
- if ((key === "Delete" || key === "Backspace") && !event.target?.toString().includes("Input")) {
22
+ const target = event.target;
23
+ const isEditable = target && (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.tagName === "SELECT" || target.isContentEditable === true);
24
+ if ((key === "Delete" || key === "Backspace") && !isEditable) {
23
25
  event.preventDefault();
24
26
  onDelete?.();
25
27
  }
@@ -13,7 +13,9 @@ export function useKeyboard(options = {}) {
13
13
  if (!enabled) return;
14
14
  const key = event.key;
15
15
  const ctrl = event.ctrlKey || event.metaKey;
16
- if ((key === "Delete" || key === "Backspace") && !event.target?.toString().includes("Input")) {
16
+ const target = event.target;
17
+ const isEditable = target && (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.tagName === "SELECT" || target.isContentEditable === true);
18
+ if ((key === "Delete" || key === "Backspace") && !isEditable) {
17
19
  event.preventDefault();
18
20
  onDelete?.();
19
21
  }
@@ -15,8 +15,8 @@ function useNodeDistribution(options) {
15
15
  targetNodes.sort((a, b) => a.position.x - b.position.x);
16
16
  const firstNode = targetNodes[0];
17
17
  const lastNode = targetNodes[targetNodes.length - 1];
18
- const lastWidth = lastNode.width || 200;
19
- const totalWidth = targetNodes.reduce((sum, n) => sum + (n.width || 200), 0);
18
+ const lastWidth = lastNode.measured?.width ?? lastNode.width ?? 200;
19
+ const totalWidth = targetNodes.reduce((sum, n) => sum + (n.measured?.width ?? n.width ?? 200), 0);
20
20
  const totalGap = gap * (targetNodes.length - 1);
21
21
  const availableSpace = lastNode.position.x + lastWidth - firstNode.position.x - totalWidth - totalGap;
22
22
  if (availableSpace <= 0) {
@@ -32,7 +32,7 @@ function useNodeDistribution(options) {
32
32
  }
33
33
  };
34
34
  }
35
- currentX += (node.width || 200) + gap;
35
+ currentX += (node.measured?.width ?? node.width ?? 200) + gap;
36
36
  });
37
37
  } else {
38
38
  let currentX = firstNode.position.x;
@@ -47,7 +47,7 @@ function useNodeDistribution(options) {
47
47
  }
48
48
  };
49
49
  }
50
- currentX += (node.width || 200) + gap;
50
+ currentX += (node.measured?.width ?? node.width ?? 200) + gap;
51
51
  });
52
52
  }
53
53
  };
@@ -58,8 +58,8 @@ function useNodeDistribution(options) {
58
58
  targetNodes.sort((a, b) => a.position.y - b.position.y);
59
59
  const firstNode = targetNodes[0];
60
60
  const lastNode = targetNodes[targetNodes.length - 1];
61
- const lastHeight = lastNode.height || 50;
62
- const totalHeight = targetNodes.reduce((sum, n) => sum + (n.height || 50), 0);
61
+ const lastHeight = lastNode.measured?.height ?? lastNode.height ?? 50;
62
+ const totalHeight = targetNodes.reduce((sum, n) => sum + (n.measured?.height ?? n.height ?? 50), 0);
63
63
  const totalGap = gap * (targetNodes.length - 1);
64
64
  const availableSpace = lastNode.position.y + lastHeight - firstNode.position.y - totalHeight - totalGap;
65
65
  if (availableSpace <= 0) {
@@ -75,7 +75,7 @@ function useNodeDistribution(options) {
75
75
  }
76
76
  };
77
77
  }
78
- currentY += (node.height || 50) + gap;
78
+ currentY += (node.measured?.height ?? node.height ?? 50) + gap;
79
79
  });
80
80
  } else {
81
81
  let currentY = firstNode.position.y;
@@ -90,7 +90,7 @@ function useNodeDistribution(options) {
90
90
  }
91
91
  };
92
92
  }
93
- currentY += (node.height || 50) + gap;
93
+ currentY += (node.measured?.height ?? node.height ?? 50) + gap;
94
94
  });
95
95
  }
96
96
  };
@@ -102,9 +102,9 @@ function useNodeDistribution(options) {
102
102
  if (alignment === "left") {
103
103
  referenceX = Math.min(...targetNodes.map(n => n.position.x));
104
104
  } else if (alignment === "right") {
105
- referenceX = Math.max(...targetNodes.map(n => n.position.x + (n.width || 200)));
105
+ referenceX = Math.max(...targetNodes.map(n => n.position.x + (n.measured?.width ?? n.width ?? 200)));
106
106
  } else {
107
- const centers = targetNodes.map(n => n.position.x + (n.width || 200) / 2);
107
+ const centers = targetNodes.map(n => n.position.x + (n.measured?.width ?? n.width ?? 200) / 2);
108
108
  referenceX = centers.reduce((a, b) => a + b, 0) / centers.length;
109
109
  }
110
110
  targetNodes.forEach(node => {
@@ -114,9 +114,9 @@ function useNodeDistribution(options) {
114
114
  if (alignment === "left") {
115
115
  newX = referenceX;
116
116
  } else if (alignment === "right") {
117
- newX = referenceX - (node.width || 200);
117
+ newX = referenceX - (node.measured?.width ?? node.width ?? 200);
118
118
  } else {
119
- newX = referenceX - (node.width || 200) / 2;
119
+ newX = referenceX - (node.measured?.width ?? node.width ?? 200) / 2;
120
120
  }
121
121
  nodes.value[nodeIndex] = {
122
122
  ...nodes.value[nodeIndex],
@@ -136,9 +136,9 @@ function useNodeDistribution(options) {
136
136
  if (alignment === "top") {
137
137
  referenceY = Math.min(...targetNodes.map(n => n.position.y));
138
138
  } else if (alignment === "bottom") {
139
- referenceY = Math.max(...targetNodes.map(n => n.position.y + (n.height || 50)));
139
+ referenceY = Math.max(...targetNodes.map(n => n.position.y + (n.measured?.height ?? n.height ?? 50)));
140
140
  } else {
141
- const middles = targetNodes.map(n => n.position.y + (n.height || 50) / 2);
141
+ const middles = targetNodes.map(n => n.position.y + (n.measured?.height ?? n.height ?? 50) / 2);
142
142
  referenceY = middles.reduce((a, b) => a + b, 0) / middles.length;
143
143
  }
144
144
  targetNodes.forEach(node => {
@@ -148,9 +148,9 @@ function useNodeDistribution(options) {
148
148
  if (alignment === "top") {
149
149
  newY = referenceY;
150
150
  } else if (alignment === "bottom") {
151
- newY = referenceY - (node.height || 50);
151
+ newY = referenceY - (node.measured?.height ?? node.height ?? 50);
152
152
  } else {
153
- newY = referenceY - (node.height || 50) / 2;
153
+ newY = referenceY - (node.measured?.height ?? node.height ?? 50) / 2;
154
154
  }
155
155
  nodes.value[nodeIndex] = {
156
156
  ...nodes.value[nodeIndex],
@@ -7,8 +7,11 @@ export function useNodeDistribution(options) {
7
7
  targetNodes.sort((a, b) => a.position.x - b.position.x);
8
8
  const firstNode = targetNodes[0];
9
9
  const lastNode = targetNodes[targetNodes.length - 1];
10
- const lastWidth = lastNode.width || 200;
11
- const totalWidth = targetNodes.reduce((sum, n) => sum + (n.width || 200), 0);
10
+ const lastWidth = lastNode.measured?.width ?? lastNode.width ?? 200;
11
+ const totalWidth = targetNodes.reduce(
12
+ (sum, n) => sum + (n.measured?.width ?? n.width ?? 200),
13
+ 0
14
+ );
12
15
  const totalGap = gap * (targetNodes.length - 1);
13
16
  const availableSpace = lastNode.position.x + lastWidth - firstNode.position.x - totalWidth - totalGap;
14
17
  if (availableSpace <= 0) {
@@ -21,7 +24,7 @@ export function useNodeDistribution(options) {
21
24
  position: { ...nodes.value[nodeIndex].position, x: currentX }
22
25
  };
23
26
  }
24
- currentX += (node.width || 200) + gap;
27
+ currentX += (node.measured?.width ?? node.width ?? 200) + gap;
25
28
  });
26
29
  } else {
27
30
  let currentX = firstNode.position.x;
@@ -33,7 +36,7 @@ export function useNodeDistribution(options) {
33
36
  position: { ...nodes.value[nodeIndex].position, x: currentX }
34
37
  };
35
38
  }
36
- currentX += (node.width || 200) + gap;
39
+ currentX += (node.measured?.width ?? node.width ?? 200) + gap;
37
40
  });
38
41
  }
39
42
  };
@@ -44,8 +47,11 @@ export function useNodeDistribution(options) {
44
47
  targetNodes.sort((a, b) => a.position.y - b.position.y);
45
48
  const firstNode = targetNodes[0];
46
49
  const lastNode = targetNodes[targetNodes.length - 1];
47
- const lastHeight = lastNode.height || 50;
48
- const totalHeight = targetNodes.reduce((sum, n) => sum + (n.height || 50), 0);
50
+ const lastHeight = lastNode.measured?.height ?? lastNode.height ?? 50;
51
+ const totalHeight = targetNodes.reduce(
52
+ (sum, n) => sum + (n.measured?.height ?? n.height ?? 50),
53
+ 0
54
+ );
49
55
  const totalGap = gap * (targetNodes.length - 1);
50
56
  const availableSpace = lastNode.position.y + lastHeight - firstNode.position.y - totalHeight - totalGap;
51
57
  if (availableSpace <= 0) {
@@ -58,7 +64,7 @@ export function useNodeDistribution(options) {
58
64
  position: { ...nodes.value[nodeIndex].position, y: currentY }
59
65
  };
60
66
  }
61
- currentY += (node.height || 50) + gap;
67
+ currentY += (node.measured?.height ?? node.height ?? 50) + gap;
62
68
  });
63
69
  } else {
64
70
  let currentY = firstNode.position.y;
@@ -70,7 +76,7 @@ export function useNodeDistribution(options) {
70
76
  position: { ...nodes.value[nodeIndex].position, y: currentY }
71
77
  };
72
78
  }
73
- currentY += (node.height || 50) + gap;
79
+ currentY += (node.measured?.height ?? node.height ?? 50) + gap;
74
80
  });
75
81
  }
76
82
  };
@@ -82,9 +88,13 @@ export function useNodeDistribution(options) {
82
88
  if (alignment === "left") {
83
89
  referenceX = Math.min(...targetNodes.map((n) => n.position.x));
84
90
  } else if (alignment === "right") {
85
- referenceX = Math.max(...targetNodes.map((n) => n.position.x + (n.width || 200)));
91
+ referenceX = Math.max(
92
+ ...targetNodes.map((n) => n.position.x + (n.measured?.width ?? n.width ?? 200))
93
+ );
86
94
  } else {
87
- const centers = targetNodes.map((n) => n.position.x + (n.width || 200) / 2);
95
+ const centers = targetNodes.map(
96
+ (n) => n.position.x + (n.measured?.width ?? n.width ?? 200) / 2
97
+ );
88
98
  referenceX = centers.reduce((a, b) => a + b, 0) / centers.length;
89
99
  }
90
100
  targetNodes.forEach((node) => {
@@ -94,9 +104,9 @@ export function useNodeDistribution(options) {
94
104
  if (alignment === "left") {
95
105
  newX = referenceX;
96
106
  } else if (alignment === "right") {
97
- newX = referenceX - (node.width || 200);
107
+ newX = referenceX - (node.measured?.width ?? node.width ?? 200);
98
108
  } else {
99
- newX = referenceX - (node.width || 200) / 2;
109
+ newX = referenceX - (node.measured?.width ?? node.width ?? 200) / 2;
100
110
  }
101
111
  nodes.value[nodeIndex] = {
102
112
  ...nodes.value[nodeIndex],
@@ -113,9 +123,13 @@ export function useNodeDistribution(options) {
113
123
  if (alignment === "top") {
114
124
  referenceY = Math.min(...targetNodes.map((n) => n.position.y));
115
125
  } else if (alignment === "bottom") {
116
- referenceY = Math.max(...targetNodes.map((n) => n.position.y + (n.height || 50)));
126
+ referenceY = Math.max(
127
+ ...targetNodes.map((n) => n.position.y + (n.measured?.height ?? n.height ?? 50))
128
+ );
117
129
  } else {
118
- const middles = targetNodes.map((n) => n.position.y + (n.height || 50) / 2);
130
+ const middles = targetNodes.map(
131
+ (n) => n.position.y + (n.measured?.height ?? n.height ?? 50) / 2
132
+ );
119
133
  referenceY = middles.reduce((a, b) => a + b, 0) / middles.length;
120
134
  }
121
135
  targetNodes.forEach((node) => {
@@ -125,9 +139,9 @@ export function useNodeDistribution(options) {
125
139
  if (alignment === "top") {
126
140
  newY = referenceY;
127
141
  } else if (alignment === "bottom") {
128
- newY = referenceY - (node.height || 50);
142
+ newY = referenceY - (node.measured?.height ?? node.height ?? 50);
129
143
  } else {
130
- newY = referenceY - (node.height || 50) / 2;
144
+ newY = referenceY - (node.measured?.height ?? node.height ?? 50) / 2;
131
145
  }
132
146
  nodes.value[nodeIndex] = {
133
147
  ...nodes.value[nodeIndex],
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.useSelection = useSelection;
7
7
  var _vue = require("vue");
8
+ var _customTypes = require("../utils/custom-types.cjs");
8
9
  function useSelection(options) {
9
10
  const {
10
11
  nodes,
@@ -44,10 +45,12 @@ function useSelection(options) {
44
45
  width: maxX - minX,
45
46
  height: maxY - minY
46
47
  };
48
+ const nodeMap = new Map(nodes.value.map(n => [n.id, n]));
47
49
  nodes.value = nodes.value.map(node => {
48
- const nodeWidth = node.width || 200;
49
- const nodeHeight = node.height || 50;
50
- const isInside = node.position.x >= minX && node.position.y >= minY && node.position.x + nodeWidth <= maxX && node.position.y + nodeHeight <= maxY;
50
+ const nodeWidth = node.measured?.width ?? node.width ?? 200;
51
+ const nodeHeight = node.measured?.height ?? node.height ?? 50;
52
+ const absPos = (0, _customTypes.getNodeAbsolutePosition)(node, nodeMap);
53
+ const isInside = absPos.x >= minX && absPos.y >= minY && absPos.x + nodeWidth <= maxX && absPos.y + nodeHeight <= maxY;
51
54
  return {
52
55
  ...node,
53
56
  selected: isInside
@@ -1,4 +1,5 @@
1
1
  import { ref, computed } from "vue";
2
+ import { getNodeAbsolutePosition } from "../utils/custom-types.mjs";
2
3
  export function useSelection(options) {
3
4
  const { nodes, edges, onSelectionChange } = options;
4
5
  const selectionRect = ref(null);
@@ -23,10 +24,12 @@ export function useSelection(options) {
23
24
  width: maxX - minX,
24
25
  height: maxY - minY
25
26
  };
27
+ const nodeMap = new Map(nodes.value.map((n) => [n.id, n]));
26
28
  nodes.value = nodes.value.map((node) => {
27
- const nodeWidth = node.width || 200;
28
- const nodeHeight = node.height || 50;
29
- const isInside = node.position.x >= minX && node.position.y >= minY && node.position.x + nodeWidth <= maxX && node.position.y + nodeHeight <= maxY;
29
+ const nodeWidth = node.measured?.width ?? node.width ?? 200;
30
+ const nodeHeight = node.measured?.height ?? node.height ?? 50;
31
+ const absPos = getNodeAbsolutePosition(node, nodeMap);
32
+ const isInside = absPos.x >= minX && absPos.y >= minY && absPos.x + nodeWidth <= maxX && absPos.y + nodeHeight <= maxY;
30
33
  return { ...node, selected: isInside };
31
34
  });
32
35
  };
@@ -86,8 +86,8 @@ function useViewport(initialTransform, options = {}) {
86
86
  let maxX = -Infinity;
87
87
  let maxY = -Infinity;
88
88
  for (const node of nodes) {
89
- const w = node.width || 200;
90
- const h = node.height || 50;
89
+ const w = node.measured?.width ?? node.width ?? 200;
90
+ const h = node.measured?.height ?? node.height ?? 50;
91
91
  minX = Math.min(minX, node.position.x);
92
92
  minY = Math.min(minY, node.position.y);
93
93
  maxX = Math.max(maxX, node.position.x + w);
@@ -112,8 +112,8 @@ function useViewport(initialTransform, options = {}) {
112
112
  let centerX = 0;
113
113
  let centerY = 0;
114
114
  for (const node of nodes) {
115
- const w = node.width || 200;
116
- const h = node.height || 50;
115
+ const w = node.measured?.width ?? node.width ?? 200;
116
+ const h = node.measured?.height ?? node.height ?? 50;
117
117
  centerX += node.position.x + w / 2;
118
118
  centerY += node.position.y + h / 2;
119
119
  }
@@ -28,6 +28,10 @@ export interface UseViewportReturn {
28
28
  };
29
29
  width?: number;
30
30
  height?: number;
31
+ measured?: {
32
+ width: number;
33
+ height: number;
34
+ };
31
35
  }[], options?: {
32
36
  padding?: number;
33
37
  }) => void;
@@ -41,6 +45,10 @@ export interface UseViewportReturn {
41
45
  };
42
46
  width?: number;
43
47
  height?: number;
48
+ measured?: {
49
+ width: number;
50
+ height: number;
51
+ };
44
52
  }[], options?: {
45
53
  padding?: number;
46
54
  }) => void;
@@ -58,8 +58,8 @@ export function useViewport(initialTransform, options = {}) {
58
58
  let maxX = -Infinity;
59
59
  let maxY = -Infinity;
60
60
  for (const node of nodes) {
61
- const w = node.width || 200;
62
- const h = node.height || 50;
61
+ const w = node.measured?.width ?? node.width ?? 200;
62
+ const h = node.measured?.height ?? node.height ?? 50;
63
63
  minX = Math.min(minX, node.position.x);
64
64
  minY = Math.min(minY, node.position.y);
65
65
  maxX = Math.max(maxX, node.position.x + w);
@@ -80,8 +80,8 @@ export function useViewport(initialTransform, options = {}) {
80
80
  let centerX = 0;
81
81
  let centerY = 0;
82
82
  for (const node of nodes) {
83
- const w = node.width || 200;
84
- const h = node.height || 50;
83
+ const w = node.measured?.width ?? node.width ?? 200;
84
+ const h = node.measured?.height ?? node.height ?? 50;
85
85
  centerX += node.position.x + w / 2;
86
86
  centerY += node.position.y + h / 2;
87
87
  }
@@ -34,8 +34,8 @@ async function applyDagreLayout(nodes, edges, options) {
34
34
  g.setDefaultEdgeLabel(() => ({}));
35
35
  nodes.forEach(node => {
36
36
  g.setNode(node.id, {
37
- width: node.width || 150,
38
- height: node.height || 50
37
+ width: node.measured?.width ?? node.width ?? 150,
38
+ height: node.measured?.height ?? node.height ?? 50
39
39
  });
40
40
  });
41
41
  edges.forEach(edge => {
@@ -48,8 +48,8 @@ async function applyDagreLayout(nodes, edges, options) {
48
48
  return {
49
49
  ...node,
50
50
  position: {
51
- x: layoutNode.x - (node.width || 150) / 2,
52
- y: layoutNode.y - (node.height || 50) / 2
51
+ x: layoutNode.x - (node.measured?.width ?? node.width ?? 150) / 2,
52
+ y: layoutNode.y - (node.measured?.height ?? node.height ?? 50) / 2
53
53
  }
54
54
  };
55
55
  });
@@ -88,8 +88,8 @@ async function applyElkLayout(nodes, edges, options) {
88
88
  },
89
89
  children: nodes.map(node => ({
90
90
  id: node.id,
91
- width: node.width || 150,
92
- height: node.height || 50
91
+ width: node.measured?.width ?? node.width ?? 150,
92
+ height: node.measured?.height ?? node.height ?? 50
93
93
  })),
94
94
  edges: edges.map((edge, index) => ({
95
95
  id: edge.id || `edge-${index}`,
@@ -26,8 +26,8 @@ async function applyDagreLayout(nodes, edges, options) {
26
26
  g.setDefaultEdgeLabel(() => ({}));
27
27
  nodes.forEach((node) => {
28
28
  g.setNode(node.id, {
29
- width: node.width || 150,
30
- height: node.height || 50
29
+ width: node.measured?.width ?? node.width ?? 150,
30
+ height: node.measured?.height ?? node.height ?? 50
31
31
  });
32
32
  });
33
33
  edges.forEach((edge) => {
@@ -40,8 +40,8 @@ async function applyDagreLayout(nodes, edges, options) {
40
40
  return {
41
41
  ...node,
42
42
  position: {
43
- x: layoutNode.x - (node.width || 150) / 2,
44
- y: layoutNode.y - (node.height || 50) / 2
43
+ x: layoutNode.x - (node.measured?.width ?? node.width ?? 150) / 2,
44
+ y: layoutNode.y - (node.measured?.height ?? node.height ?? 50) / 2
45
45
  }
46
46
  };
47
47
  });
@@ -81,8 +81,8 @@ async function applyElkLayout(nodes, edges, options) {
81
81
  },
82
82
  children: nodes.map((node) => ({
83
83
  id: node.id,
84
- width: node.width || 150,
85
- height: node.height || 50
84
+ width: node.measured?.width ?? node.width ?? 150,
85
+ height: node.measured?.height ?? node.height ?? 50
86
86
  })),
87
87
  edges: edges.map((edge, index) => ({
88
88
  id: edge.id || `edge-${index}`,
@@ -24,8 +24,8 @@ function computeBoundingBox(nodes, paddingX, paddingY) {
24
24
  maxX = -Infinity,
25
25
  maxY = -Infinity;
26
26
  nodes.forEach(node => {
27
- const w = node.width || 150;
28
- const h = node.height || 50;
27
+ const w = node.measured?.width ?? node.width ?? 150;
28
+ const h = node.measured?.height ?? node.height ?? 50;
29
29
  minX = Math.min(minX, node.position.x);
30
30
  minY = Math.min(minY, node.position.y);
31
31
  maxX = Math.max(maxX, node.position.x + w);
@@ -165,7 +165,15 @@ function createNodeGroupPlugin(options = {}) {
165
165
  }
166
166
  });
167
167
  if (hidden) {
168
+ const groupNode = flow.getNode(groupId);
169
+ const currentW = groupNode?.width ?? groupNode?.style?.width ?? 200;
170
+ const currentH = groupNode?.height ?? groupNode?.style?.height ?? 150;
168
171
  flow.updateNode(groupId, {
172
+ data: {
173
+ ...(groupNode?.data || {}),
174
+ _origWidth: currentW,
175
+ _origHeight: currentH
176
+ },
169
177
  style: {
170
178
  width: 160,
171
179
  height: 50,
@@ -10,8 +10,8 @@ function computeBoundingBox(nodes, paddingX, paddingY) {
10
10
  if (nodes.length === 0) return { x: 0, y: 0, width: 200, height: 150 };
11
11
  let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
12
12
  nodes.forEach((node) => {
13
- const w = node.width || 150;
14
- const h = node.height || 50;
13
+ const w = node.measured?.width ?? node.width ?? 150;
14
+ const h = node.measured?.height ?? node.height ?? 50;
15
15
  minX = Math.min(minX, node.position.x);
16
16
  minY = Math.min(minY, node.position.y);
17
17
  maxX = Math.max(maxX, node.position.x + w);
@@ -139,7 +139,15 @@ export function createNodeGroupPlugin(options = {}) {
139
139
  }
140
140
  });
141
141
  if (hidden) {
142
+ const groupNode = flow.getNode(groupId);
143
+ const currentW = groupNode?.width ?? groupNode?.style?.width ?? 200;
144
+ const currentH = groupNode?.height ?? groupNode?.style?.height ?? 150;
142
145
  flow.updateNode(groupId, {
146
+ data: {
147
+ ...groupNode?.data || {},
148
+ _origWidth: currentW,
149
+ _origHeight: currentH
150
+ },
143
151
  style: { width: 160, height: 50, minWidth: 160, minHeight: 50 },
144
152
  width: 160,
145
153
  height: 50