@elicdavis/node-flow 0.1.12 → 0.1.13

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.js CHANGED
@@ -38,6 +38,7 @@ var index_exports = {};
38
38
  __export(index_exports, {
39
39
  ButtonWidget: () => ButtonWidget,
40
40
  ColorWidget: () => ColorWidget,
41
+ ContextMenuItemState: () => ContextMenuItemState,
41
42
  FlowNode: () => FlowNode,
42
43
  FlowNote: () => FlowNote,
43
44
  GlobalWidgetFactory: () => GlobalWidgetFactory,
@@ -114,7 +115,8 @@ var Theme = {
114
115
  ContextMenu: {
115
116
  BackgroundColor: "#07212A",
116
117
  HighlightColor: "#205A6D",
117
- FontColor: "#afb9bb"
118
+ FontColor: "#afb9bb",
119
+ DisabledFontColor: "#4a585c"
118
120
  },
119
121
  Note: {
120
122
  FontColor: "#afb9bb",
@@ -379,22 +381,33 @@ _count2 = new WeakMap();
379
381
 
380
382
  // src/contextMenu.ts
381
383
  var contextEntryHeight = 30;
382
- var _name, _callback, _textStyle;
384
+ var ContextMenuItemState = /* @__PURE__ */ ((ContextMenuItemState2) => {
385
+ ContextMenuItemState2[ContextMenuItemState2["Enabled"] = 0] = "Enabled";
386
+ ContextMenuItemState2[ContextMenuItemState2["Disabled"] = 1] = "Disabled";
387
+ ContextMenuItemState2[ContextMenuItemState2["Hidden"] = 2] = "Hidden";
388
+ return ContextMenuItemState2;
389
+ })(ContextMenuItemState || {});
390
+ var _name, _callback, _textStyle, _state;
383
391
  var ContextMenuItem = class {
384
392
  constructor(config) {
385
393
  __privateAdd(this, _name);
386
394
  __privateAdd(this, _callback);
387
395
  __privateAdd(this, _textStyle);
396
+ __privateAdd(this, _state);
388
397
  __privateSet(this, _name, (config == null ? void 0 : config.name) === void 0 ? "item" : config.name);
389
398
  __privateSet(this, _callback, config == null ? void 0 : config.callback);
390
399
  __privateSet(this, _textStyle, new TextStyle(config == null ? void 0 : config.textStyle));
391
400
  this.group = config == null ? void 0 : config.group;
401
+ __privateSet(this, _state, (config == null ? void 0 : config.enabled) === void 0 ? 0 /* Enabled */ : config.enabled());
392
402
  }
393
403
  getName() {
394
404
  return __privateGet(this, _name);
395
405
  }
406
+ state() {
407
+ return __privateGet(this, _state);
408
+ }
396
409
  execute() {
397
- if (__privateGet(this, _callback) === void 0) {
410
+ if (__privateGet(this, _state) !== 0 /* Enabled */ || __privateGet(this, _callback) === void 0) {
398
411
  return;
399
412
  }
400
413
  __privateGet(this, _callback).call(this);
@@ -403,6 +416,7 @@ var ContextMenuItem = class {
403
416
  _name = new WeakMap();
404
417
  _callback = new WeakMap();
405
418
  _textStyle = new WeakMap();
419
+ _state = new WeakMap();
406
420
  var _calculatedHeight;
407
421
  var ContextGroup = class {
408
422
  constructor(entries) {
@@ -476,7 +490,11 @@ var _ContextMenu = class _ContextMenu {
476
490
  }
477
491
  if ((config == null ? void 0 : config.items) !== void 0) {
478
492
  for (let i = 0; i < (config == null ? void 0 : config.items.length); i++) {
479
- __privateGet(this, _items).push(new ContextMenuItem(config == null ? void 0 : config.items[i]));
493
+ const item = new ContextMenuItem(config == null ? void 0 : config.items[i]);
494
+ if (item.state() === 2 /* Hidden */) {
495
+ continue;
496
+ }
497
+ __privateGet(this, _items).push(item);
480
498
  }
481
499
  }
482
500
  __privateMethod(this, _ContextMenu_instances, calculateEntries_fn).call(this);
@@ -547,7 +565,8 @@ var _ContextMenu = class _ContextMenu {
547
565
  __privateSet(this, _openSubMenu, void 0);
548
566
  }
549
567
  }
550
- if (entryMousedOver || __privateGet(this, _openSubMenu) !== void 0 && entry.subMenu === __privateGet(this, _openSubMenu)) {
568
+ const itemDisabled = entry.item !== void 0 && entry.item.state() === 1 /* Disabled */;
569
+ if (!itemDisabled && (entryMousedOver || __privateGet(this, _openSubMenu) !== void 0 && entry.subMenu === __privateGet(this, _openSubMenu))) {
551
570
  ctx.fillStyle = Theme.ContextMenu.HighlightColor;
552
571
  ctx.beginPath();
553
572
  ctx.roundRect(
@@ -560,6 +579,9 @@ var _ContextMenu = class _ContextMenu {
560
579
  ctx.fill();
561
580
  }
562
581
  __privateGet(this, _textStyle2).setupStyle(ctx, menuScale);
582
+ if (itemDisabled) {
583
+ ctx.fillStyle = Theme.ContextMenu.DisabledFontColor;
584
+ }
563
585
  ctx.fillText(entry.text, position.x + scaledEntryHeight / 5, __privateGet(this, _tempBox).Position.y + scaledEntryHeight / 2);
564
586
  if (entry.subMenu !== void 0) {
565
587
  ctx.beginPath();
@@ -671,9 +693,13 @@ _openSubMenu = new WeakMap();
671
693
  var ContextMenu = _ContextMenu;
672
694
 
673
695
  // src/input.ts
674
- var _clicked, _lastTouch, _ele, _lastMousePosition, _dragCallback, _moveCallback, _clickStart, _clickStop, _contextMenu, _MouseObserver_instances, mousePosition_fn, move_fn, moveTouch_fn, down_fn, touchDown_fn, up_fn;
696
+ var LONG_PRESS_MS = 500;
697
+ var LONG_PRESS_SLOP = 12;
698
+ var PINCH_SENSITIVITY = 50;
699
+ var SUPPRESS_MOUSE_MS = 600;
700
+ var _clicked, _lastTouch, _ele, _lastMousePosition, _dragCallback, _moveCallback, _clickStart, _clickStop, _contextMenu, _zoomCallback, _longPressTimer, _longPressOrigin, _longPressFired, _pinchDist, _lastTouchAt, _MouseObserver_instances, mousePos_fn, touchPos_fn, fromTouch_fn, clearLongPress_fn, wheel_fn, move_fn, down_fn, up_fn, touchStart_fn, touchMove_fn, touchEnd_fn;
675
701
  var MouseObserver = class {
676
- constructor(ele, dragCallback, moveCallback, clickStart, clickStop, contextMenu, fileDrop) {
702
+ constructor(ele, dragCallback, moveCallback, clickStart, clickStop, contextMenu, fileDrop, zoomCallback) {
677
703
  __privateAdd(this, _MouseObserver_instances);
678
704
  __privateAdd(this, _clicked);
679
705
  __privateAdd(this, _lastTouch);
@@ -684,49 +710,55 @@ var MouseObserver = class {
684
710
  __privateAdd(this, _clickStart);
685
711
  __privateAdd(this, _clickStop);
686
712
  __privateAdd(this, _contextMenu);
713
+ __privateAdd(this, _zoomCallback);
714
+ __privateAdd(this, _longPressTimer, null);
715
+ __privateAdd(this, _longPressOrigin, Zero());
716
+ __privateAdd(this, _longPressFired, false);
717
+ __privateAdd(this, _pinchDist, 0);
718
+ __privateAdd(this, _lastTouchAt, 0);
687
719
  __privateSet(this, _ele, ele);
688
720
  __privateSet(this, _dragCallback, dragCallback);
689
721
  __privateSet(this, _moveCallback, moveCallback);
690
722
  __privateSet(this, _clickStart, clickStart);
691
723
  __privateSet(this, _clickStop, clickStop);
692
724
  __privateSet(this, _contextMenu, contextMenu);
725
+ __privateSet(this, _zoomCallback, zoomCallback);
693
726
  __privateSet(this, _clicked, false);
694
727
  __privateSet(this, _lastTouch, Zero());
695
728
  __privateSet(this, _lastMousePosition, Zero());
729
+ ele.style.touchAction = "none";
696
730
  ele.addEventListener("mousedown", __privateMethod(this, _MouseObserver_instances, down_fn).bind(this), false);
697
- ele.addEventListener("touchstart", __privateMethod(this, _MouseObserver_instances, touchDown_fn).bind(this), false);
731
+ ele.addEventListener("touchstart", __privateMethod(this, _MouseObserver_instances, touchStart_fn).bind(this), { passive: false });
698
732
  document.addEventListener("mouseup", __privateMethod(this, _MouseObserver_instances, up_fn).bind(this), false);
699
- document.addEventListener("touchend", __privateMethod(this, _MouseObserver_instances, up_fn).bind(this), false);
733
+ document.addEventListener("touchend", __privateMethod(this, _MouseObserver_instances, touchEnd_fn).bind(this), false);
734
+ document.addEventListener("touchcancel", __privateMethod(this, _MouseObserver_instances, touchEnd_fn).bind(this), false);
700
735
  ele.addEventListener("mousemove", __privateMethod(this, _MouseObserver_instances, move_fn).bind(this), false);
701
- ele.addEventListener("touchmove", __privateMethod(this, _MouseObserver_instances, moveTouch_fn).bind(this), false);
736
+ ele.addEventListener("touchmove", __privateMethod(this, _MouseObserver_instances, touchMove_fn).bind(this), { passive: false });
737
+ ele.addEventListener("wheel", __privateMethod(this, _MouseObserver_instances, wheel_fn).bind(this), { passive: false });
702
738
  ele.addEventListener("drop", (ev) => {
703
739
  var _a;
704
740
  ev.preventDefault();
705
- console.log(ev);
706
741
  if ((_a = ev.dataTransfer) == null ? void 0 : _a.items) {
707
742
  [...ev.dataTransfer.items].forEach((item, i) => {
708
743
  if (item.kind === "file") {
709
744
  const file = item.getAsFile();
710
745
  if (file) {
711
746
  fileDrop(file);
712
- console.log(file);
713
- console.log(`\u2026 file[${i}].name = ${file.name}`);
714
747
  }
715
748
  }
716
749
  });
717
- } else if (ev.dataTransfer) {
718
- [...ev.dataTransfer.files].forEach((file, i) => {
719
- console.log(`\u2026 file[${i}].name = ${file.name}`);
720
- });
721
750
  }
722
751
  });
723
752
  ele.addEventListener("dragover", (ev) => {
724
753
  ev.preventDefault();
725
- __privateGet(this, _moveCallback).call(this, __privateMethod(this, _MouseObserver_instances, mousePosition_fn).call(this, ev));
754
+ __privateGet(this, _moveCallback).call(this, __privateMethod(this, _MouseObserver_instances, mousePos_fn).call(this, ev));
726
755
  });
727
756
  ele.addEventListener("contextmenu", (evt) => {
728
- contextMenu(__privateMethod(this, _MouseObserver_instances, mousePosition_fn).call(this, evt));
729
757
  evt.preventDefault();
758
+ if (Date.now() - __privateGet(this, _lastTouchAt) < SUPPRESS_MOUSE_MS) {
759
+ return;
760
+ }
761
+ __privateGet(this, _contextMenu).call(this, __privateMethod(this, _MouseObserver_instances, mousePos_fn).call(this, evt));
730
762
  }, false);
731
763
  }
732
764
  };
@@ -739,16 +771,57 @@ _moveCallback = new WeakMap();
739
771
  _clickStart = new WeakMap();
740
772
  _clickStop = new WeakMap();
741
773
  _contextMenu = new WeakMap();
774
+ _zoomCallback = new WeakMap();
775
+ _longPressTimer = new WeakMap();
776
+ _longPressOrigin = new WeakMap();
777
+ _longPressFired = new WeakMap();
778
+ _pinchDist = new WeakMap();
779
+ _lastTouchAt = new WeakMap();
742
780
  _MouseObserver_instances = new WeakSet();
743
- mousePosition_fn = function(event) {
744
- var rect = __privateGet(this, _ele).getBoundingClientRect();
781
+ mousePos_fn = function(event) {
782
+ const rect = __privateGet(this, _ele).getBoundingClientRect();
745
783
  return {
746
784
  x: event.clientX - rect.left,
747
785
  y: event.clientY - rect.top
748
786
  };
749
787
  };
788
+ touchPos_fn = function(touch) {
789
+ const rect = __privateGet(this, _ele).getBoundingClientRect();
790
+ return {
791
+ x: touch.clientX - rect.left,
792
+ y: touch.clientY - rect.top
793
+ };
794
+ };
795
+ fromTouch_fn = function() {
796
+ return Date.now() - __privateGet(this, _lastTouchAt) < SUPPRESS_MOUSE_MS;
797
+ };
798
+ clearLongPress_fn = function() {
799
+ if (__privateGet(this, _longPressTimer) !== null) {
800
+ clearTimeout(__privateGet(this, _longPressTimer));
801
+ __privateSet(this, _longPressTimer, null);
802
+ }
803
+ };
804
+ wheel_fn = function(event) {
805
+ event.preventDefault();
806
+ let dy = event.deltaY;
807
+ if (event.deltaMode === WheelEvent.DOM_DELTA_LINE) {
808
+ dy *= 16;
809
+ } else if (event.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
810
+ dy *= __privateGet(this, _ele).clientHeight;
811
+ }
812
+ const amount = -dy / 100;
813
+ if (amount === 0) {
814
+ return;
815
+ }
816
+ const anchor = __privateMethod(this, _MouseObserver_instances, mousePos_fn).call(this, event);
817
+ __privateGet(this, _moveCallback).call(this, anchor);
818
+ __privateGet(this, _zoomCallback).call(this, amount, anchor);
819
+ };
750
820
  move_fn = function(event) {
751
- const pos = __privateMethod(this, _MouseObserver_instances, mousePosition_fn).call(this, event);
821
+ if (__privateMethod(this, _MouseObserver_instances, fromTouch_fn).call(this)) {
822
+ return;
823
+ }
824
+ const pos = __privateMethod(this, _MouseObserver_instances, mousePos_fn).call(this, event);
752
825
  if (__privateGet(this, _clicked)) {
753
826
  const delta = Zero();
754
827
  SubVector2(delta, pos, __privateGet(this, _lastMousePosition));
@@ -757,14 +830,80 @@ move_fn = function(event) {
757
830
  __privateGet(this, _moveCallback).call(this, pos);
758
831
  CopyVector2(__privateGet(this, _lastMousePosition), pos);
759
832
  };
760
- moveTouch_fn = function(event) {
761
- const rect = __privateGet(this, _ele).getBoundingClientRect();
762
- const pos = {
763
- x: event.touches[0].clientX - rect.left,
764
- y: event.touches[0].clientY - rect.top
765
- };
833
+ down_fn = function(event) {
834
+ if (event.button !== 0 || __privateMethod(this, _MouseObserver_instances, fromTouch_fn).call(this)) {
835
+ return;
836
+ }
837
+ __privateSet(this, _clicked, true);
838
+ __privateGet(this, _clickStart).call(this, __privateMethod(this, _MouseObserver_instances, mousePos_fn).call(this, event), event.ctrlKey || event.shiftKey);
839
+ };
840
+ up_fn = function(event) {
841
+ if (event.button !== 0 || __privateMethod(this, _MouseObserver_instances, fromTouch_fn).call(this)) {
842
+ return;
843
+ }
844
+ __privateSet(this, _clicked, false);
845
+ __privateGet(this, _clickStop).call(this);
846
+ };
847
+ touchStart_fn = function(event) {
848
+ __privateSet(this, _lastTouchAt, Date.now());
849
+ event.preventDefault();
850
+ if (event.touches.length >= 2) {
851
+ __privateMethod(this, _MouseObserver_instances, clearLongPress_fn).call(this);
852
+ __privateSet(this, _clicked, false);
853
+ __privateSet(this, _pinchDist, Distance(
854
+ __privateMethod(this, _MouseObserver_instances, touchPos_fn).call(this, event.touches[0]),
855
+ __privateMethod(this, _MouseObserver_instances, touchPos_fn).call(this, event.touches[1])
856
+ ));
857
+ return;
858
+ }
859
+ if (event.touches.length !== 1) {
860
+ return;
861
+ }
862
+ const pos = __privateMethod(this, _MouseObserver_instances, touchPos_fn).call(this, event.touches[0]);
863
+ CopyVector2(__privateGet(this, _longPressOrigin), pos);
864
+ CopyVector2(__privateGet(this, _lastTouch), pos);
865
+ __privateSet(this, _longPressFired, false);
866
+ __privateSet(this, _pinchDist, 0);
867
+ __privateMethod(this, _MouseObserver_instances, clearLongPress_fn).call(this);
868
+ const x = pos.x;
869
+ const y = pos.y;
870
+ __privateSet(this, _longPressTimer, setTimeout(() => {
871
+ __privateSet(this, _longPressTimer, null);
872
+ __privateSet(this, _longPressFired, true);
873
+ __privateSet(this, _clicked, false);
874
+ __privateGet(this, _clickStop).call(this);
875
+ __privateGet(this, _contextMenu).call(this, { x, y });
876
+ }, LONG_PRESS_MS));
877
+ __privateSet(this, _clicked, true);
766
878
  __privateGet(this, _moveCallback).call(this, pos);
767
- if (__privateGet(this, _clicked)) {
879
+ __privateGet(this, _clickStart).call(this, pos, false);
880
+ };
881
+ touchMove_fn = function(event) {
882
+ __privateSet(this, _lastTouchAt, Date.now());
883
+ event.preventDefault();
884
+ if (event.touches.length >= 2) {
885
+ __privateMethod(this, _MouseObserver_instances, clearLongPress_fn).call(this);
886
+ __privateSet(this, _clicked, false);
887
+ const a = __privateMethod(this, _MouseObserver_instances, touchPos_fn).call(this, event.touches[0]);
888
+ const b = __privateMethod(this, _MouseObserver_instances, touchPos_fn).call(this, event.touches[1]);
889
+ const dist = Distance(a, b);
890
+ const anchor = { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };
891
+ if (__privateGet(this, _pinchDist) > 0) {
892
+ __privateGet(this, _moveCallback).call(this, anchor);
893
+ __privateGet(this, _zoomCallback).call(this, (dist - __privateGet(this, _pinchDist)) / PINCH_SENSITIVITY, anchor);
894
+ }
895
+ __privateSet(this, _pinchDist, dist);
896
+ return;
897
+ }
898
+ if (event.touches.length !== 1) {
899
+ return;
900
+ }
901
+ const pos = __privateMethod(this, _MouseObserver_instances, touchPos_fn).call(this, event.touches[0]);
902
+ if (__privateGet(this, _longPressTimer) !== null && Distance(pos, __privateGet(this, _longPressOrigin)) > LONG_PRESS_SLOP) {
903
+ __privateMethod(this, _MouseObserver_instances, clearLongPress_fn).call(this);
904
+ }
905
+ __privateGet(this, _moveCallback).call(this, pos);
906
+ if (__privateGet(this, _clicked) && !__privateGet(this, _longPressFired)) {
768
907
  __privateGet(this, _dragCallback).call(this, {
769
908
  x: pos.x - __privateGet(this, _lastTouch).x,
770
909
  y: pos.y - __privateGet(this, _lastTouch).y
@@ -772,26 +911,19 @@ moveTouch_fn = function(event) {
772
911
  }
773
912
  CopyVector2(__privateGet(this, _lastTouch), pos);
774
913
  };
775
- down_fn = function(event) {
776
- if (event.button !== 0) {
777
- return;
778
- }
779
- __privateSet(this, _clicked, true);
780
- __privateGet(this, _clickStart).call(this, __privateMethod(this, _MouseObserver_instances, mousePosition_fn).call(this, event), event.ctrlKey || event.shiftKey);
781
- };
782
- touchDown_fn = function(event) {
783
- __privateSet(this, _clicked, true);
784
- const rect = __privateGet(this, _ele).getBoundingClientRect();
785
- __privateGet(this, _lastTouch).x = event.touches[0].clientX - rect.left;
786
- __privateGet(this, _lastTouch).y = event.touches[0].clientY - rect.top;
787
- __privateGet(this, _clickStart).call(this, __privateGet(this, _lastTouch), false);
788
- };
789
- up_fn = function(event) {
790
- if (event.button !== 0) {
914
+ touchEnd_fn = function(event) {
915
+ __privateSet(this, _lastTouchAt, Date.now());
916
+ __privateMethod(this, _MouseObserver_instances, clearLongPress_fn).call(this);
917
+ if (event.touches.length >= 1) {
918
+ __privateSet(this, _pinchDist, 0);
791
919
  return;
792
920
  }
921
+ __privateSet(this, _pinchDist, 0);
793
922
  __privateSet(this, _clicked, false);
794
- __privateGet(this, _clickStop).call(this);
923
+ if (!__privateGet(this, _longPressFired)) {
924
+ __privateGet(this, _clickStop).call(this);
925
+ }
926
+ __privateSet(this, _longPressFired, false);
795
927
  };
796
928
 
797
929
  // src/elements/interfaces.ts
@@ -2771,6 +2903,12 @@ GlobalWidgetFactory.register("image", (node, config) => new ImageWidget(config))
2771
2903
  GlobalWidgetFactory.register("text", (node, config) => new TextWidget(node, config));
2772
2904
 
2773
2905
  // src/connection.ts
2906
+ var BACKWARD_PORT_STUB = 30;
2907
+ var BACKWARD_STUB_RAMP = 80;
2908
+ function smoothstep(t) {
2909
+ const x = Clamp01(t);
2910
+ return x * x * (3 - 2 * x);
2911
+ }
2774
2912
  function DefaultConnectionRenderer(connectionSize, connectionColor, mouseOverSize, mouseOverColor) {
2775
2913
  return (params) => {
2776
2914
  var _a, _b;
@@ -2794,10 +2932,26 @@ function DefaultConnectionRenderer(connectionSize, connectionColor, mouseOverSiz
2794
2932
  }
2795
2933
  params.ctx.strokeStyle = color;
2796
2934
  params.ctx.lineWidth = lineSize;
2935
+ const inX = params.start.x;
2936
+ const inY = params.start.y;
2937
+ const outX = params.end.x;
2938
+ const outY = params.end.y;
2939
+ const overlap = outX - inX;
2940
+ const fullStub = BACKWARD_PORT_STUB * params.graphScale;
2941
+ const ramp = BACKWARD_STUB_RAMP * params.graphScale;
2942
+ const stub = overlap <= 0 ? 0 : fullStub * smoothstep(overlap / ramp);
2943
+ const curveStartX = inX - stub;
2944
+ const curveEndX = outX + stub;
2797
2945
  params.ctx.beginPath();
2798
- params.ctx.moveTo(params.start.x, params.start.y);
2799
- const midX = (params.start.x + params.end.x) / 2;
2800
- params.ctx.bezierCurveTo(midX, params.start.y, midX, params.end.y, params.end.x, params.end.y);
2946
+ params.ctx.moveTo(inX, inY);
2947
+ if (stub > 0) {
2948
+ params.ctx.lineTo(curveStartX, inY);
2949
+ }
2950
+ const midX = (curveStartX + curveEndX) / 2;
2951
+ params.ctx.bezierCurveTo(midX, inY, midX, outY, curveEndX, outY);
2952
+ if (stub > 0) {
2953
+ params.ctx.lineTo(outX, outY);
2954
+ }
2801
2955
  params.ctx.stroke();
2802
2956
  params.ctx.shadowBlur = 0;
2803
2957
  };
@@ -3285,7 +3439,7 @@ function BuildConnectionRenderer(config) {
3285
3439
  // config?.mouseOverColor === undefined ? "#00FF22" : config.mouseOverColor
3286
3440
  );
3287
3441
  }
3288
- var _postProcessPass, _nodes, _connections2, _nodeHovering, _nodesGrabbed, _connectionSelected, _idleConnectionRenderer, _portHovering, _widgetHovering, _widgetCurrentlyClicking, _cursor, _nodeFactory, _boxSelect, _boxSelectStart_graphSpace, _boxSelectEnd_graphSpace, _boxSelectionNodes, _boxSelectStyle, _nodeRemovedCallbacks, _registeredNodeAddedCallbacks, _NodeSubsystem_instances, removeNodeConnections_fn, interactingWithNode_fn, interactingWithConnection_fn, interactingWithWidget_fn, removeNodeByIndex_fn, removeConnectionByIndex_fn, removeConnection_fn, nodesSelected_fn, organizeSelected_fn, selectInputNodesAndDescendents_fn, selectConnectedNodes_fn, selectNodeByIndex_fn, selectNode_fn, clearCurrentlySelectedConnection_fn, renderConnections_fn, renderNodes_fn, boxSelectionScreenspaceBox_fn;
3442
+ var _postProcessPass, _nodes, _connections2, _nodeHovering, _nodesGrabbed, _connectionSelected, _idleConnectionRenderer, _portHovering, _widgetHovering, _widgetCurrentlyClicking, _cursor, _nodeFactory, _boxSelect, _boxSelectStart_graphSpace, _boxSelectEnd_graphSpace, _boxSelectionNodes, _boxSelectStyle, _lastCtx, _nodeRemovedCallbacks, _registeredNodeAddedCallbacks, _NodeSubsystem_instances, removeNodeConnections_fn, interactingWithNode_fn, interactingWithConnection_fn, interactingWithWidget_fn, removeNodeByIndex_fn, removeConnectionByIndex_fn, removeConnection_fn, nodesSelected_fn, organizeSelected_fn, selectInputNodesAndDescendents_fn, selectConnectedNodes_fn, selectNodeByIndex_fn, selectNode_fn, clearCurrentlySelectedConnection_fn, renderConnections_fn, renderNodes_fn, boxSelectionScreenspaceBox_fn;
3289
3443
  var NodeSubsystem2 = class {
3290
3444
  // ========================================================================
3291
3445
  constructor(postProcessPass, config) {
@@ -3307,6 +3461,7 @@ var NodeSubsystem2 = class {
3307
3461
  __privateAdd(this, _boxSelectEnd_graphSpace);
3308
3462
  __privateAdd(this, _boxSelectionNodes);
3309
3463
  __privateAdd(this, _boxSelectStyle);
3464
+ __privateAdd(this, _lastCtx);
3310
3465
  // LISTENERS ==============================================================
3311
3466
  __privateAdd(this, _nodeRemovedCallbacks);
3312
3467
  __privateAdd(this, _registeredNodeAddedCallbacks);
@@ -3328,6 +3483,7 @@ var NodeSubsystem2 = class {
3328
3483
  __privateSet(this, _boxSelectStart_graphSpace, Zero());
3329
3484
  __privateSet(this, _boxSelectEnd_graphSpace, Zero());
3330
3485
  __privateSet(this, _boxSelectionNodes, new List());
3486
+ __privateSet(this, _lastCtx, null);
3331
3487
  __privateSet(this, _boxSelectStyle, new BoxStyle({
3332
3488
  border: {
3333
3489
  color: Theme.BoxSelect.Color,
@@ -3360,6 +3516,29 @@ var NodeSubsystem2 = class {
3360
3516
  }
3361
3517
  clickStart(mousePosition, camera, ctrlKey) {
3362
3518
  __privateSet(this, _boxSelect, false);
3519
+ __privateGet(this, _nodesGrabbed).Clear();
3520
+ if (__privateGet(this, _lastCtx) !== null) {
3521
+ __privateSet(this, _portHovering, null);
3522
+ __privateSet(this, _widgetHovering, null);
3523
+ __privateSet(this, _nodeHovering, -1);
3524
+ for (let i = 0; i < __privateGet(this, _nodes).length; i++) {
3525
+ const intersection = __privateGet(this, _nodes)[i].inBounds(__privateGet(this, _lastCtx), camera, mousePosition);
3526
+ if (intersection.Node !== void 0 && intersection.PortIndex === void 0 && intersection.Widget === void 0) {
3527
+ __privateSet(this, _nodeHovering, i);
3528
+ }
3529
+ if (intersection.Widget !== void 0) {
3530
+ __privateSet(this, _widgetHovering, intersection.Widget);
3531
+ }
3532
+ if (intersection.Port !== void 0 && intersection.Node !== void 0 && intersection.PortIndex !== void 0 && intersection.PortIsInput !== void 0) {
3533
+ __privateSet(this, _portHovering, {
3534
+ Index: intersection.PortIndex,
3535
+ Node: intersection.Node,
3536
+ Port: intersection.Port,
3537
+ InputPort: intersection.PortIsInput
3538
+ });
3539
+ }
3540
+ }
3541
+ }
3363
3542
  let hoveringSomething = false;
3364
3543
  if (__privateGet(this, _nodeHovering) > -1) {
3365
3544
  __privateMethod(this, _NodeSubsystem_instances, selectNodeByIndex_fn).call(this, __privateGet(this, _nodeHovering), !ctrlKey);
@@ -3534,6 +3713,19 @@ var NodeSubsystem2 = class {
3534
3713
  getNodes() {
3535
3714
  return __privateGet(this, _nodes);
3536
3715
  }
3716
+ /**
3717
+ * Returns currently selected nodes in stable graph order (same selection
3718
+ * state used by Ctrl+click and box-select styling via FlowNode.selected()).
3719
+ */
3720
+ getSelectedNodes() {
3721
+ const selected = new Array();
3722
+ for (let i = 0; i < __privateGet(this, _nodes).length; i++) {
3723
+ if (__privateGet(this, _nodes)[i].selected()) {
3724
+ selected.push(__privateGet(this, _nodes)[i]);
3725
+ }
3726
+ }
3727
+ return selected;
3728
+ }
3537
3729
  /**
3538
3730
  * Returns all nodes who are connected to the inputs of the
3539
3731
  * node in question
@@ -3680,6 +3872,7 @@ var NodeSubsystem2 = class {
3680
3872
  return config;
3681
3873
  }
3682
3874
  render(ctx, camera, mousePosition) {
3875
+ __privateSet(this, _lastCtx, ctx);
3683
3876
  __privateSet(this, _cursor, "default" /* Default */);
3684
3877
  TimeExecution("Render_Connections", () => {
3685
3878
  __privateMethod(this, _NodeSubsystem_instances, renderConnections_fn).call(this, ctx, camera, mousePosition);
@@ -3713,6 +3906,7 @@ _boxSelectStart_graphSpace = new WeakMap();
3713
3906
  _boxSelectEnd_graphSpace = new WeakMap();
3714
3907
  _boxSelectionNodes = new WeakMap();
3715
3908
  _boxSelectStyle = new WeakMap();
3909
+ _lastCtx = new WeakMap();
3716
3910
  _nodeRemovedCallbacks = new WeakMap();
3717
3911
  _registeredNodeAddedCallbacks = new WeakMap();
3718
3912
  _NodeSubsystem_instances = new WeakSet();
@@ -4369,42 +4563,44 @@ var FlowNode = class {
4369
4563
  // }
4370
4564
  calculateBounds(ctx, camera) {
4371
4565
  const tempMeasurement = Zero();
4372
- const doublePadding = __privateGet(this, _padding2) * 2;
4566
+ const zoom = camera.zoom;
4567
+ const scaledPadding = __privateGet(this, _padding2) * zoom;
4568
+ const doubleScaledPadding = scaledPadding * 2;
4569
+ const scaledElementSpacing = __privateGet(this, _elementSpacing) * zoom;
4373
4570
  const screenSpacePosition = Zero();
4374
4571
  camera.graphSpaceToScreenSpace(__privateGet(this, _position), screenSpacePosition);
4375
4572
  const size = Zero();
4376
- __privateGet(this, _title2).size(ctx, 1, size);
4573
+ __privateGet(this, _title2).size(ctx, zoom, size);
4377
4574
  const subtitleSize = Zero();
4378
- __privateGet(this, _subTitle).size(ctx, 1, subtitleSize);
4575
+ __privateGet(this, _subTitle).size(ctx, zoom, subtitleSize);
4379
4576
  size.x = Math.max(size.x, subtitleSize.x);
4380
4577
  if (__privateGet(this, _infoText) !== "") {
4381
4578
  size.x += size.y * 4;
4382
4579
  }
4383
- size.x += doublePadding;
4384
- size.y += doublePadding + __privateGet(this, _elementSpacing) * __privateGet(this, _input).length;
4580
+ size.x += doubleScaledPadding;
4581
+ size.y += doubleScaledPadding + scaledElementSpacing * __privateGet(this, _input).length;
4385
4582
  for (let i = 0; i < __privateGet(this, _input).length; i++) {
4386
4583
  const port = __privateGet(this, _input)[i];
4387
- __privateGet(this, _portTextStyle).measure(ctx, 1, port.getDisplayName(), tempMeasurement);
4584
+ __privateGet(this, _portTextStyle).measure(ctx, zoom, port.getDisplayName(), tempMeasurement);
4388
4585
  size.y += tempMeasurement.y;
4389
- size.x = Math.max(size.x, tempMeasurement.x + doublePadding);
4586
+ size.x = Math.max(size.x, tempMeasurement.x + doubleScaledPadding);
4390
4587
  }
4391
- size.y += __privateGet(this, _elementSpacing) * __privateGet(this, _output).length;
4588
+ size.y += scaledElementSpacing * __privateGet(this, _output).length;
4392
4589
  for (let i = 0; i < __privateGet(this, _output).length; i++) {
4393
4590
  const port = __privateGet(this, _output)[i];
4394
- __privateGet(this, _portTextStyle).measure(ctx, 1, port.getDisplayName(), tempMeasurement);
4591
+ __privateGet(this, _portTextStyle).measure(ctx, zoom, port.getDisplayName(), tempMeasurement);
4395
4592
  size.y += tempMeasurement.y;
4396
- size.x = Math.max(size.x, tempMeasurement.x + doublePadding);
4593
+ size.x = Math.max(size.x, tempMeasurement.x + doubleScaledPadding);
4397
4594
  }
4398
- size.y += __privateGet(this, _elementSpacing) * __privateGet(this, _widgets).length;
4595
+ size.y += scaledElementSpacing * __privateGet(this, _widgets).length;
4399
4596
  for (let i = 0; i < __privateGet(this, _widgets).length; i++) {
4400
4597
  const element = __privateGet(this, _widgets)[i];
4401
4598
  const eleSize = element.Size();
4402
- size.y += eleSize.y;
4403
- size.x = Math.max(size.x, eleSize.x + doublePadding);
4599
+ size.y += eleSize.y * zoom;
4600
+ size.x = Math.max(size.x, eleSize.x * zoom + doubleScaledPadding);
4404
4601
  }
4405
- size.y += __privateGet(this, _elementSpacing);
4406
- size.x = Math.max(size.x, MINIMUM_NODE_WIDTH);
4407
- ScaleVector(size, camera.zoom);
4602
+ size.y += scaledElementSpacing;
4603
+ size.x = Math.max(size.x, MINIMUM_NODE_WIDTH * zoom);
4408
4604
  return {
4409
4605
  Position: screenSpacePosition,
4410
4606
  Size: size
@@ -6364,9 +6560,9 @@ var NodeFlowGraph = class {
6364
6560
  __privateSet(this, _contextMenuConfig, CombineContextMenus({
6365
6561
  items: [
6366
6562
  {
6367
- name: "Reset View",
6563
+ name: "Center on Graph",
6368
6564
  group: contextMenuGroup,
6369
- callback: __privateGet(this, _camera).reset.bind(__privateGet(this, _camera))
6565
+ callback: this.centerOnGraph.bind(this)
6370
6566
  }
6371
6567
  ]
6372
6568
  }, config == null ? void 0 : config.contextMenu));
@@ -6386,21 +6582,19 @@ var NodeFlowGraph = class {
6386
6582
  __privateSet(this, _backgroundRenderer, BuildBackgroundRenderer(backgroundColor));
6387
6583
  }
6388
6584
  window.requestAnimationFrame(__privateMethod(this, _NodeFlowGraph_instances, render_fn).bind(this));
6389
- __privateGet(this, _canvas).addEventListener("wheel", (event) => {
6390
- event.preventDefault();
6391
- this.zoom(Math.sign(event.deltaY));
6392
- }, false);
6393
6585
  new MouseObserver(
6394
6586
  __privateGet(this, _canvas),
6395
6587
  __privateMethod(this, _NodeFlowGraph_instances, mouseDragEvent_fn).bind(this),
6396
- // Mouse move event
6397
6588
  (mousePosition) => {
6398
6589
  __privateSet(this, _mousePosition, mousePosition);
6399
6590
  },
6400
6591
  __privateMethod(this, _NodeFlowGraph_instances, clickStart_fn).bind(this),
6401
6592
  __privateMethod(this, _NodeFlowGraph_instances, clickEnd_fn).bind(this),
6402
6593
  __privateMethod(this, _NodeFlowGraph_instances, openContextMenu_fn).bind(this),
6403
- __privateMethod(this, _NodeFlowGraph_instances, fileDrop_fn).bind(this)
6594
+ __privateMethod(this, _NodeFlowGraph_instances, fileDrop_fn).bind(this),
6595
+ (amount, anchor) => {
6596
+ this.zoom(amount, anchor);
6597
+ }
6404
6598
  );
6405
6599
  document.addEventListener(
6406
6600
  "keydown",
@@ -6451,17 +6645,20 @@ var NodeFlowGraph = class {
6451
6645
  addNoteDragStopListener(callback) {
6452
6646
  __privateGet(this, _mainNoteSubsystem).addNoteDragStopListener(callback);
6453
6647
  }
6454
- zoom(amount) {
6648
+ zoom(amount, anchor) {
6649
+ const anchorPos = anchor != null ? anchor : __privateGet(this, _mousePosition);
6455
6650
  let oldPos = void 0;
6456
- if (__privateGet(this, _mousePosition)) {
6457
- oldPos = __privateMethod(this, _NodeFlowGraph_instances, sceenPositionToGraphPosition_fn).call(this, __privateGet(this, _mousePosition));
6458
- ;
6651
+ if (anchorPos !== void 0) {
6652
+ oldPos = __privateMethod(this, _NodeFlowGraph_instances, sceenPositionToGraphPosition_fn).call(this, anchorPos);
6459
6653
  }
6460
6654
  __privateGet(this, _camera).zoom += amount * __privateGet(this, _camera).zoom * 0.05;
6461
- if (!oldPos || !__privateGet(this, _mousePosition)) {
6655
+ if (!oldPos || anchorPos === void 0) {
6462
6656
  return;
6463
6657
  }
6464
- const newPos = __privateMethod(this, _NodeFlowGraph_instances, sceenPositionToGraphPosition_fn).call(this, __privateGet(this, _mousePosition));
6658
+ if (anchor !== void 0) {
6659
+ __privateSet(this, _mousePosition, anchor);
6660
+ }
6661
+ const newPos = __privateMethod(this, _NodeFlowGraph_instances, sceenPositionToGraphPosition_fn).call(this, anchorPos);
6465
6662
  __privateGet(this, _camera).position.x += (newPos.x - oldPos.x) * __privateGet(this, _camera).zoom;
6466
6663
  __privateGet(this, _camera).position.y += (newPos.y - oldPos.y) * __privateGet(this, _camera).zoom;
6467
6664
  }
@@ -6477,6 +6674,60 @@ var NodeFlowGraph = class {
6477
6674
  getNodes() {
6478
6675
  return __privateGet(this, _mainNodeSubsystem).getNodes();
6479
6676
  }
6677
+ /**
6678
+ * Returns currently selected nodes in stable graph order (same selection
6679
+ * state used by Ctrl+click and box-select styling via FlowNode.selected()).
6680
+ */
6681
+ getSelectedNodes() {
6682
+ return __privateGet(this, _mainNodeSubsystem).getSelectedNodes();
6683
+ }
6684
+ /**
6685
+ * Adjusts camera position and zoom so all nodes fit in view (~10% padding).
6686
+ * Falls back to camera.reset() when there are no nodes.
6687
+ */
6688
+ centerOnGraph() {
6689
+ const nodes = this.getNodes();
6690
+ if (nodes.length === 0) {
6691
+ __privateGet(this, _camera).reset();
6692
+ return;
6693
+ }
6694
+ const measureCamera = new Camera();
6695
+ let minX = Infinity;
6696
+ let minY = Infinity;
6697
+ let maxX = -Infinity;
6698
+ let maxY = -Infinity;
6699
+ for (let i = 0; i < nodes.length; i++) {
6700
+ const bounds = nodes[i].calculateBounds(__privateGet(this, _ctx), measureCamera);
6701
+ minX = Math.min(minX, bounds.Position.x);
6702
+ minY = Math.min(minY, bounds.Position.y);
6703
+ maxX = Math.max(maxX, bounds.Position.x + bounds.Size.x);
6704
+ maxY = Math.max(maxY, bounds.Position.y + bounds.Size.y);
6705
+ }
6706
+ let width2 = maxX - minX;
6707
+ let height2 = maxY - minY;
6708
+ if (width2 <= 0 || height2 <= 0) {
6709
+ __privateGet(this, _camera).reset();
6710
+ return;
6711
+ }
6712
+ const padX = width2 * 0.05;
6713
+ const padY = height2 * 0.05;
6714
+ minX -= padX;
6715
+ minY -= padY;
6716
+ width2 += padX * 2;
6717
+ height2 += padY * 2;
6718
+ const canvasWidth = __privateGet(this, _canvas).clientWidth;
6719
+ const canvasHeight = __privateGet(this, _canvas).clientHeight;
6720
+ if (canvasWidth <= 0 || canvasHeight <= 0) {
6721
+ __privateGet(this, _camera).reset();
6722
+ return;
6723
+ }
6724
+ const zoom = Math.min(canvasWidth / width2, canvasHeight / height2);
6725
+ const centerX = minX + width2 / 2;
6726
+ const centerY = minY + height2 / 2;
6727
+ __privateGet(this, _camera).zoom = zoom;
6728
+ __privateGet(this, _camera).position.x = canvasWidth / 2 - centerX * zoom;
6729
+ __privateGet(this, _camera).position.y = canvasHeight / 2 - centerY * zoom;
6730
+ }
6480
6731
  connectedInputsNodeReferences(nodeIndex) {
6481
6732
  return __privateGet(this, _mainNodeSubsystem).connectedInputsNodeReferencesByIndex(nodeIndex);
6482
6733
  }
@@ -6579,21 +6830,6 @@ openContextMenu_fn = function(position) {
6579
6830
  Position: contextMenuPosition
6580
6831
  });
6581
6832
  };
6582
- // Somethings wrong here. Needs more testing
6583
- // #fitView(): void {
6584
- // if (this.#nodes.length === 0) {
6585
- // return;
6586
- // }
6587
- // const curBox: Box = {
6588
- // Position: { x: 0, y: 0 },
6589
- // Size: { x: 0, y: 0 }
6590
- // };
6591
- // CopyBox(curBox, this.#nodes[0].calculateBounds(this.#ctx, this.#graphState.position, this.#graphState.scale));
6592
- // for (let i = 1; i < this.#nodes.length; i++) {
6593
- // ExpandBox(curBox, this.#nodes[i].calculateBounds(this.#ctx, this.#graphState.position, this.#graphState.scale));
6594
- // }
6595
- // CopyVector2(this.#graphState.position, curBox.Position);
6596
- // }
6597
6833
  clickEnd_fn = function() {
6598
6834
  this.currentView().clickEnd();
6599
6835
  };
@@ -6659,6 +6895,7 @@ renderQuickMenu_fn = function() {
6659
6895
  0 && (module.exports = {
6660
6896
  ButtonWidget,
6661
6897
  ColorWidget,
6898
+ ContextMenuItemState,
6662
6899
  FlowNode,
6663
6900
  FlowNote,
6664
6901
  GlobalWidgetFactory,