Skip to content

Commit 12b65b2

Browse files
committed
Restore node min-width in Vue compat layout and add regression tests
1 parent 5b63381 commit 12b65b2

2 files changed

Lines changed: 103 additions & 4 deletions

File tree

js/node/resolution_master_node_lifecycle.js

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,31 @@ export const nodeLifecycleMethods = {
4747
: minimumHeight;
4848
},
4949

50+
getVueCompatMinimumWidth() {
51+
return Math.max(0, Number(this.node.min_size?.[0]) || 330);
52+
},
53+
54+
applyVueCompatMinimumWidth() {
55+
if (!this.isVueNodesMode()) return false;
56+
57+
const minimumWidth = this.getVueCompatMinimumWidth();
58+
const currentWidth = Number(this.node.size?.[0]) || 0;
59+
if (currentWidth >= minimumWidth) return false;
60+
61+
const currentHeight = Number(this.node.size?.[1]) || this.node.min_size?.[1] || 200;
62+
this._isApplyingAutoSize = true;
63+
try {
64+
if (typeof this.node.setSize === "function") {
65+
this.node.setSize([minimumWidth, currentHeight]);
66+
} else {
67+
this.node.size = [minimumWidth, currentHeight];
68+
}
69+
} finally {
70+
this._isApplyingAutoSize = false;
71+
}
72+
return true;
73+
},
74+
5075
getVueCompatBottomBadgeClearance() {
5176
return this.isVueNodesMode() && this.collapsedSections?.extraControls ? -23 : 0;
5277
},
@@ -72,11 +97,16 @@ export const nodeLifecycleMethods = {
7297
Math.ceil(Number(widgetHeight) || 0),
7398
this.node.min_size?.[1] || 200
7499
);
75-
if (this._vueCompatAutoSizedContentHeight === targetHeight) return;
100+
const targetWidth = Math.max(
101+
Number(this.node.size?.[0]) || 0,
102+
this.getVueCompatMinimumWidth()
103+
);
104+
const widthMatches = Math.abs((Number(this.node.size?.[0]) || 0) - targetWidth) <= 1;
105+
const heightMatches = Math.abs((Number(this.node.size?.[1]) || 0) - targetHeight) <= 1;
106+
if (this._vueCompatAutoSizedContentHeight === targetHeight && widthMatches && heightMatches) return;
76107

77108
this._vueCompatAutoSizedContentHeight = targetHeight;
78-
const targetWidth = Math.max(Number(this.node.size?.[0]) || 0, 330);
79-
if (Math.abs((Number(this.node.size?.[1]) || 0) - targetHeight) <= 1) return;
109+
if (widthMatches && heightMatches) return;
80110

