@elicdavis/node-flow 0.2.1 → 0.2.2

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/index.mjs CHANGED
@@ -735,7 +735,7 @@ var ContextMenu = class _ContextMenu {
735
735
  // src/input.ts
736
736
  var LONG_PRESS_MS = 500;
737
737
  var LONG_PRESS_SLOP = 12;
738
- var PINCH_SENSITIVITY = 50;
738
+ var WHEEL_ZOOM_PER_PIXEL = 5e-4;
739
739
  var SUPPRESS_MOUSE_MS = 600;
740
740
  var MouseObserver = class {
741
741
  #clicked;
@@ -833,13 +833,12 @@ var MouseObserver = class {
833
833
  } else if (event.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
834
834
  dy *= this.#ele.clientHeight;
835
835
  }
836
- const amount = -dy / 100;
837
- if (amount === 0) {
836
+ if (dy === 0) {
838
837
  return;
839
838
  }
840
839
  const anchor = this.#mousePos(event);
841
840
  this.#moveCallback(anchor);
842
- this.#zoomCallback(amount, anchor);
841
+ this.#zoomCallback(Math.exp(-dy * WHEEL_ZOOM_PER_PIXEL), anchor);
843
842
  }
844
843
  #move(event) {
845
844
  if (this.#fromTouch()) {
@@ -915,7 +914,7 @@ var MouseObserver = class {
915
914
  const anchor = { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };
916
915
  if (this.#pinchDist > 0) {
917
916
  this.#moveCallback(anchor);
918
- this.#zoomCallback((dist - this.#pinchDist) / PINCH_SENSITIVITY, anchor);
917
+ this.#zoomCallback(dist / this.#pinchDist, anchor);
919
918
  }
920
919
  this.#pinchDist = dist;
921
920
  return;
@@ -1765,9 +1764,13 @@ var Port = class {
1765
1764
  }
1766
1765
  }
1767
1766
  /**
1768
- * A port asked to hide still shows while anything is connected to it.
1767
+ * A port asked to hide still shows while anything is connected to it,
1768
+ * and while its node is showing its hidden ports.
1769
1769
  */
1770
1770
  hidden() {
1771
+ return this.tucked() && !(this.#node?.hiddenPortsShown() ?? false);
1772
+ }
1773
+ tucked() {
1771
1774
  return this.#hidden && this.#connections.length === 0;
1772
1775
  }
1773
1776
  addConnectionRemovedListener(callback) {
@@ -1869,117 +1872,6 @@ var Port = class {
1869
1872
  }
1870
1873
  };
1871
1874
 
1872
- // src/styles/stroke.ts
1873
- function StrokeStyleWithFallback(input, fallback) {
1874
- return {
1875
- color: input?.color === void 0 ? fallback?.color : input?.color,
1876
- size: input?.size === void 0 ? fallback?.size : input?.size
1877
- };
1878
- }
1879
- var StrokeStyle = class {
1880
- #size;
1881
- #color;
1882
- constructor(config) {
1883
- this.#size = config?.size === void 0 ? 0.5 : config.size;
1884
- this.#color = config?.color === void 0 ? "black" : config.color;
1885
- }
1886
- setupStyle(ctx, scale) {
1887
- ctx.strokeStyle = this.#color;
1888
- ctx.lineWidth = scale * this.#size;
1889
- }
1890
- setColor(newColor) {
1891
- this.#color = newColor;
1892
- }
1893
- setSize(newSize) {
1894
- this.#size = newSize;
1895
- }
1896
- size() {
1897
- return this.#size;
1898
- }
1899
- };
1900
-
1901
- // src/styles/box.ts
1902
- function BoxStyleWithFallback(input, fallback) {
1903
- return {
1904
- radius: input?.radius === void 0 ? fallback?.radius : input?.radius,
1905
- color: input?.color === void 0 ? fallback?.color : input?.color,
1906
- border: StrokeStyleWithFallback(input?.border, fallback?.border)
1907
- };
1908
- }
1909
- var BoxStyle = class {
1910
- #border;
1911
- #color;
1912
- #radius;
1913
- constructor(config) {
1914
- this.#color = config?.color === void 0 ? "#CCCCCC" : config.color;
1915
- this.#border = config?.border === void 0 ? null : new StrokeStyle(config.border);
1916
- this.#radius = config?.radius === void 0 ? 2 : config.radius;
1917
- }
1918
- #box(ctx, box, scale, radius) {
1919
- ctx.fillStyle = this.#color;
1920
- this.#border?.setupStyle(ctx, scale);
1921
- ctx.beginPath();
1922
- ctx.roundRect(
1923
- box.Position.x,
1924
- box.Position.y,
1925
- box.Size.x,
1926
- box.Size.y,
1927
- radius
1928
- );
1929
- ctx.fill();
1930
- }
1931
- #draw(ctx, box, scale, radius) {
1932
- this.#box(ctx, box, scale, radius);
1933
- ctx.stroke();
1934
- }
1935
- Outline(ctx, box, scale, radius) {
1936
- this.#border?.setupStyle(ctx, scale);
1937
- ctx.beginPath();
1938
- ctx.roundRect(
1939
- box.Position.x,
1940
- box.Position.y,
1941
- box.Size.x,
1942
- box.Size.y,
1943
- radius
1944
- );
1945
- ctx.stroke();
1946
- }
1947
- Draw(ctx, box, scale) {
1948
- this.#draw(ctx, box, scale, this.#radius * scale);
1949
- }
1950
- DrawRoundedTopOnly(ctx, box, scale) {
1951
- this.#draw(ctx, box, scale, [this.#radius * scale * 2, this.#radius * scale * 2, 0, 0]);
1952
- }
1953
- DrawUnderline(ctx, box, scale) {
1954
- this.#box(ctx, box, scale, [this.#radius * scale * 2, this.#radius * scale * 2, 0, 0]);
1955
- ctx.beginPath();
1956
- ctx.moveTo(box.Position.x, box.Position.y + box.Size.y);
1957
- ctx.lineTo(box.Position.x + box.Size.x, box.Position.y + box.Size.y);
1958
- ctx.stroke();
1959
- }
1960
- borderSize() {
1961
- if (this.#border === null) {
1962
- return 0;
1963
- }
1964
- return this.#border.size();
1965
- }
1966
- radius() {
1967
- return this.#radius;
1968
- }
1969
- setColor(color) {
1970
- this.#color = color;
1971
- }
1972
- setBorderColor(color) {
1973
- if (this.#border === null) {
1974
- this.#border = new StrokeStyle({
1975
- color
1976
- });
1977
- } else {
1978
- this.#border.setColor(color);
1979
- }
1980
- }
1981
- };
1982
-
1983
1875
  // src/styles/cursor.ts
