@elicdavis/node-flow 0.2.2 → 0.2.4

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
@@ -55,7 +55,8 @@ var defaults = {
55
55
  Idle: "#1c1c1c",
56
56
  MouseOver: "#8e8e8e",
57
57
  Grabbed: "white",
58
- Selected: "#6e6e6e"
58
+ Selected: "#6e6e6e",
59
+ Highlighted: "#ffc95c"
59
60
  },
60
61
  Bevel: null,
61
62
  Port: {
@@ -142,6 +143,7 @@ var defaults = {
142
143
  H3: {
143
144
  FontSize: 16
144
145
  },
146
+ CodeFontFamily: null,
145
147
  CodeBlock: {
146
148
  BackgroundColor: "#0c2b35",
147
149
  FontColor: "#afb9bb",
@@ -591,11 +593,11 @@ var ContextMenu = class _ContextMenu {
591
593
  #tempBox = { Position: Zero(), Size: Zero() };
592
594
  #openSubMenu;
593
595
  #bounds = null;
594
- #contains(point) {
596
+ contains(point) {
595
597
  if (this.#bounds !== null && InBox(this.#bounds, point)) {
596
598
  return true;
597
599
  }
598
- return this.#openSubMenu !== void 0 && this.#openSubMenu.#contains(point);
600
+ return this.#openSubMenu !== void 0 && this.#openSubMenu.contains(point);
599
601
  }
600
602
  /**
601
603
  * A submenu is anchored to its parent's left edge and told the parent's
@@ -638,7 +640,7 @@ var ContextMenu = class _ContextMenu {
638
640
  Position: { x: position.x, y: position.y },
639
641
  Size: { x: scaledEntryWidth, y: totalScaledHeight }
640
642
  };
641
- const pointer = mousePosition !== void 0 && this.#openSubMenu !== void 0 && this.#openSubMenu.#contains(mousePosition) ? void 0 : mousePosition;
643
+ const pointer = mousePosition !== void 0 && this.#openSubMenu !== void 0 && this.#openSubMenu.contains(mousePosition) ? void 0 : mousePosition;
642
644
  this.#tempBox.Size.x = scaledEntryWidth;
643
645
  this.#tempBox.Size.y = scaledEntryHeight;
644
646
  CopyVector2(this.#tempBox.Position, position);
@@ -748,12 +750,14 @@ var MouseObserver = class {
748
750
  #clickStop;
749
751
  #contextMenu;
750
752
  #zoomCallback;
753
+ #leaveCallback;
754
+ #inside = false;
751
755
  #longPressTimer = null;
752
756
  #longPressOrigin = Zero();
753
757
  #longPressFired = false;
754
758
  #pinchDist = 0;
755
759
  #lastTouchAt = 0;
756
- constructor(ele, dragCallback, moveCallback, clickStart, clickStop, contextMenu, fileDrop, zoomCallback) {
760
+ constructor(ele, dragCallback, moveCallback, clickStart, clickStop, contextMenu, fileDrop, zoomCallback, leaveCallback) {
757
761
  this.#ele = ele;
758
762
  this.#dragCallback = dragCallback;
759
763
  this.#moveCallback = moveCallback;
@@ -761,6 +765,7 @@ var MouseObserver = class {
761
765
  this.#clickStop = clickStop;
762
766
  this.#contextMenu = contextMenu;
763
767
  this.#zoomCallback = zoomCallback;
768
+ this.#leaveCallback = leaveCallback;
764
769
  this.#clicked = false;
765
770
  this.#lastTouch = Zero();
766
771
  this.#lastMousePosition = Zero();
@@ -775,6 +780,12 @@ var MouseObserver = class {
775
780
  document.addEventListener("touchend", redraws(this.#touchEnd.bind(this)), false);
776
781
  document.addEventListener("touchcancel", redraws(this.#touchEnd.bind(this)), false);
777
782
  ele.addEventListener("mousemove", redraws(this.#move.bind(this)), false);
783
+ ele.addEventListener("mouseleave", redraws(() => {
784
+ this.#inside = false;
785
+ if (!this.#clicked) {
786
+ this.#leaveCallback?.();
787
+ }
788
+ }), false);
778
789
  ele.addEventListener("touchmove", redraws(this.#touchMove.bind(this)), { passive: false });
779
790
  ele.addEventListener("wheel", redraws(this.#wheel.bind(this)), { passive: false });
780
791
  ele.addEventListener("drop", redraws((ev) => {
@@ -844,6 +855,7 @@ var MouseObserver = class {
844
855
  if (this.#fromTouch()) {
845
856
  return;
846
857
  }
858
+ this.#inside = true;
847
859
  const pos = this.#mousePos(event);
848
860
  if (this.#clicked) {
849
861
  const delta = Zero();
@@ -857,6 +869,7 @@ var MouseObserver = class {
857
869
  if (event.button !== 0 || this.#fromTouch()) {
858
870
  return;
859
871
  }
872
+ this.#inside = true;
860
873
  this.#clicked = true;
861
874
  this.#clickStart(this.#mousePos(event), event.ctrlKey || event.shiftKey);
862
875
  }
@@ -864,8 +877,12 @@ var MouseObserver = class {
864
877
  if (event.button !== 0 || this.#fromTouch()) {
865
878
  return;
866
879
  }
880
+ const wasClicked = this.#clicked;
867
881
  this.#clicked = false;
868
882
  this.#clickStop();
883
+ if (wasClicked && !this.#inside) {
884
+ this.#leaveCallback?.();
885
+ }
869
886
  }
870
887
  #touchStart(event) {
871
888
  this.#lastTouchAt = Date.now();
@@ -1555,6 +1572,18 @@ function typeSetsCompatible(a, b) {
1555
1572
  }
1556
1573
  return a.some((type) => b.includes(type));
1557
1574
  }
1575
+ function portsConnect(output, input, casts) {
1576
+ if (!output || !input) {
1577
+ return false;
1578
+ }
1579
+ return typeSetsConnect(output.acceptedTypes(), input.acceptedTypes(), casts);
1580
+ }
1581
+ function typeSetsConnect(output, input, casts) {
1582
+ if (typeSetsCompatible(output, input)) {
1583
+ return true;
1584
+ }
1585
+ return (casts ?? []).some((cast) => output.includes(cast.from) && input.includes(cast.to));
1586
+ }
1558
1587
  function portConfigTypes(config) {
1559
1588
  if (config.anyType === true) {
1560
1589
  return [];
@@ -1591,6 +1620,9 @@ function fallbackColor(type, s) {
1591
1620
  HSV2RGB(hsv, color);
1592
1621
  return RgbToHex(color);
1593
1622
  }
1623
+ function portTypeColor(type) {
1624
+ return fallbackColor(type, 1);
1625
+ }
1594
1626
  var Port = class {
1595
1627
  #node;
1596
1628
  #displayName;
@@ -1609,6 +1641,7 @@ var Port = class {
1609
1641
  #dataTypePopupElement;
1610
1642
  #onConnectionAdded;
1611
1643
  #onConnectionRemoved;
1644
+ #widget = null;
1612
1645
  constructor(node, portType, config) {
1613
1646
  this.#node = node;
1614
1647
  this.#connections = new Array();
@@ -1759,10 +1792,23 @@ var Port = class {
1759
1792
  this.#visibilityMayHaveChanged(was);
1760
1793
  }
1761
1794
  #visibilityMayHaveChanged(was) {
1762
- if (was !== this.hidden() || this.#portType === "INPUTARRAY" /* InputArray */) {
1795
+ if (was !== this.hidden() || this.#portType === "INPUTARRAY" /* InputArray */ || this.#widget !== null) {
1763
1796
  this.#node?.invalidateLayout();
1764
1797
  }
1765
1798
  }
1799
+ setWidget(widget) {
1800
+ this.#widget = widget;
1801
+ this.#node?.invalidateLayout();
1802
+ }
1803
+ widget() {
1804
+ return this.#widget;
1805
+ }
1806
+ /**
1807
+ * The widget stands in for a wire, so it leaves once one is connected.
1808
+ */
1809
+ widgetShown() {
1810
+ return this.#widget !== null && this.#portType !== "OUTPUT" /* Output */ && this.#connections.length === 0 && !this.hidden() && !(this.#widget.Hidden?.() ?? false);
1811
+ }
1766
1812
  /**
1767
1813
  * A port asked to hide still shows while anything is connected to it,
1768
1814
  * and while its node is showing its hidden ports.
@@ -3885,11 +3931,10 @@ function TimeExecution(name, callback) {
3885
3931
 
3886
3932
  // src/nodes/publisher.ts
3887
3933
  function offersMatchingPort(config, filter) {
3888
- const ports = filter.needs === "INPUT" /* Input */ ? config.inputs : config.outputs;
3889
- if (ports === void 0) {
3890
- return false;
3934
+ if (filter.needs === "INPUT" /* Input */) {
3935
+ return (config.inputs ?? []).some((port) => typeSetsConnect(filter.types, portConfigTypes(port), filter.casts));
3891
3936
  }
3892
- return ports.some((port) => typeSetsCompatible(portConfigTypes(port), filter.types));
3937
+ return (config.outputs ?? []).some((port) => typeSetsConnect(portConfigTypes(port), filter.types, filter.casts));
3893
3938
  }
3894
3939
  var Publisher = class {
3895
3940
  #name;
@@ -4070,11 +4115,14 @@ var NodeSubsystem2 = class {
4070
4115
  #boxSelectStart_graphSpace;
4071
4116
  #boxSelectEnd_graphSpace;
4072
4117
  #boxSelectionNodes;
4118
+ #casts;
4073
4119
  #lastCtx;
4074
4120
  #lastMousePosition;
4075
4121
  // LISTENERS ==============================================================
4076
4122
  #nodeRemovedCallbacks;
4077
4123
  #registeredNodeAddedCallbacks;
4124
+ #nodeHoverCallbacks = new Array();
4125
+ #hoveredNode = null;
4078
4126
  // ========================================================================
4079
4127
  constructor(postProcessPass, config) {
4080
4128
  this.#postProcessPass = postProcessPass;
@@ -4096,6 +4144,13 @@ var NodeSubsystem2 = class {
4096
4144
  this.#boxSelectEnd_graphSpace = Zero();
4097
4145
  this.#boxSelectionNodes = new List();
4098
4146
  this.#lastCtx = null;
4147
+ this.#casts = config?.casts ?? [];
4148
+ }
4149
+ setCasts(casts) {
4150
+ this.#casts = casts;
4151
+ }
4152
+ casts() {
4153
+ return this.#casts;
4099
4154
  }
4100
4155
  addPublisher(identifier, publisher) {
4101
4156
  this.#nodeFactory.addPublisher(identifier, publisher);
@@ -4118,6 +4173,18 @@ var NodeSubsystem2 = class {
4118
4173
  }
4119
4174
  this.#nodeRemovedCallbacks.push(callback);
4120
4175
  }
4176
+ addNodeHoverListener(callback) {
4177
+ this.#nodeHoverCallbacks.push(callback);
4178
+ }
4179
+ #setHoveredNode(node) {
4180
+ if (this.#hoveredNode === node) {
4181
+ return;
4182
+ }
4183
+ this.#hoveredNode = node;
4184
+ for (let i = 0; i < this.#nodeHoverCallbacks.length; i++) {
4185
+ this.#nodeHoverCallbacks[i](node);
4186
+ }
4187
+ }
4121
4188
  clickStart(mousePosition, camera, ctrlKey) {
4122
4189
  this.#boxSelect = false;
4123
4190
  this.#nodesGrabbed.Clear();
@@ -4337,7 +4404,8 @@ var NodeSubsystem2 = class {
4337
4404
  let firstHidden = -1;
4338
4405
  for (let i = 0; i < count; i++) {
4339
4406
  const port = side === "INPUT" /* Input */ ? node.inputPort(i) : node.outputPort(i);
4340
- if (!portsCompatible(port, against)) {
4407
+ const compatible = side === "INPUT" /* Input */ ? portsConnect(against, port, this.#casts) : portsConnect(port, against, this.#casts);
4408
+ if (!compatible) {
4341
4409
  continue;
4342
4410
  }
4343
4411
  if (!port.hidden()) {
@@ -4394,11 +4462,11 @@ var NodeSubsystem2 = class {
4394
4462
  this.#clearCurrentlySelectedConnection();
4395
4463
  return;
4396
4464
  }
4397
- if (this.#portHovering.InputPort && !portsCompatible(this.#portHovering.Port, conn.outPort())) {
4465
+ if (this.#portHovering.InputPort && !portsConnect(conn.outPort(), this.#portHovering.Port, this.#casts)) {
4398
4466
  this.#clearCurrentlySelectedConnection();
4399
4467
  return;
4400
4468
  }
4401
- if (!this.#portHovering.InputPort && !portsCompatible(this.#portHovering.Port, conn.inPort())) {
4469
+ if (!this.#portHovering.InputPort && !portsConnect(this.#portHovering.Port, conn.inPort(), this.#casts)) {
4402
4470
  this.#clearCurrentlySelectedConnection();
4403
4471
  return;
4404
4472
  }
@@ -4421,7 +4489,7 @@ var NodeSubsystem2 = class {
4421
4489
  connectNodes(nodeOut, outPort, nodeIn, inPort) {
4422
4490
  const from = nodeOut.outputPort(outPort);
4423
4491
  const to = nodeIn.inputPort(inPort);
4424
- if (!portsCompatible(from, to)) {
4492
+ if (!portsConnect(from, to, this.#casts)) {
4425
4493
  console.error("can't connect nodes of different types", from.getDataType(), to.getDataType());
4426
4494
  return;
4427
4495
  }
@@ -4764,6 +4832,7 @@ var NodeSubsystem2 = class {
4764
4832
  this.#widgetHovering = null;
4765
4833
  this.#nodeHovering = -1;
4766
4834
  this.#boxSelectionNodes.Clear();
4835
+ let hovered = null;
4767
4836
  const selectedBox_Screenspace = this.#boxSelectionScreenspaceBox(camera);
4768
4837
  const canvas = {
4769
4838
  Position: { x: 0, y: 0 },
@@ -4777,6 +4846,9 @@ var NodeSubsystem2 = class {
4777
4846
  }
4778
4847
  if (mousePosition !== void 0 && !this.#boxSelect) {
4779
4848
  const intersection = this.#nodes[i].inBounds(ctx, camera, mousePosition);
4849
+ if (intersection.Node !== void 0) {
4850
+ hovered = intersection.Node;
4851
+ }
4780
4852
  if (intersection.Node !== void 0 && intersection.PortIndex === void 0 && intersection.Widget === void 0) {
4781
4853
  state = 1 /* MouseOver */;
4782
4854
  this.#nodeHovering = i;
@@ -4808,6 +4880,7 @@ var NodeSubsystem2 = class {
4808
4880
  }
4809
4881
  this.#nodes[i].render(ctx, camera, state, mousePosition, this.#postProcessPass);
4810
4882
  }
4883
+ this.#setHoveredNode(hovered);
4811
4884
  if (this.#widgetCurrentlyClicking !== null) {
4812
4885
  this.#cursor = this.#widgetCurrentlyClicking.Cursor?.() ?? "pointer" /* Pointer */;
4813
4886
  }
@@ -5113,9 +5186,11 @@ var FlowNode = class {
5113
5186
  #elementSpacing;
5114
5187
  // Runtime ================================================================
5115
5188
  #selected;
5189
+ #highlighted = false;
5116
5190
  #inputPortPositions;
5117
5191
  #outputPortPositions;
5118
5192
  #widgetPositions;
5193
+ #portWidgetPositions = new List();
5119
5194
  #data;
5120
5195
  #registeredAnyPropertyChangeCallbacks;
5121
5196
  #registeredPropertyChangeCallbacks;
@@ -5215,6 +5290,16 @@ var FlowNode = class {
5215
5290
  this.#onSelect[i]();
5216
5291
  }
5217
5292
  }
5293
+ highlighted() {
5294
+ return this.#highlighted;
5295
+ }
5296
+ setHighlighted(highlighted) {
5297
+ if (this.#highlighted === highlighted) {
5298
+ return;
5299
+ }
5300
+ this.#highlighted = highlighted;
5301
+ requestRender();
5302
+ }
5218
5303
  raiseDragStoppedEvent() {
5219
5304
  for (let i = 0; i < this.#onDragStop.length; i++) {
5220
5305
  this.#onDragStop[i](this);
@@ -5603,7 +5688,7 @@ var FlowNode = class {
5603
5688
  }
5604
5689
  this.#portTextStyle.measure(ctx, 1, port.getDisplayName(), tempMeasurement);
5605
5690
  size.y += this.#portRowHeight(port, tempMeasurement.y) + this.#elementSpacing;
5606
- size.x = Math.max(size.x, tempMeasurement.x + doublePadding);
5691
+ size.x = Math.max(size.x, this.#portRowWidth(port, tempMeasurement.x) + doublePadding);
5607
5692
  }
5608
5693
  const widgets = this.#hasHiddenPortsToggle() ? [this.#hiddenPortsToggle, ...this.#widgets] : this.#widgets;
5609
5694
  for (const widget of widgets) {
@@ -5624,6 +5709,9 @@ var FlowNode = class {
5624
5709
  }
5625
5710
  addInput(config) {
5626
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
+ }
5627
5715
  this.#input.push(port);
5628
5716
  return port;
5629
5717
  }
@@ -5749,6 +5837,17 @@ var FlowNode = class {
5749
5837
  intersection.WidgetBox = this.#widgetPositions.At(i);
5750
5838
  }
5751
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
+ }
5752
5851
  return intersection;
5753
5852
  }
5754
5853
  canEditTitle() {
@@ -5863,7 +5962,14 @@ var FlowNode = class {
5863
5962
  }
5864
5963
  #portRowHeight(port, textHeight) {
5865
5964
  const slots = port.slots();
5866
- 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;
5867
5973
  }
5868
5974
  hasBeenLaidOut() {
5869
5975
  return this.#laidOut;
@@ -5885,11 +5991,28 @@ var FlowNode = class {
5885
5991
  this.#inputPortPositions.Clear();
5886
5992
  this.#outputPortPositions.Clear();
5887
5993
  this.#widgetPositions.Clear();
5994
+ this.#portWidgetPositions.Clear();
5888
5995
  const scaledPadding = this.#padding * camera.zoom;
5889
5996
  const scaledElementSpacing = this.#elementSpacing * camera.zoom;
5890
5997
  const nodeBounds = this.calculateBounds(ctx, camera);
5891
5998
  const nodeStyle = this.#calculateStyle(state);
5892
5999
  nodeStyle.Draw(ctx, nodeBounds, camera.zoom);
6000
+ if (this.#highlighted) {
6001
+ const gap = 3;
6002
+ ctx.save();
6003
+ ctx.strokeStyle = Theme.Node.Border.Highlighted;
6004
+ ctx.lineWidth = 2;
6005
+ ctx.beginPath();
6006
+ ctx.roundRect(
6007
+ nodeBounds.Position.x - gap,
6008
+ nodeBounds.Position.y - gap,
6009
+ nodeBounds.Size.x + gap * 2,
6010
+ nodeBounds.Size.y + gap * 2,
6011
+ nodeStyle.radius() * camera.zoom + gap
6012
+ );
6013
+ ctx.stroke();
6014
+ ctx.restore();
6015
+ }
5893
6016
  const borderSize = nodeStyle.borderSize();
5894
6017
  ctx.textAlign = "center" /* Center */;
5895
6018
  ctx.textBaseline = "middle" /* Middle */;
@@ -5979,6 +6102,7 @@ var FlowNode = class {
5979
6102
  const port = this.#input[i];
5980
6103
  if (port.hidden()) {
5981
6104
  this.#inputPortPositions.Push({ Position: { x: nodeBounds.Position.x, y: startY }, Size: { x: 0, y: 0 } });
6105
+ this.#portWidgetPositions.Push({ Position: { x: nodeBounds.Position.x, y: startY }, Size: { x: 0, y: 0 } });
5982
6106
  continue;
5983
6107
  }
5984
6108
  this.#portTextStyle.measure(ctx, 1, port.getDisplayName(), tempMeasurement);
@@ -5988,6 +6112,19 @@ var FlowNode = class {
5988
6112
  position.y = startY + portHeight / 2;
5989
6113
  this.#portTextStyle.setupStyle(ctx, camera.zoom);
5990
6114
  ctx.fillText(port.getDisplayName(), leftSide, position.y);
6115
+ if (port.widgetShown()) {
6116
+ const widget = port.widget();
6117
+ const widgetHeight = widget.Size().y * camera.zoom;
6118
+ const widgetLeft = leftSide + tempMeasurement.x * camera.zoom + scaledElementSpacing;
6119
+ const box = {
6120
+ Position: { x: widgetLeft, y: startY + (portHeight - widgetHeight) / 2 },
6121
+ Size: { x: nodeBounds.Position.x + nodeBounds.Size.x - scaledPadding - widgetLeft, y: widgetHeight }
6122
+ };
6123
+ widget.Draw(ctx, box, camera.zoom, mousePosition);
6124
+ this.#portWidgetPositions.Push(box);
6125
+ } else {
6126
+ this.#portWidgetPositions.Push({ Position: { x: nodeBounds.Position.x, y: startY }, Size: { x: 0, y: 0 } });
6127
+ }
5991
6128
  this.#inputPortPositions.Push(port.render(ctx, position, camera, mousePosition, postProcess));
5992
6129
  startY += portHeight + scaledElementSpacing;
5993
6130
  }
@@ -6073,6 +6210,7 @@ var FlowNode = class {
6073
6210
  return false;
6074
6211
  }
6075
6212
  this.#widgetPositions.Clear();
6213
+ this.#portWidgetPositions.Clear();
6076
6214
  this.#hiddenPortsTogglePosition = null;
6077
6215
  return true;
6078
6216
  }
@@ -6580,7 +6718,7 @@ var MarkdownSyntaxParser = class {
6580
6718
  content += token.lexeme();
6581
6719
  this.#inc();
6582
6720
  }
6583
- return [new Text(content, { font: "monospace" })];
6721
+ return [new Text(content, { font: Theme.Note.CodeFontFamily ?? "monospace" })];
6584
6722
  }
6585
6723
  #text() {
6586
6724
  let contents = new Array();
@@ -6694,7 +6832,7 @@ var MarkdownSyntaxParser = class {
6694
6832
  this.#inc();
6695
6833
  this.#inc();
6696
6834
  const codeBlockText = this.#originalText.substring(start, end).replace(/\r?\n$/, "");
6697
- const entryText = new Text(codeBlockText);
6835
+ const entryText = new Text(codeBlockText, { font: Theme.Note.CodeFontFamily ?? void 0 });
6698
6836
  this.#assignStandardStyling([entryText]);
6699
6837
  entryText.setColor(Theme.Note.CodeBlock.FontColor);
6700
6838
  return new CodeBlockEntry(entryText);
@@ -7456,8 +7594,16 @@ var QuickMenu = class {
7456
7594
  pos.x = 0;
7457
7595
  }
7458
7596
  this.#container.render(ctx, pos, 1, this.renderSize);
7597
+ this.#bounds = {
7598
+ Position: { x: pos.x, y: pos.y },
7599
+ Size: { x: this.renderSize.x, y: this.renderSize.y }
7600
+ };
7459
7601
  return null;
7460
7602
  }
7603
+ #bounds = null;
7604
+ contains(point) {
7605
+ return this.#bounds !== null && InBox(this.#bounds, point);
7606
+ }
7461
7607
  };
7462
7608
 
7463
7609
  // src/minimap.ts
@@ -7668,6 +7814,7 @@ var NodeFlowGraph = class {
7668
7814
  #backgroundRenderer;
7669
7815
  #contextMenuConfig;
7670
7816
  #mousePosition;
7817
+ #mouseOverCanvas = false;
7671
7818
  #camera;
7672
7819
  #openedContextMenu;
7673
7820
  #openQuickMenu;
@@ -7680,7 +7827,8 @@ var NodeFlowGraph = class {
7680
7827
  const postProcessPass = new PassSubsystem();
7681
7828
  this.#mainNodeSubsystem = new NodeSubsystem2(postProcessPass, {
7682
7829
  nodes: config?.nodes,
7683
- idleConnection: config?.idleConnection
7830
+ idleConnection: config?.idleConnection,
7831
+ casts: config?.casts
7684
7832
  });
7685
7833
  this.#lastFrameCursor = "default" /* Default */;
7686
7834
  this.#cursor = "default" /* Default */;
@@ -7729,6 +7877,7 @@ var NodeFlowGraph = class {
7729
7877
  this.#mouseDragEvent.bind(this),
7730
7878
  (mousePosition) => {
7731
7879
  this.#mousePosition = mousePosition;
7880
+ this.#mouseOverCanvas = true;
7732
7881
  },
7733
7882
  this.#clickStart.bind(this),
7734
7883
  this.#clickEnd.bind(this),
@@ -7736,6 +7885,9 @@ var NodeFlowGraph = class {
7736
7885
  this.#fileDrop.bind(this),
7737
7886
  (factor, anchor) => {
7738
7887
  this.#zoomBy(factor, anchor);
7888
+ },
7889
+ () => {
7890
+ this.#mouseOverCanvas = false;
7739
7891
  }
7740
7892
  );
7741
7893
  document.addEventListener(
@@ -7893,6 +8045,7 @@ var NodeFlowGraph = class {
7893
8045
  this.#openQuickMenu = null;
7894
8046
  this.#contextMenuEntryHovering = null;
7895
8047
  this.#mousePosition = mousePosition;
8048
+ this.#mouseOverCanvas = true;
7896
8049
  if (this.#minimap.contains(mousePosition)) {
7897
8050
  this.#lookAtFromMinimap(mousePosition);
7898
8051
  this.#draggingMinimap = true;
@@ -7921,6 +8074,9 @@ var NodeFlowGraph = class {
7921
8074
  addPublisher(identifier, publisher) {
7922
8075
  this.#mainNodeSubsystem.addPublisher(identifier, publisher);
7923
8076
  }
8077
+ setCasts(casts) {
8078
+ this.#mainNodeSubsystem.setCasts(casts);
8079
+ }
7924
8080
  getNodes() {
7925
8081
  return this.#mainNodeSubsystem.getNodes();
7926
8082
  }
@@ -8041,6 +8197,9 @@ var NodeFlowGraph = class {
8041
8197
  addOnNodeRemovedListener(callback) {
8042
8198
  this.#mainNodeSubsystem.addOnNodeRemovedListener(callback);
8043
8199
  }
8200
+ addNodeHoverListener(callback) {
8201
+ this.#mainNodeSubsystem.addNodeHoverListener(callback);
8202
+ }
8044
8203
  #sceenPositionToGraphPosition(screenPosition) {
8045
8204
  const out = Zero();
8046
8205
  this.#camera.screenSpaceToGraphSpace(screenPosition, out);
@@ -8066,6 +8225,7 @@ var NodeFlowGraph = class {
8066
8225
  {
8067
8226
  needs: dangling.needs,
8068
8227
  types: dangling.types,
8228
+ casts: this.#mainNodeSubsystem.casts(),
8069
8229
  onCreated: dangling.connectTo
8070
8230
  }
8071
8231
  );
@@ -8137,7 +8297,7 @@ var NodeFlowGraph = class {
8137
8297
  TimeExecution("Render_Background", this.#renderBackground.bind(this));
8138
8298
  TimeExecution("Render_View_" + this.#currentView, () => {
8139
8299
  placeEditsDuring(this.#canvas, () => {
8140
- let results = this.currentView().render(this.#ctx, this.#camera, this.#mousePosition);
8300
+ let results = this.currentView().render(this.#ctx, this.#camera, this.#pointerOnGraph());
8141
8301
  if (results?.cursorStyle) {
8142
8302
  this.#cursor = results?.cursorStyle;
8143
8303
  }
@@ -8153,6 +8313,19 @@ var NodeFlowGraph = class {
8153
8313
  }
8154
8314
  this.#lastFrameCursor = this.#cursor;
8155
8315
  }
8316
+ #pointer() {
8317
+ return this.#mouseOverCanvas ? this.#mousePosition : void 0;
8318
+ }
8319
+ #pointerOnGraph() {
8320
+ const pointer = this.#pointer();
8321
+ if (pointer === void 0) {
8322
+ return void 0;
8323
+ }
8324
+ if (this.#openedContextMenu?.Menu.contains(pointer) || this.#openQuickMenu?.Menu.contains(pointer)) {
8325
+ return void 0;
8326
+ }
8327
+ return pointer;
8328
+ }
8156
8329
  #renderBackground() {
8157
8330
  this.#backgroundRenderer(this.#canvas, this.#ctx, this.#camera.position, this.#camera.zoom);
8158
8331
  }
@@ -8161,7 +8334,7 @@ var NodeFlowGraph = class {
8161
8334
  if (this.#openedContextMenu !== null) {
8162
8335
  const pos = VectorPool.get();
8163
8336
  this.#camera.graphSpaceToScreenSpace(this.#openedContextMenu.Position, pos);
8164
- this.#contextMenuEntryHovering = this.#openedContextMenu.Menu.render(this.#ctx, pos, this.#camera.zoom, this.#mousePosition, true);
8337
+ this.#contextMenuEntryHovering = this.#openedContextMenu.Menu.render(this.#ctx, pos, this.#camera.zoom, this.#pointer(), true);
8165
8338
  if (this.#contextMenuEntryHovering !== null) {
8166
8339
  this.#cursor = "pointer" /* Pointer */;
8167
8340
  }
@@ -8173,7 +8346,7 @@ var NodeFlowGraph = class {
8173
8346
  if (this.#openQuickMenu !== null) {
8174
8347
  const pos = VectorPool.get();
8175
8348
  this.#camera.graphSpaceToScreenSpace(this.#openQuickMenu.Position, pos);
8176
- this.#contextMenuEntryHovering = this.#openQuickMenu.Menu.render(this.#ctx, pos, this.#camera.zoom, this.#mousePosition);
8349
+ this.#contextMenuEntryHovering = this.#openQuickMenu.Menu.render(this.#ctx, pos, this.#camera.zoom, this.#pointer());
8177
8350
  if (this.#contextMenuEntryHovering !== null) {
8178
8351
  this.#cursor = "pointer" /* Pointer */;
8179
8352
  }
@@ -8220,12 +8393,15 @@ export {
8220
8393
  formatNumber,
8221
8394
  onThemeChange,
8222
8395
  portConfigTypes,
8396
+ portTypeColor,
8223
8397
  portsCompatible,
8398
+ portsConnect,
8224
8399
  renderContinuously,
8225
8400
  requestRender,
8226
8401
  setTheme,
8227
8402
  themeVersion,
8228
8403
  typeSetsCompatible,
8404
+ typeSetsConnect,
8229
8405
  widgetFont
8230
8406
  };
8231
8407
  //# sourceMappingURL=index.mjs.map