@elicdavis/node-flow 0.2.2 → 0.2.3

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.d.mts CHANGED
@@ -156,97 +156,6 @@ interface Box {
156
156
  }
157
157
  declare function InBox(box: Box, position: Vector2): boolean;
158
158
 
159
- declare enum PortType {
160
- Input = "INPUT",
161
- Output = "OUTPUT",
162
- InputArray = "INPUTARRAY"
163
- }
164
- interface PortStyle {
165
- size?: number;
166
- fillColor?: string;
167
- borderColor?: string;
168
- borderSize?: number;
169
- }
170
- type ConnectionChangeCallback = (connection: Connection, connectionIndex: number, port: Port, portType: PortType, node: FlowNode) => void;
171
- interface PortConfig {
172
- name?: string;
173
- type?: string;
174
- description?: string;
175
- array?: boolean;
176
- /**
177
- * Lets this port connect to a port of any type, instead of only to one
178
- * declaring the same `type` string. For a port whose type is decided by
179
- * whatever gets wired into it, where `type` is a placeholder shown to
180
- * the user rather than a promise about the values passing through.
181
- */
182
- anyType?: boolean;
183
- /**
184
- * Every type this port takes, when it takes more than one. For a port
185
- * that works on a single value or an array of them, where `type` is
186
- * only the one it happens to be showing.
187
- *
188
- * An empty or absent list means the port takes exactly its `type`,
189
- * unless `anyType` says otherwise.
190
- */
191
- acceptedTypes?: Array<string>;
192
- /**
193
- * Leaves the port off the node until something is connected to it.
194
- */
195
- hidden?: boolean;
196
- emptyStyle?: PortStyle;
197
- filledStyle?: PortStyle;
198
- onConnectionAdded?: ConnectionChangeCallback;
199
- onConnectionRemoved?: ConnectionChangeCallback;
200
- }
201
- /**
202
- * Whether two ports may be connected, going by their types alone. Each port
203
- * offers the set of types it takes - one entry for an ordinary port, several
204
- * for a port that takes more than one, and none at all for a port that takes
205
- * anything. They connect when those sets overlap.
206
- */
207
- declare function portsCompatible(a: Port | undefined | null, b: Port | undefined | null): boolean;
208
- declare function typeSetsCompatible(a: Array<string>, b: Array<string>): boolean;
209
- declare function portConfigTypes(config: PortConfig): Array<string>;
210
- declare class Port {
211
- #private;
212
- constructor(node: FlowNode, portType: PortType, config?: PortConfig);
213
- setDataType(type: string): void;
214
- setAnyType(anyType: boolean): void;
215
- /**
216
- * Scope accepted types to singular type
217
- */
218
- settleOn(type: string): void;
219
- addConnection(connection: Connection, index?: number): void;
220
- replaceConnection(connection: Connection, index: number): void;
221
- addConnectionAddedListener(callback: ConnectionChangeCallback): void;
222
- connections(): Array<Connection>;
223
- /**
224
- * How many wires the port has room for: one per connection on an array
225
- * input, so each can be told apart and picked up on its own.
226
- */
227
- slots(): number;
228
- setHidden(hidden: boolean): void;
229
- /**
230
- * A port asked to hide still shows while anything is connected to it,
231
- * and while its node is showing its hidden ports.
232
- */
233
- hidden(): boolean;
234
- tucked(): boolean;
235
- addConnectionRemovedListener(callback: ConnectionChangeCallback): void;
236
- clearConnection(connection: Connection): void;
237
- getDataType(): string;
238
- acceptsAnyType(): boolean;
239
- /**
240
- * Every type this port takes. Empty means it takes anything.
241
- */
242
- acceptedTypes(): Array<string>;
243
- setAcceptedTypes(types: Array<string>): void;
244
- getPortType(): PortType;
245
- getDisplayName(): string;
246
- filledStyleColor(): string;
247
- render(ctx: CanvasRenderingContext2D, position: Vector2, camera: Camera, mousePosition: Vector2 | undefined, postProcess: PassSubsystem): Box;
248
- }
249
-
250
159
  /**
251
160
  * Where the pointer is, in canvas pixels, and whether it is over the widget.
252
161
  * A press that starts on a widget keeps reporting to it until it is let go,
@@ -301,17 +210,6 @@ declare abstract class WidgetBase implements Widget {
301
210
  protected onClick(pointer: WidgetPointer): void;
302
211
  }
303
212
 
304
- interface StrokeStyleConfig {
305
- size?: number;
306
- color?: string;
307
- }
308
-
309
- interface BoxStyleConfig {
310
- border?: StrokeStyleConfig;
311
- color?: string;
312
- radius?: number;
313
- }
314
-
315
213
  interface ValueWidgetConfig<T> {
316
214
  /**
317
215
  * A node property the widget shows and edits. Setting the property from
@@ -535,6 +433,119 @@ declare class WidgetFactory {
535
433
  }
536
434
  declare const GlobalWidgetFactory: WidgetFactory;
537
435
 
436
+ declare enum PortType {
437
+ Input = "INPUT",
438
+ Output = "OUTPUT",
439
+ InputArray = "INPUTARRAY"
440
+ }
441
+ interface PortStyle {
442
+ size?: number;
443
+ fillColor?: string;
444
+ borderColor?: string;
445
+ borderSize?: number;
446
+ }
447
+ type ConnectionChangeCallback = (connection: Connection, connectionIndex: number, port: Port, portType: PortType, node: FlowNode) => void;
448
+ interface PortConfig {
449
+ name?: string;
450
+ type?: string;
451
+ description?: string;
452
+ array?: boolean;
453
+ /**
454
+ * Lets this port connect to a port of any type, instead of only to one
455
+ * declaring the same `type` string. For a port whose type is decided by
456
+ * whatever gets wired into it, where `type` is a placeholder shown to
457
+ * the user rather than a promise about the values passing through.
458
+ */
459
+ anyType?: boolean;
460
+ /**
461
+ * Every type this port takes, when it takes more than one. For a port
462
+ * that works on a single value or an array of them, where `type` is
463
+ * only the one it happens to be showing.
464
+ *
465
+ * An empty or absent list means the port takes exactly its `type`,
466
+ * unless `anyType` says otherwise.
467
+ */
468
+ acceptedTypes?: Array<string>;
469
+ /**
470
+ * Leaves the port off the node until something is connected to it.
471
+ */
472
+ hidden?: boolean;
473
+ /**
474
+ * A widget drawn on the port's own row while nothing is connected to
475
+ * it, for a value the port holds on its own. Input ports only.
476
+ */
477
+ widget?: WidgetConfig;
478
+ emptyStyle?: PortStyle;
479
+ filledStyle?: PortStyle;
480
+ onConnectionAdded?: ConnectionChangeCallback;
481
+ onConnectionRemoved?: ConnectionChangeCallback;
482
+ }
483
+ /**
484
+ * Whether two ports may be connected, going by their types alone. Each port
485
+ * offers the set of types it takes - one entry for an ordinary port, several
486
+ * for a port that takes more than one, and none at all for a port that takes
487
+ * anything. They connect when those sets overlap.
488
+ */
489
+ declare function portsCompatible(a: Port | undefined | null, b: Port | undefined | null): boolean;
490
+ declare function typeSetsCompatible(a: Array<string>, b: Array<string>): boolean;
491
+ declare function portConfigTypes(config: PortConfig): Array<string>;
492
+ declare class Port {
493
+ #private;
494
+ constructor(node: FlowNode, portType: PortType, config?: PortConfig);
495
+ setDataType(type: string): void;
496
+ setAnyType(anyType: boolean): void;
497
+ /**
498
+ * Scope accepted types to singular type
499
+ */
500
+ settleOn(type: string): void;
501
+ addConnection(connection: Connection, index?: number): void;
502
+ replaceConnection(connection: Connection, index: number): void;
503
+ addConnectionAddedListener(callback: ConnectionChangeCallback): void;
504
+ connections(): Array<Connection>;
505
+ /**
506
+ * How many wires the port has room for: one per connection on an array
507
+ * input, so each can be told apart and picked up on its own.
508
+ */
509
+ slots(): number;
510
+ setHidden(hidden: boolean): void;
511
+ setWidget(widget: Widget | null): void;
512
+ widget(): Widget | null;
513
+ /**
514
+ * The widget stands in for a wire, so it leaves once one is connected.
515
+ */
516
+ widgetShown(): boolean;
517
+ /**
518
+ * A port asked to hide still shows while anything is connected to it,
519
+ * and while its node is showing its hidden ports.
520
+ */
521
+ hidden(): boolean;
522
+ tucked(): boolean;
523
+ addConnectionRemovedListener(callback: ConnectionChangeCallback): void;
524
+ clearConnection(connection: Connection): void;
525
+ getDataType(): string;
526
+ acceptsAnyType(): boolean;
527
+ /**
528
+ * Every type this port takes. Empty means it takes anything.
529
+ */
530
+ acceptedTypes(): Array<string>;
531
+ setAcceptedTypes(types: Array<string>): void;
532
+ getPortType(): PortType;
533
+ getDisplayName(): string;
534
+ filledStyleColor(): string;
535
+ render(ctx: CanvasRenderingContext2D, position: Vector2, camera: Camera, mousePosition: Vector2 | undefined, postProcess: PassSubsystem): Box;
536
+ }
537
+
538
+ interface StrokeStyleConfig {
539
+ size?: number;
540
+ color?: string;
541
+ }
542
+
543
+ interface BoxStyleConfig {
544
+ border?: StrokeStyleConfig;
545
+ color?: string;
546
+ radius?: number;
547
+ }
548
+
538
549
  interface Metadata {
539
550
  [name: string]: any;
540
551
  }