1984
1876
  var CursorStyle = /* @__PURE__ */ ((CursorStyle2) => {
1985
1877
  CursorStyle2["Default"] = "default";
@@ -2001,97 +1893,6 @@ var CursorStyle = /* @__PURE__ */ ((CursorStyle2) => {
2001
1893
  return CursorStyle2;
2002
1894
  })(CursorStyle || {});
2003
1895
 
2004
- // src/styles/bevel.ts
2005
- function drawBevel(ctx, box, scale, colors, sunken) {
2006
- const width2 = Math.max(1, 2 * scale);
2007
- const half = width2 / 2;
2008
- const left = box.Position.x + half;
2009
- const top = box.Position.y + half;
2010
- const right = box.Position.x + box.Size.x - half;
2011
- const bottom = box.Position.y + box.Size.y - half;
2012
- ctx.save();
2013
- ctx.lineWidth = width2;
2014
- ctx.lineCap = "square";
2015
- ctx.strokeStyle = sunken ? colors.Dark : colors.Light;
2016
- ctx.beginPath();
2017
- ctx.moveTo(left, bottom);
2018
- ctx.lineTo(left, top);
2019
- ctx.lineTo(right, top);
2020
- ctx.stroke();
2021
- ctx.strokeStyle = sunken ? colors.Light : colors.Dark;
2022
- ctx.beginPath();
2023
- ctx.moveTo(right, top);
2024
- ctx.lineTo(right, bottom);
2025
- ctx.lineTo(left, bottom);
2026
- ctx.stroke();
2027
- ctx.restore();
2028
- }
2029
-
2030
- // src/widgets/field.ts
2031
- function widgetFont(scale) {
2032
- return `${Theme.Widget.FontSize * scale}px ${Theme.FontFamily}`;
2033
- }
2034
- function fieldBackground(look) {
2035
- if (look.background !== void 0) {
2036
- return look.background;
2037
- }
2038
- if (look.input) {
2039
- return look.hovered ? Theme.Widget.Input.HoverBackgroundColor : Theme.Widget.Input.BackgroundColor;
2040
- }
2041
- if (look.pressed) {
2042
- return Theme.Widget.Button.Click.BackgroundColor;
2043
- }
2044
- return look.hovered ? Theme.Widget.Hover.BackgroundColor : Theme.Widget.BackgroundColor;
2045
- }
2046
- function drawFieldBox(ctx, box, scale, look) {
2047
- ctx.fillStyle = fieldBackground(look);
2048
- ctx.beginPath();
2049
- ctx.roundRect(box.Position.x, box.Position.y, box.Size.x, box.Size.y, Theme.Widget.Border.Radius * scale);
2050
- ctx.fill();
2051
- if (Theme.Widget.Border.Size > 0) {
2052
- ctx.strokeStyle = look.border ?? Theme.Widget.Border.Color;
2053
- ctx.lineWidth = Theme.Widget.Border.Size * scale;
2054
- ctx.stroke();
2055
- }
2056
- if (Theme.Widget.Bevel !== null) {
2057
- drawBevel(ctx, box, scale, Theme.Widget.Bevel, look.input === true || look.pressed === true);
2058
- }
2059
- }
2060
- function drawField(ctx, box, scale, look) {
2061
- drawFieldBox(ctx, box, scale, look);
2062
- drawFieldText(ctx, box, scale, look);
2063
- }
2064
- function drawFieldText(ctx, box, scale, look) {
2065
- const padding = Theme.Widget.Padding * scale;
2066
- const middle = box.Position.y + box.Size.y / 2;
2067
- const textColor = look.textColor ?? (look.input ? Theme.Widget.Input.FontColor : Theme.Widget.FontColor);
2068
- ctx.font = widgetFont(scale);
2069
- ctx.textBaseline = "middle";
2070
- if (look.label === void 0 || look.label === "") {
2071
- ctx.textAlign = "center";
2072
- ctx.fillStyle = textColor;
2073
- ctx.fillText(
2074
- fitString(ctx, look.value, box.Size.x - padding * 2),
2075
- box.Position.x + box.Size.x / 2,
2076
- middle
2077
- );
2078
- return;
2079
- }
2080
- const room = box.Size.x - padding * 2;
2081
- const label = fitString(ctx, look.label, room / 2);
2082
- const labelWidth = ctx.measureText(label).width;
2083
- ctx.textAlign = "left";
2084
- ctx.fillStyle = look.textColor ?? Theme.Widget.LabelColor;
2085
- ctx.fillText(label, box.Position.x + padding, middle);
2086
- ctx.textAlign = "right";
2087
- ctx.fillStyle = textColor;
2088
- ctx.fillText(
2089
- fitString(ctx, look.value, room - labelWidth - padding),
2090
- box.Position.x + box.Size.x - padding,
2091
- middle
2092
- );
2093
- }
2094
-
2095
1896
  // src/widgets/inplace.ts
2096
1897
  var open = /* @__PURE__ */ new Set();
2097
1898
  function placeEditsDuring(canvas, draw) {
@@ -2312,6 +2113,242 @@ function startingWidgetValue(node, property, configured, fallback) {
2312
2113
  return fallback;
2313
2114
  }
2314
2115
 
2116
+ // src/widgets/hidden_ports.ts
2117
+ var HiddenPortsToggle = class extends WidgetBase {
2118
+ constructor(owner) {
2119
+ super();
2120
+ this.owner = owner;
2121
+ }
2122
+ Size() {
2123
+ return { x: 150, y: 16 };
2124
+ }
2125
+ render(ctx, box, scale) {
2126
+ const label = this.owner.hiddenPortsShown() ? "\u25B4 less" : `\u25BE ${this.owner.hiddenPortCount()} more`;
2127
+ const midY = box.Position.y + box.Size.y / 2;
2128
+ const centerX = box.Position.x + box.Size.x / 2;
2129
+ ctx.font = `${11 * scale}px ${Theme.FontFamily}`;
2130
+ const half = ctx.measureText(label).width / 2 + 6 * scale;
2131
+ ctx.globalAlpha = this.hovered() ? 1 : 0.5;
2132
+ ctx.strokeStyle = Theme.Widget.FontColor;
2133
+ ctx.fillStyle = Theme.Widget.FontColor;
2134
+ ctx.lineWidth = Math.max(1, scale);
2135
+ ctx.beginPath();
2136
+ ctx.moveTo(box.Position.x, midY);
2137
+ ctx.lineTo(centerX - half, midY);
2138
+ ctx.moveTo(centerX + half, midY);
2139
+ ctx.lineTo(box.Position.x + box.Size.x, midY);
2140
+ ctx.stroke();
2141
+ ctx.textAlign = "center";
2142
+ ctx.textBaseline = "middle";
2143
+ ctx.fillText(label, centerX, midY);
2144
+ }
2145
+ onClick() {
2146
+ this.owner.setHiddenPortsShown(!this.owner.hiddenPortsShown());
2147
+ }
2148
+ };
2149
+
2150
+ // src/styles/stroke.ts
2151
+ function StrokeStyleWithFallback(input, fallback) {
2152
+ return {
2153
+ color: input?.color === void 0 ? fallback?.color : input?.color,
2154
+ size: input?.size === void 0 ? fallback?.size : input?.size
2155
+ };
2156
+ }
2157
+ var StrokeStyle = class {
2158
+ #size;
2159
+ #color;
2160
+ constructor(config) {
2161
+ this.#size = config?.size === void 0 ? 0.5 : config.size;
2162
+ this.#color = config?.color === void 0 ? "black" : config.color;
2163
+ }
2164
+ setupStyle(ctx, scale) {
2165
+ ctx.strokeStyle = this.#color;
2166
+ ctx.lineWidth = scale * this.#size;
2167
+ }
2168
+ setColor(newColor) {
2169
+ this.#color = newColor;
2170
+ }
2171
+ setSize(newSize) {
2172
+ this.#size = newSize;
2173
+ }
2174
+ size() {
2175
+ return this.#size;
2176
+ }
2177
+ };
2178
+
2179
+ // src/styles/box.ts
2180
+ function BoxStyleWithFallback(input, fallback) {
2181
+ return {
2182
+ radius: input?.radius === void 0 ? fallback?.radius : input?.radius,
2183
+ color: input?.color === void 0 ? fallback?.color : input?.color,
2184
+ border: StrokeStyleWithFallback(input?.border, fallback?.border)
2185
+ };
2186
+ }
2187
+ var BoxStyle = class {
2188
+ #border;
2189
+ #color;
2190
+ #radius;
2191
+ constructor(config) {
2192
+ this.#color = config?.color === void 0 ? "#CCCCCC" : config.color;
2193
+ this.#border = config?.border === void 0 ? null : new StrokeStyle(config.border);
2194
+ this.#radius = config?.radius === void 0 ? 2 : config.radius;
2195
+ }
2196
+ #box(ctx, box, scale, radius) {
2197
+ ctx.fillStyle = this.#color;
2198
+ this.#border?.setupStyle(ctx, scale);
2199
+ ctx.beginPath();
2200
+ ctx.roundRect(
2201
+ box.Position.x,
2202
+ box.Position.y,
2203
+ box.Size.x,
2204
+ box.Size.y,
2205
+ radius
2206
+ );
2207
+ ctx.fill();
2208
+ }
2209
+ #draw(ctx, box, scale, radius) {
2210
+ this.#box(ctx, box, scale, radius);
2211
+ ctx.stroke();
2212
+ }
2213
+ Outline(ctx, box, scale, radius) {
2214
+ this.#border?.setupStyle(ctx, scale);
2215
+ ctx.beginPath();
2216
+ ctx.roundRect(
2217
+ box.Position.x,
2218
+ box.Position.y,
2219
+ box.Size.x,
2220
+ box.Size.y,
2221
+ radius
2222
+ );
2223
+ ctx.stroke();
2224
+ }
2225
+ Draw(ctx, box, scale) {
2226
+ this.#draw(ctx, box, scale, this.#radius * scale);
2227
+ }
2228
+ DrawRoundedTopOnly(ctx, box, scale) {
2229
+ this.#draw(ctx, box, scale, [this.#radius * scale * 2, this.#radius * scale * 2, 0, 0]);
2230
+ }
2231
+ DrawUnderline(ctx, box, scale) {
2232
+ this.#box(ctx, box, scale, [this.#radius * scale * 2, this.#radius * scale * 2, 0, 0]);
2233
+ ctx.beginPath();
2234
+ ctx.moveTo(box.Position.x, box.Position.y + box.Size.y);
2235
+ ctx.lineTo(box.Position.x + box.Size.x, box.Position.y + box.Size.y);
2236
+ ctx.stroke();
2237
+ }
2238
+ borderSize() {
2239
+ if (this.#border === null) {
2240
+ return 0;
2241
+ }
2242
+ return this.#border.size();
2243
+ }
2244
+ radius() {
2245
+ return this.#radius;
2246
+ }
2247
+ setColor(color) {
2248
+ this.#color = color;
2249
+ }
2250
+ setBorderColor(color) {
2251
+ if (this.#border === null) {
2252
+ this.#border = new StrokeStyle({
2253
+ color
2254
+ });
2255
+ } else {
2256
+ this.#border.setColor(color);
2257
+ }
2258
+ }
2259
+ };
2260
+
2261
+ // src/styles/bevel.ts
2262
+ function drawBevel(ctx, box, scale, colors, sunken) {
2263
+ const width2 = Math.max(1, 2 * scale);
2264
+ const half = width2 / 2;
2265
+ const left = box.Position.x + half;
2266
+ const top = box.Position.y + half;
2267
+ const right = box.Position.x + box.Size.x - half;
2268
+ const bottom = box.Position.y + box.Size.y - half;
2269
+ ctx.save();
2270
+ ctx.lineWidth = width2;
2271
+ ctx.lineCap = "square";
2272
+ ctx.strokeStyle = sunken ? colors.Dark : colors.Light;
2273
+ ctx.beginPath();
2274
+ ctx.moveTo(left, bottom);
2275
+ ctx.lineTo(left, top);
2276
+ ctx.lineTo(right, top);
2277
+ ctx.stroke();
2278
+ ctx.strokeStyle = sunken ? colors.Light : colors.Dark;
2279
+ ctx.beginPath();
2280
+ ctx.moveTo(right, top);
2281
+ ctx.lineTo(right, bottom);
2282
+ ctx.lineTo(left, bottom);
2283
+ ctx.stroke();
2284
+ ctx.restore();
2285
+ }
2286
+
2287
+ // src/widgets/field.ts
2288
+ function widgetFont(scale) {
2289
+ return `${Theme.Widget.FontSize * scale}px ${Theme.FontFamily}`;
2290
+ }
2291
+ function fieldBackground(look) {
2292
+ if (look.background !== void 0) {
2293
+ return look.background;
2294
+ }
2295
+ if (look.input) {
2296
+ return look.hovered ? Theme.Widget.Input.HoverBackgroundColor : Theme.Widget.Input.BackgroundColor;
2297
+ }
2298
+ if (look.pressed) {
2299
+ return Theme.Widget.Button.Click.BackgroundColor;
2300
+ }
2301
+ return look.hovered ? Theme.Widget.Hover.BackgroundColor : Theme.Widget.BackgroundColor;
2302
+ }
2303
+ function drawFieldBox(ctx, box, scale, look) {
2304
+ ctx.fillStyle = fieldBackground(look);
2305
+ ctx.beginPath();
2306
+ ctx.roundRect(box.Position.x, box.Position.y, box.Size.x, box.Size.y, Theme.Widget.Border.Radius * scale);
2307
+ ctx.fill();
2308
+ if (Theme.Widget.Border.Size > 0) {
2309
+ ctx.strokeStyle = look.border ?? Theme.Widget.Border.Color;
2310
+ ctx.lineWidth = Theme.Widget.Border.Size * scale;
2311
+ ctx.stroke();
2312
+ }
2313
+ if (Theme.Widget.Bevel !== null) {
2314
+ drawBevel(ctx, box, scale, Theme.Widget.Bevel, look.input === true || look.pressed === true);
2315
+ }
2316
+ }
2317
+ function drawField(ctx, box, scale, look) {
2318
+ drawFieldBox(ctx, box, scale, look);
2319
+ drawFieldText(ctx, box, scale, look);
2320
+ }
2321
+ function drawFieldText(ctx, box, scale, look) {
2322
+ const padding = Theme.Widget.Padding * scale;
2323
+ const middle = box.Position.y + box.Size.y / 2;
2324
+ const textColor = look.textColor ?? (look.input ? Theme.Widget.Input.FontColor : Theme.Widget.FontColor);
2325
+ ctx.font = widgetFont(scale);
2326
+ ctx.textBaseline = "middle";
2327
+ if (look.label === void 0 || look.label === "") {
2328
+ ctx.textAlign = "center";
2329
+ ctx.fillStyle = textColor;
2330
+ ctx.fillText(
2331
+ fitString(ctx, look.value, box.Size.x - padding * 2),
2332
+ box.Position.x + box.Size.x / 2,
2333
+ middle
2334
+ );
2335
+ return;
2336
+ }
2337
+ const room = box.Size.x - padding * 2;
2338
+ const label = fitString(ctx, look.label, room / 2);
2339
+ const labelWidth = ctx.measureText(label).width;
2340
+ ctx.textAlign = "left";
2341
+ ctx.fillStyle = look.textColor ?? Theme.Widget.LabelColor;
2342
+ ctx.fillText(label, box.Position.x + padding, middle);
2343
+ ctx.textAlign = "right";
2344
+ ctx.fillStyle = textColor;
2345
+ ctx.fillText(
2346
+ fitString(ctx, look.value, room - labelWidth - padding),
2347
+ box.Position.x + box.Size.x - padding,
2348
+ middle
2349
+ );
2350
+ }
2351
+
2315
2352
  // src/widgets/value.ts