81111
this._isApplyingAutoSize = true;
82112
try {
@@ -119,6 +149,7 @@ export const nodeLifecycleMethods = {
119149
this._vueCompatWidgetHeight = height;
120150
if (this.collapsedSections?.extraControls) {
121151
this._vueCompatAutoSizedContentHeight = null;
152+
this.applyVueCompatMinimumWidth();
122153
} else {
123154
this.applyVueCompatAutoSize(height);
124155
}
@@ -255,13 +286,16 @@ export const nodeLifecycleMethods = {
255286
if (this._vueCompatLayout?.widgetsGrid !== widgetsGrid) {
256287
this.teardownVueCompatCanvasLayout();
257288
const canvasHost = canvasElement.parentElement;
289+
const nodeElement = widgetsGrid.closest?.(".lg-node") || null;
258290
this._vueCompatLayout = {
259291
bodyElement,
260292
widgetsGrid,
261293
slotsElement,
262294
canvasHost,
295+
nodeElement,
263296
bodyPosition: bodyElement.style.position,
264297
canvasHostMinHeight: canvasHost?.style.minHeight ?? '',
298+
nodeMinWidth: nodeElement?.style.minWidth ?? '',
265299
gridMarginTop: widgetsGrid.style.marginTop,
266300
gridPosition: widgetsGrid.style.position,
267301
gridZIndex: widgetsGrid.style.zIndex,
@@ -277,6 +311,9 @@ export const nodeLifecycleMethods = {
277311
}
278312

279313
const slotHeight = Math.max(0, Number(slotsElement.offsetHeight) || 0);
314+
if (this._vueCompatLayout.nodeElement) {
315+
this._vueCompatLayout.nodeElement.style.minWidth = `${this.getVueCompatMinimumWidth()}px`;
316+
}
280317
bodyElement.style.position = "relative";
281318
widgetsGrid.style.marginTop = "";
282319
widgetsGrid.style.position = "relative";
@@ -470,6 +507,9 @@ export const nodeLifecycleMethods = {
470507
if (layout.canvasHost) {
471508
layout.canvasHost.style.minHeight = layout.canvasHostMinHeight ?? "";
472509
}
510+
if (layout.nodeElement) {
511+
layout.nodeElement.style.minWidth = layout.nodeMinWidth ?? "";
512+
}
473513
layout.widgetsGrid.style.marginTop = layout.gridMarginTop;
474514
layout.widgetsGrid.style.position = layout.gridPosition;
475515
layout.widgetsGrid.style.zIndex = layout.gridZIndex;
@@ -644,7 +684,7 @@ export const nodeLifecycleMethods = {
644684
}
645685
const height = self.getVueCompatWidgetHeight();
646686
return {
647-
minWidth: 330,
687+
minWidth: self.getVueCompatMinimumWidth(),
648688
minHeight: height,
649689
maxHeight: self.collapsedSections?.extraControls ? 100000 : height
650690
};
@@ -668,6 +708,7 @@ export const nodeLifecycleMethods = {
668708
self._vueCompatWidgetHeight = contentHeight;
669709
if (self.collapsedSections?.extraControls) {
670710
self._vueCompatAutoSizedContentHeight = null;
711+
self.applyVueCompatMinimumWidth();
671712
} else {
672713
self.applyVueCompatAutoSize(minimumHeight);
673714
}

tests/js/node_lifecycle.test.mjs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,24 @@ test("Vue auto-sizing enforces minimum width and restores its internal guard", (
8282
});
8383

8484

85+
test("Vue auto-sizing restores minimum width after height was already synchronized", () => {
86+
const sizes = [];
87+
const controller = createLifecycleController({
88+
size: [200, 260],
89+
setSize(size) {
90+
sizes.push([...size]);
91+
this.size = [...size];
92+
}
93+
});
94+
controller._vueCompatAutoSizedContentHeight = 260;
95+
96+
withLiteGraph({ vueNodesMode: true }, () => controller.applyVueCompatAutoSize(260));
97+
98+
assert.deepEqual(sizes, [[330, 260]]);
99+
assert.deepEqual(controller.node.size, [330, 260]);
100+
});
101+
102+
85103
test("classic LiteGraph mode does not apply Vue-specific auto-sizing", () => {
86104
const controller = createLifecycleController();
87105

@@ -175,6 +193,46 @@ test("Vue output slot centers are measured relative to the widget canvas", () =>
175193
});
176194

177195

196+
test("Vue canvas layout enforces and restores the legacy node minimum width", () => {
197+
const controller = createLifecycleController();
198+
const nodeElement = { style: { minWidth: "120px" } };
199+
const slotsElement = {
200+
style: {},
201+
offsetHeight: 0,
202+
querySelectorAll() {
203+
return [];
204+
}
205+
};
206+
const bodyElement = { style: {} };
207+
const widgetsGrid = {
208+
style: {},
209+
previousElementSibling: slotsElement,
210+
parentElement: bodyElement,
211+
closest() {
212+
return nodeElement;
213+
}
214+
};
215+
const canvasElement = {
216+
clientWidth: 330,
217+
clientHeight: 200,
218+
parentElement: { style: {} },
219+
closest() {
220+
return widgetsGrid;
221+
},
222+
getBoundingClientRect() {
223+
return { left: 0, top: 0, width: 330, height: 200 };
224+
}
225+
};
226+
controller.ensureVueCompatHeaderControls = () => {};
227+
228+
controller.updateVueCompatCanvasLayout(canvasElement);
229+
assert.equal(nodeElement.style.minWidth, "330px");
230+
231+
controller.teardownVueCompatCanvasLayout();
232+
assert.equal(nodeElement.style.minWidth, "120px");
233+
});
234+
235+
178236
test("Vue tooltip is rendered in the document overlay and constrained to the viewport", () => {
179237
const previousDocument = globalThis.document;
180238
const tooltip = {

0 commit comments

Comments
 (0)