package/dist/index.d.ts CHANGED
@@ -156,97 +156,6 @@ interface Box {
156
156
  }
157
157
  declare function InBox(box: Box, position: Vector2): boolean;
158
158
 
159
- declare enum PortType {
160
- Input = "INPUT",
161
- Output = "OUTPUT",
162
- InputArray = "INPUTARRAY"
163
- }
164
- interface PortStyle {
165
- size?: number;
166
- fillColor?: string;
167
- borderColor?: string;
168
- borderSize?: number;
169
- }
170
- type ConnectionChangeCallback = (connection: Connection, connectionIndex: number, port: Port, portType: PortType, node: FlowNode) => void;
171
- interface PortConfig {
172
- name?: string;
173
- type?: string;
174
- description?: string;
175
- array?: boolean;
176
- /**
177
- * Lets this port connect to a port of any type, instead of only to one
178
- * declaring the same `type` string. For a port whose type is decided by
179
- * whatever gets wired into it, where `type` is a placeholder shown to
180
- * the user rather than a promise about the values passing through.
181
- */
182
- anyType?: boolean;
183
- /**
184
- * Every type this port takes, when it takes more than one. For a port
185
- * that works on a single value or an array of them, where `type` is
186
- * only the one it happens to be showing.
187
- *
188
- * An empty or absent list means the port takes exactly its `type`,
189
- * unless `anyType` says otherwise.
190
- */
191
- acceptedTypes?: Array<string>;
192
- /**
193
- * Leaves the port off the node until something is connected to it.
194
- */
195
- hidden?: boolean;
196
- emptyStyle?: PortStyle;
197
- filledStyle?: PortStyle;
198
- onConnectionAdded?: ConnectionChangeCallback;
199
- onConnectionRemoved?: ConnectionChangeCallback;
200
- }
201
- /**
202
- * Whether two ports may be connected, going by their types alone. Each port
203
- * offers the set of types it takes - one entry for an ordinary port, several
204
- * for a port that takes more than one, and none at all for a port that takes
205
- * anything. They connect when those sets overlap.
206
- */
207
- declare function portsCompatible(a: Port | undefined | null, b: Port | undefined | null): boolean;
208
- declare function typeSetsCompatible(a: Array<string>, b: Array<string>): boolean;
209
- declare function portConfigTypes(config: PortConfig): Array<string>;
210
- declare class Port {
211
- #private;
212
- constructor(node: FlowNode, portType: PortType, config?: PortConfig);
213
- setDataType(type: string): void;
214
- setAnyType(anyType: boolean): void;
215
- /**
216
- * Scope accepted types to singular type
217
- */
218
- settleOn(type: string): void;
219
- addConnection(connection: Connection, index?: number): void;
220
- replaceConnection(connection: Connection, index: number): void;
221
- addConnectionAddedListener(callback: ConnectionChangeCallback): void;
222
- connections(): Array<Connection>;
223
- /**
224
- * How many wires the port has room for: one per connection on an array
225
- * input, so each can be told apart and picked up on its own.
226
- */
227
- slots(): number;
228
- setHidden(hidden: boolean): void;
229
- /**
230
- * A port asked to hide still shows while anything is connected to it,
231
- * and while its node is showing its hidden ports.
232
- */
233
- hidden(): boolean;
234
- tucked(): boolean;
235
- addConnectionRemovedListener(callback: ConnectionChangeCallback): void;
236
- clearConnection(connection: Connection): void;
237
- getDataType(): string;
238
- acceptsAnyType(): boolean;
239
- /**
240
- * Every type this port takes. Empty means it takes anything.
241
- */
242
- acceptedTypes(): Array<string>;
243
- setAcceptedTypes(types: Array<string>): void;
244
- getPortType(): PortType;
245
- getDisplayName(): string;
246
- filledStyleColor(): string;
247
- render(ctx: CanvasRenderingContext2D, position: Vector2, camera: Camera, mousePosition: Vector2 | undefined, postProcess: PassSubsystem): Box;
248
- }
249
-
250
159
  /**
251
160
  * Where the pointer is, in canvas pixels, and whether it is over the widget.
252
161
  * A press that starts on a widget keeps reporting to it until it is let go,
@@ -301,17 +210,6 @@ declare abstract class WidgetBase implements Widget {
301
210
  protected onClick(pointer: WidgetPointer): void;
302
211
  }
303
212
 
304
- interface StrokeStyleConfig {
305
- size?: number;
306
- color?: string;
307
- }
308
-
309
- interface BoxStyleConfig {
310
- border?: StrokeStyleConfig;
311
- color?: string;
312
- radius?: number;
313
- }
314
-
315
213
  interface ValueWidgetConfig<T> {
316
214
  /**
317
215
  * A node property the widget shows and edits. Setting the property from
@@ -535,6 +433,119 @@ declare class WidgetFactory {
535
433
  }
536
434
  declare const GlobalWidgetFactory: WidgetFactory;
537
435
 
436
+ declare enum PortType {
437
+ Input = "INPUT",
438
+ Output = "OUTPUT",
439
+ InputArray = "INPUTARRAY"
440
+ }
441
+ interface PortStyle {
442
+ size?: number;
443
+ fillColor?: string;
444
+ borderColor?: string;
445
+ borderSize?: number;
446
+ }
447
+ type ConnectionChangeCallback = (connection: Connection, connectionIndex: number, port: Port, portType: PortType, node: FlowNode) => void;
448
+ interface PortConfig {
449
+ name?: string;
450
+ type?: string;
451
+ description?: string;
452
+ array?: boolean;
453
+ /**
454
+ * Lets this port connect to a port of any type, instead of only to one
455
+ * declaring the same `type` string. For a port whose type is decided by
456
+ * whatever gets wired into it, where `type` is a placeholder shown to
457
+ * the user rather than a promise about the values passing through.
458
+ */
459
+ anyType?: boolean;
460
+ /**
461
+ * Every type this port takes, when it takes more than one. For a port
462
+ * that works on a single value or an array of them, where `type` is
463
+ * only the one it happens to be showing.
464
+ *
465
+ * An empty or absent list means the port takes exactly its `type`,
466
+ * unless `anyType` says otherwise.
467
+ */
468
+ acceptedTypes?: Array<string>;
469
+ /**
470
+ * Leaves the port off the node until something is connected to it.
471
+ */
472
+ hidden?: boolean;
473
+ /**
474
+ * A widget drawn on the port's own row while nothing is connected to
475
+ * it, for a value the port holds on its own. Input ports only.
476
+ */
477
+ widget?: WidgetConfig;
478
+ emptyStyle?: PortStyle;
479
+ filledStyle?: PortStyle;
480
+ onConnectionAdded?: ConnectionChangeCallback;
481
+ onConnectionRemoved?: ConnectionChangeCallback;
482
+ }
483
+ /**
484
+ * Whether two ports may be connected, going by their types alone. Each port
485
+ * offers the set of types it takes - one entry for an ordinary port, several
486
+ * for a port that takes more than one, and none at all for a port that takes
487
+ * anything. They connect when those sets overlap.
488
+ */
489
+ declare function portsCompatible(a: Port | undefined | null, b: Port | undefined | null): boolean;
490
+ declare function typeSetsCompatible(a: Array<string>, b: Array<string>): boolean;
491
+ declare function portConfigTypes(config: PortConfig): Array<string>;
492
+ declare class Port {
493
+ #private;
494
+ constructor(node: FlowNode, portType: PortType, config?: PortConfig);
495
+ setDataType(type: string): void;
496
+ setAnyType(anyType: boolean): void;
497
+ /**
498
+ * Scope accepted types to singular type
499
+ */
500
+ settleOn(type: string): void;
501
+ addConnection(connection: Connection, index?: number): void;
502
+ replaceConnection(connection: Connection, index: number): void;
503
+ addConnectionAddedListener(callback: ConnectionChangeCallback): void;
504
+ connections(): Array<Connection>;
505
+ /**
506
+ * How many wires the port has room for: one per connection on an array
507
+ * input, so each can be told apart and picked up on its own.
508
+ */
509
+ slots(): number;
510
+ setHidden(hidden: boolean): void;
511
+ setWidget(widget: Widget | null): void;
512
+ widget(): Widget | null;
513
+ /**
514
+ * The widget stands in for a wire, so it leaves once one is connected.
515
+ */
516
+ widgetShown(): boolean;
517
+ /**
518
+ * A port asked to hide still shows while anything is connected to it,
519
+ * and while its node is showing its hidden ports.
520
+ */
521
+ hidden(): boolean;
522
+ tucked(): boolean;
523
+ addConnectionRemovedListener(callback: ConnectionChangeCallback): void;
524
+ clearConnection(connection: Connection): void;
525
+ getDataType(): string;
526
+ acceptsAnyType(): boolean;
527
+ /**
528
+ * Every type this port takes. Empty means it takes anything.
529
+ */
530
+ acceptedTypes(): Array<string>;
531
+ setAcceptedTypes(types: Array<string>): void;
532
+ getPortType(): PortType;
533
+ getDisplayName(): string;
534
+ filledStyleColor(): string;
535
+ render(ctx: CanvasRenderingContext2D, position: Vector2, camera: Camera, mousePosition: Vector2 | undefined, postProcess: PassSubsystem): Box;
536
+ }
537
+
538
+ interface StrokeStyleConfig {
539
+ size?: number;
540
+ color?: string;
541
+ }
542
+
543
+ interface BoxStyleConfig {
544
+ border?: StrokeStyleConfig;
545
+ color?: string;
546
+ radius?: number;
547
+ }
548
+
538
549
  interface Metadata {
539
550
  [name: string]: any;
540
551
  }