2316
2353
  var ValueWidget = class extends WidgetBase {
2317
2354
  #node;
@@ -5568,7 +5605,8 @@ var FlowNode = class {
5568
5605
  size.y += this.#portRowHeight(port, tempMeasurement.y) + this.#elementSpacing;
5569
5606
  size.x = Math.max(size.x, tempMeasurement.x + doublePadding);
5570
5607
  }
5571
- for (const widget of this.#widgets) {
5608
+ const widgets = this.#hasHiddenPortsToggle() ? [this.#hiddenPortsToggle, ...this.#widgets] : this.#widgets;
5609
+ for (const widget of widgets) {
5572
5610
  if (widget.Hidden?.()) {
5573
5611
  continue;
5574
5612
  }
@@ -5594,6 +5632,31 @@ var FlowNode = class {
5594
5632
  this.#output.push(port);
5595
5633
  return port;
5596
5634
  }
5635
+ #hiddenPortsShown = false;
5636
+ #hiddenPortsToggle = new HiddenPortsToggle(this);
5637
+ #hiddenPortsTogglePosition = null;
5638
+ hiddenPortsShown() {
5639
+ return this.#hiddenPortsShown;
5640
+ }
5641
+ setHiddenPortsShown(shown) {
5642
+ if (shown === this.#hiddenPortsShown) {
5643
+ return;
5644
+ }
5645
+ this.#hiddenPortsShown = shown;
5646
+ this.invalidateLayout();
5647
+ }
5648
+ hiddenPortCount() {
5649
+ let count = 0;
5650
+ for (const port of [...this.#input, ...this.#output]) {
5651
+ if (port.tucked()) {
5652
+ count++;
5653
+ }
5654
+ }
5655
+ return count;
5656
+ }
5657
+ #hasHiddenPortsToggle() {
5658
+ return this.hiddenPortCount() > 0;
5659
+ }
5597
5660
  addWidget(widget) {
5598
5661
  this.#widgets.push(widget);
5599
5662
  requestRender();
@@ -5672,6 +5735,11 @@ var FlowNode = class {
5672
5735
  intersection.Port = this.#output[i];
5673
5736
  }
5674
5737
  }
5738
+ if (this.#hiddenPortsTogglePosition !== null && InBox(this.#hiddenPortsTogglePosition, position)) {
5739
+ intersection.Node = this;
5740
+ intersection.Widget = this.#hiddenPortsToggle;
5741
+ intersection.WidgetBox = this.#hiddenPortsTogglePosition;
5742
+ }
5675
5743
  for (let i = 0; i < this.#widgetPositions.Count(); i++) {
5676
5744
  const widget = this.#widgets[i];
5677
5745
  if (widget !== void 0 && !widget.Hidden?.() && InBox(this.#widgetPositions.At(i), position)) {
@@ -5941,6 +6009,16 @@ var FlowNode = class {
5941
6009
  this.#outputPortPositions.Push(port.render(ctx, position, camera, mousePosition, postProcess));
5942
6010
  startY += portHeight + scaledElementSpacing;
5943
6011
  }
6012
+ this.#hiddenPortsTogglePosition = null;
6013
+ if (this.#hasHiddenPortsToggle()) {
6014
+ const box = {
6015
+ Position: { x: nodeBounds.Position.x + scaledPadding, y: startY },
6016
+ Size: { x: nodeBounds.Size.x - scaledPadding * 2, y: this.#hiddenPortsToggle.Size().y * camera.zoom }
6017
+ };
6018
+ this.#hiddenPortsToggle.Draw(ctx, box, camera.zoom, mousePosition);
6019
+ this.#hiddenPortsTogglePosition = box;
6020
+ startY += box.Size.y + scaledElementSpacing;
6021
+ }
5944
6022
  for (let i = 0; i < this.#widgets.length; i++) {
5945
6023
  const widget = this.#widgets[i];
5946
6024
  if (widget.Hidden?.()) {
@@ -5995,6 +6073,7 @@ var FlowNode = class {
5995
6073
  return false;
5996
6074
  }
5997
6075
  this.#widgetPositions.Clear();
6076
+ this.#hiddenPortsTogglePosition = null;
5998
6077
  return true;
5999
6078
  }
6000
6079
  placePorts(bounds, zoom) {
@@ -7655,8 +7734,8 @@ var NodeFlowGraph = class {
7655
7734
  this.#clickEnd.bind(this),
7656
7735
  this.#openContextMenu.bind(this),
7657
7736
  this.#fileDrop.bind(this),
7658
- (amount, anchor) => {
7659
- this.zoom(amount, anchor);
7737
+ (factor, anchor) => {
7738
+ this.#zoomBy(factor, anchor);
7660
7739
  }
7661
7740
  );
7662
7741
  document.addEventListener(
@@ -7784,12 +7863,15 @@ var NodeFlowGraph = class {
7784
7863
  this.#mainNoteSubsystem.addNoteDragStopListener(callback);
7785
7864
  }
7786
7865
  zoom(amount, anchor) {
7866
+ this.#zoomBy(1 + amount * 0.05, anchor);
7867
+ }
7868
+ #zoomBy(factor, anchor) {
7787
7869
  const anchorPos = anchor ?? this.#mousePosition;
7788
7870
  let oldPos = void 0;
7789
7871
  if (anchorPos !== void 0) {
7790
7872
  oldPos = this.#sceenPositionToGraphPosition(anchorPos);
7791
7873
  }
7792
- this.#camera.zoom += amount * this.#camera.zoom * 0.05;
7874
+ this.#camera.zoom *= factor;
7793
7875
  if (!oldPos || anchorPos === void 0) {
7794
7876
  return;
7795
7877
  }