package/dist/index.js CHANGED
@@ -1679,6 +1679,7 @@ var Port = class {
1679
1679
  #dataTypePopupElement;
1680
1680
  #onConnectionAdded;
1681
1681
  #onConnectionRemoved;
1682
+ #widget = null;
1682
1683
  constructor(node, portType, config) {
1683
1684
  this.#node = node;
1684
1685
  this.#connections = new Array();
@@ -1829,10 +1830,23 @@ var Port = class {
1829
1830
  this.#visibilityMayHaveChanged(was);
1830
1831
  }
1831
1832
  #visibilityMayHaveChanged(was) {
1832
- if (was !== this.hidden() || this.#portType === "INPUTARRAY" /* InputArray */) {
1833
+ if (was !== this.hidden() || this.#portType === "INPUTARRAY" /* InputArray */ || this.#widget !== null) {
1833
1834
  this.#node?.invalidateLayout();
1834
1835
  }
1835
1836
  }
1837
+ setWidget(widget) {
1838
+ this.#widget = widget;
1839
+ this.#node?.invalidateLayout();
1840
+ }
1841
+ widget() {
1842
+ return this.#widget;
1843
+ }
1844
+ /**
1845
+ * The widget stands in for a wire, so it leaves once one is connected.
1846
+ */
1847
+ widgetShown() {
1848
+ return this.#widget !== null && this.#portType !== "OUTPUT" /* Output */ && this.#connections.length === 0 && !this.hidden() && !(this.#widget.Hidden?.() ?? false);
1849
+ }
1836
1850
  /**
1837
1851
  * A port asked to hide still shows while anything is connected to it,
1838
1852
  * and while its node is showing its hidden ports.
@@ -5186,6 +5200,7 @@ var FlowNode = class {
5186
5200
  #inputPortPositions;
5187
5201
  #outputPortPositions;
5188
5202
  #widgetPositions;
5203
+ #portWidgetPositions = new List();
5189
5204
  #data;
5190
5205
  #registeredAnyPropertyChangeCallbacks;
5191
5206
  #registeredPropertyChangeCallbacks;
@@ -5673,7 +5688,7 @@ var FlowNode = class {
5673
5688
  }
5674
5689
  this.#portTextStyle.measure(ctx, 1, port.getDisplayName(), tempMeasurement);
5675
5690
  size.y += this.#portRowHeight(port, tempMeasurement.y) + this.#elementSpacing;
5676
- size.x = Math.max(size.x, tempMeasurement.x + doublePadding);
5691
+ size.x = Math.max(size.x, this.#portRowWidth(port, tempMeasurement.x) + doublePadding);
5677
5692
  }
5678
5693
  const widgets = this.#hasHiddenPortsToggle() ? [this.#hiddenPortsToggle, ...this.#widgets] : this.#widgets;
5679
5694
  for (const widget of widgets) {
@@ -5694,6 +5709,9 @@ var FlowNode = class {
5694
5709
  }
5695
5710
  addInput(config) {
5696
5711
  const port = new Port(this, config.array ? "INPUTARRAY" /* InputArray */ : "INPUT" /* Input */, config);
5712
+ if (config.widget !== void 0) {
5713
+ port.setWidget(GlobalWidgetFactory.createFromConfig(this, config.widget));
5714
+ }
5697
5715
  this.#input.push(port);
5698
5716
  return port;
5699
5717
  }
@@ -5819,6 +5837,17 @@ var FlowNode = class {
5819
5837
  intersection.WidgetBox = this.#widgetPositions.At(i);
5820
5838
  }
5821
5839
  }
5840
+ for (let i = 0; i < this.#portWidgetPositions.Count(); i++) {
5841
+ const port = this.#input[i];
5842
+ if (port !== void 0 && port.widgetShown() && InBox(this.#portWidgetPositions.At(i), position)) {
5843
+ intersection.Node = this;
5844
+ intersection.Widget = port.widget();
5845
+ intersection.WidgetBox = this.#portWidgetPositions.At(i);
5846
+ intersection.Port = void 0;
5847
+ intersection.PortIndex = void 0;
5848
+ intersection.PortIsInput = void 0;
5849
+ }
5850
+ }
5822
5851
  return intersection;
5823
5852
  }
5824
5853
  canEditTitle() {
@@ -5933,7 +5962,14 @@ var FlowNode = class {
5933
5962
  }
5934
5963
  #portRowHeight(port, textHeight) {
5935
5964
  const slots = port.slots();
5936
- return slots > 1 ? Math.max(textHeight, slots * ARRAY_SLOT_PITCH) : textHeight;
5965
+ const widget = port.widgetShown() ? port.widget().Size().y : 0;
5966
+ return Math.max(slots > 1 ? slots * ARRAY_SLOT_PITCH : 0, textHeight, widget);
5967
+ }
5968
+ #portRowWidth(port, textWidth) {
5969
+ if (!port.widgetShown()) {
5970
+ return textWidth;
5971
+ }
5972
+ return textWidth + this.#elementSpacing + port.widget().Size().x;
5937
5973
  }
5938
5974
  hasBeenLaidOut() {
5939
5975
  return this.#laidOut;
@@ -5955,6 +5991,7 @@ var FlowNode = class {
5955
5991
  this.#inputPortPositions.Clear();
5956
5992
  this.#outputPortPositions.Clear();
5957
5993
  this.#widgetPositions.Clear();
5994
+ this.#portWidgetPositions.Clear();
5958
5995
  const scaledPadding = this.#padding * camera.zoom;
5959
5996
  const scaledElementSpacing = this.#elementSpacing * camera.zoom;
5960
5997
  const nodeBounds = this.calculateBounds(ctx, camera);
@@ -6049,6 +6086,7 @@ var FlowNode = class {
6049
6086
  const port = this.#input[i];
6050
6087
  if (port.hidden()) {
6051
6088
  this.#inputPortPositions.Push({ Position: { x: nodeBounds.Position.x, y: startY }, Size: { x: 0, y: 0 } });
6089
+ this.#portWidgetPositions.Push({ Position: { x: nodeBounds.Position.x, y: startY }, Size: { x: 0, y: 0 } });
6052
6090
  continue;
6053
6091
  }
6054
6092
  this.#portTextStyle.measure(ctx, 1, port.getDisplayName(), tempMeasurement);
@@ -6058,6 +6096,19 @@ var FlowNode = class {
6058
6096
  position.y = startY + portHeight / 2;
6059
6097
  this.#portTextStyle.setupStyle(ctx, camera.zoom);
6060
6098
  ctx.fillText(port.getDisplayName(), leftSide, position.y);
6099
+ if (port.widgetShown()) {
6100
+ const widget = port.widget();
6101
+ const widgetHeight = widget.Size().y * camera.zoom;
6102
+ const widgetLeft = leftSide + tempMeasurement.x * camera.zoom + scaledElementSpacing;
6103
+ const box = {
6104
+ Position: { x: widgetLeft, y: startY + (portHeight - widgetHeight) / 2 },
6105
+ Size: { x: nodeBounds.Position.x + nodeBounds.Size.x - scaledPadding - widgetLeft, y: widgetHeight }
6106
+ };
6107
+ widget.Draw(ctx, box, camera.zoom, mousePosition);
6108
+ this.#portWidgetPositions.Push(box);
6109
+ } else {
6110
+ this.#portWidgetPositions.Push({ Position: { x: nodeBounds.Position.x, y: startY }, Size: { x: 0, y: 0 } });
6111
+ }
6061
6112
  this.#inputPortPositions.Push(port.render(ctx, position, camera, mousePosition, postProcess));
6062
6113
  startY += portHeight + scaledElementSpacing;
6063
6114
  }
@@ -6143,6 +6194,7 @@ var FlowNode = class {
6143
6194
  return false;
6144
6195
  }
6145
6196
  this.#widgetPositions.Clear();
6197
+ this.#portWidgetPositions.Clear();
6146
6198
  this.#hiddenPortsTogglePosition = null;
6147
6199
  return true;
6148
6200
  }