@elicdavis/node-flow 0.1.12 → 0.1.14

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
@@ -74,7 +74,8 @@ var Theme = {
74
74
  ContextMenu: {
75
75
  BackgroundColor: "#07212A",
76
76
  HighlightColor: "#205A6D",
77
- FontColor: "#afb9bb"
77
+ FontColor: "#afb9bb",
78
+ DisabledFontColor: "#4a585c"
78
79
  },
79
80
  Note: {
80
81
  FontColor: "#afb9bb",
@@ -339,22 +340,33 @@ _count2 = new WeakMap();
339
340
 
340
341
  // src/contextMenu.ts
341
342
  var contextEntryHeight = 30;
342
- var _name, _callback, _textStyle;
343
+ var ContextMenuItemState = /* @__PURE__ */ ((ContextMenuItemState2) => {
344
+ ContextMenuItemState2[ContextMenuItemState2["Enabled"] = 0] = "Enabled";
345
+ ContextMenuItemState2[ContextMenuItemState2["Disabled"] = 1] = "Disabled";
346
+ ContextMenuItemState2[ContextMenuItemState2["Hidden"] = 2] = "Hidden";
347
+ return ContextMenuItemState2;
348
+ })(ContextMenuItemState || {});
349
+ var _name, _callback, _textStyle, _state;
343
350
  var ContextMenuItem = class {
344
351
  constructor(config) {
345
352
  __privateAdd(this, _name);
346
353
  __privateAdd(this, _callback);
347
354
  __privateAdd(this, _textStyle);
355
+ __privateAdd(this, _state);
348
356
  __privateSet(this, _name, (config == null ? void 0 : config.name) === void 0 ? "item" : config.name);
349
357
  __privateSet(this, _callback, config == null ? void 0 : config.callback);
350
358
  __privateSet(this, _textStyle, new TextStyle(config == null ? void 0 : config.textStyle));
351
359
  this.group = config == null ? void 0 : config.group;
360
+ __privateSet(this, _state, (config == null ? void 0 : config.enabled) === void 0 ? 0 /* Enabled */ : config.enabled());
352
361
  }
353
362
  getName() {
354
363
  return __privateGet(this, _name);
355
364
  }
365
+ state() {
366
+ return __privateGet(this, _state);
367
+ }
356
368
  execute() {
357
- if (__privateGet(this, _callback) === void 0) {
369
+ if (__privateGet(this, _state) !== 0 /* Enabled */ || __privateGet(this, _callback) === void 0) {
358
370
  return;
359
371
  }
360
372
  __privateGet(this, _callback).call(this);
@@ -363,6 +375,7 @@ var ContextMenuItem = class {
363
375
  _name = new WeakMap();
364
376
  _callback = new WeakMap();
365
377
  _textStyle = new WeakMap();
378
+ _state = new WeakMap();
366
379
  var _calculatedHeight;
367
380
  var ContextGroup = class {
368
381
  constructor(entries) {
@@ -436,7 +449,11 @@ var _ContextMenu = class _ContextMenu {
436
449
  }
437
450
  if ((config == null ? void 0 : config.items) !== void 0) {
438
451
  for (let i = 0; i < (config == null ? void 0 : config.items.length); i++) {
439
- __privateGet(this, _items).push(new ContextMenuItem(config == null ? void 0 : config.items[i]));
452
+ const item = new ContextMenuItem(config == null ? void 0 : config.items[i]);
453
+ if (item.state() === 2 /* Hidden */) {
454
+ continue;
455
+ }
456
+ __privateGet(this, _items).push(item);
440
457
  }
441
458
  }
442
459
  __privateMethod(this, _ContextMenu_instances, calculateEntries_fn).call(this);
@@ -507,7 +524,8 @@ var _ContextMenu = class _ContextMenu {
507
524
  __privateSet(this, _openSubMenu, void 0);
508
525
  }
509
526
  }
510
- if (entryMousedOver || __privateGet(this, _openSubMenu) !== void 0 && entry.subMenu === __privateGet(this, _openSubMenu)) {
527
+ const itemDisabled = entry.item !== void 0 && entry.item.state() === 1 /* Disabled */;
528
+ if (!itemDisabled && (entryMousedOver || __privateGet(this, _openSubMenu) !== void 0 && entry.subMenu === __privateGet(this, _openSubMenu))) {
511
529
  ctx.fillStyle = Theme.ContextMenu.HighlightColor;
512
530
  ctx.beginPath();
513
531
  ctx.roundRect(
@@ -520,6 +538,9 @@ var _ContextMenu = class _ContextMenu {
520
538
  ctx.fill();
521
539
  }
522
540
  __privateGet(this, _textStyle2).setupStyle(ctx, menuScale);
541
+ if (itemDisabled) {
542
+ ctx.fillStyle = Theme.ContextMenu.DisabledFontColor;
543
+ }
523
544
  ctx.fillText(entry.text, position.x + scaledEntryHeight / 5, __privateGet(this, _tempBox).Position.y + scaledEntryHeight / 2);
524
545
  if (entry.subMenu !== void 0) {
525
546
  ctx.beginPath();
@@ -631,9 +652,13 @@ _openSubMenu = new WeakMap();
631
652
  var ContextMenu = _ContextMenu;
632
653
 
633
654
  // src/input.ts
634
- var _clicked, _lastTouch, _ele, _lastMousePosition, _dragCallback, _moveCallback, _clickStart, _clickStop, _contextMenu, _MouseObserver_instances, mousePosition_fn, move_fn, moveTouch_fn, down_fn, touchDown_fn, up_fn;
655
+ var LONG_PRESS_MS = 500;
656
+ var LONG_PRESS_SLOP = 12;
657
+ var PINCH_SENSITIVITY = 50;
658
+ var SUPPRESS_MOUSE_MS = 600;
659
+ 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;
635
660
  var MouseObserver = class {
636
- constructor(ele, dragCallback, moveCallback, clickStart, clickStop, contextMenu, fileDrop) {
661
+ constructor(ele, dragCallback, moveCallback, clickStart, clickStop, contextMenu, fileDrop, zoomCallback) {
637
662
  __privateAdd(this, _MouseObserver_instances);
638
663
  __privateAdd(this, _clicked);
639
664
  __privateAdd(this, _lastTouch);
@@ -644,49 +669,55 @@ var MouseObserver = class {
644
669
  __privateAdd(this, _clickStart);
645
670
  __privateAdd(this, _clickStop);
646
671
  __privateAdd(this, _contextMenu);
672
+ __privateAdd(this, _zoomCallback);
673
+ __privateAdd(this, _longPressTimer, null);
674
+ __privateAdd(this, _longPressOrigin, Zero());
675
+ __privateAdd(this, _longPressFired, false);
676
+ __privateAdd(this, _pinchDist, 0);
677
+ __privateAdd(this, _lastTouchAt, 0);
647
678
  __privateSet(this, _ele, ele);
648
679
  __privateSet(this, _dragCallback, dragCallback);
649
680
  __privateSet(this, _moveCallback, moveCallback);
650
681
  __privateSet(this, _clickStart, clickStart);
651
682
  __privateSet(this, _clickStop, clickStop);
652
683
  __privateSet(this, _contextMenu, contextMenu);
684
+ __privateSet(this, _zoomCallback, zoomCallback);
653
685
  __privateSet(this, _clicked, false);
654
686
  __privateSet(this, _lastTouch, Zero());
655
687
  __privateSet(this, _lastMousePosition, Zero());
688
+ ele.style.touchAction = "none";
656
689
  ele.addEventListener("mousedown", __privateMethod(this, _MouseObserver_instances, down_fn).bind(this), false);
657
- ele.addEventListener("touchstart", __privateMethod(this, _MouseObserver_instances, touchDown_fn).bind(this), false);
690
+ ele.addEventListener("touchstart", __privateMethod(this, _MouseObserver_instances, touchStart_fn).bind(this), { passive: false });
658
691
  document.addEventListener("mouseup", __privateMethod(this, _MouseObserver_instances, up_fn).bind(this), false);
659
- document.addEventListener("touchend", __privateMethod(this, _MouseObserver_instances, up_fn).bind(this), false);
692
+ document.addEventListener("touchend", __privateMethod(this, _MouseObserver_instances, touchEnd_fn).bind(this), false);
693
+ document.addEventListener("touchcancel", __privateMethod(this, _MouseObserver_instances, touchEnd_fn).bind(this), false);
660
694
  ele.addEventListener("mousemove", __privateMethod(this, _MouseObserver_instances, move_fn).bind(this), false);
661
- ele.addEventListener("touchmove", __privateMethod(this, _MouseObserver_instances, moveTouch_fn).bind(this), false);
695
+ ele.addEventListener("touchmove", __privateMethod(this, _MouseObserver_instances, touchMove_fn).bind(this), { passive: false });
696
+ ele.addEventListener("wheel", __privateMethod(this, _MouseObserver_instances, wheel_fn).bind(this), { passive: false });
662
697
  ele.addEventListener("drop", (ev) => {
663
698
  var _a;
664
699
  ev.preventDefault();
665
- console.log(ev);
666
700
  if ((_a = ev.dataTransfer) == null ? void 0 : _a.items) {
667
701
  [...ev.dataTransfer.items].forEach((item, i) => {
668
702
  if (item.kind === "file") {
669
703
  const file = item.getAsFile();
670
704
  if (file) {
671
705
  fileDrop(file);
672
- console.log(file);
673
- console.log(`\u2026 file[${i}].name = ${file.name}`);
674
706
  }
675
707
  }
676
708
  });
677
- } else if (ev.dataTransfer) {
678
- [...ev.dataTransfer.files].forEach((file, i) => {
679
- console.log(`\u2026 file[${i}].name = ${file.name}`);
680
- });
681
709
  }
682
710
  });
683
711
  ele.addEventListener("dragover", (ev) => {
684
712
  ev.preventDefault();
685
- __privateGet(this, _moveCallback).call(this, __privateMethod(this, _MouseObserver_instances, mousePosition_fn).call(this, ev));
713
+ __privateGet(this, _moveCallback).call(this, __privateMethod(this, _MouseObserver_instances, mousePos_fn).call(this, ev));
686
714
  });
687
715
  ele.addEventListener("contextmenu", (evt) => {
688
- contextMenu(__privateMethod(this, _MouseObserver_instances, mousePosition_fn).call(this, evt));
689
716
  evt.preventDefault();
717
+ if (Date.now() - __privateGet(this, _lastTouchAt) < SUPPRESS_MOUSE_MS) {
718
+ return;
719
+ }
720
+ __privateGet(this, _contextMenu).call(this, __privateMethod(this, _MouseObserver_instances, mousePos_fn).call(this, evt));
690
721
  }, false);
691
722
  }
692
723
  };
@@ -699,16 +730,57 @@ _moveCallback = new WeakMap();
699
730
  _clickStart = new WeakMap();
700
731
  _clickStop = new WeakMap();
701
732
  _contextMenu = new WeakMap();
733
+ _zoomCallback = new WeakMap();
734
+ _longPressTimer = new WeakMap();
735
+ _longPressOrigin = new WeakMap();
736
+ _longPressFired = new WeakMap();
737
+ _pinchDist = new WeakMap();
738
+ _lastTouchAt = new WeakMap();
702
739
  _MouseObserver_instances = new WeakSet();
703
- mousePosition_fn = function(event) {
704
- var rect = __privateGet(this, _ele).getBoundingClientRect();
740
+ mousePos_fn = function(event) {
741
+ const rect = __privateGet(this, _ele).getBoundingClientRect();
705
742
  return {
706
743
  x: event.clientX - rect.left,
707
744
  y: event.clientY - rect.top
708
745
  };
709
746
  };
747
+ touchPos_fn = function(touch) {
748
+ const rect = __privateGet(this, _ele).getBoundingClientRect();
749
+ return {
750
+ x: touch.clientX - rect.left,
751
+ y: touch.clientY - rect.top
752
+ };
753
+ };
754
+ fromTouch_fn = function() {
755
+ return Date.now() - __privateGet(this, _lastTouchAt) < SUPPRESS_MOUSE_MS;
756
+ };
757
+ clearLongPress_fn = function() {
758
+ if (__privateGet(this, _longPressTimer) !== null) {
759
+ clearTimeout(__privateGet(this, _longPressTimer));
760
+ __privateSet(this, _longPressTimer, null);
761
+ }
762
+ };
763
+ wheel_fn = function(event) {
764
+ event.preventDefault();
765
+ let dy = event.deltaY;
766
+ if (event.deltaMode === WheelEvent.DOM_DELTA_LINE) {
767
+ dy *= 16;
768
+ } else if (event.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
769
+ dy *= __privateGet(this, _ele).clientHeight;
770
+ }
771
+ const amount = -dy / 100;
772
+ if (amount === 0) {
773
+ return;
774
+ }
775
+ const anchor = __privateMethod(this, _MouseObserver_instances, mousePos_fn).call(this, event);
776
+ __privateGet(this, _moveCallback).call(this, anchor);
777
+ __privateGet(this, _zoomCallback).call(this, amount, anchor);
778
+ };
710
779
  move_fn = function(event) {
711
- const pos = __privateMethod(this, _MouseObserver_instances, mousePosition_fn).call(this, event);
780
+ if (__privateMethod(this, _MouseObserver_instances, fromTouch_fn).call(this)) {
781
+ return;
782
+ }
783
+ const pos = __privateMethod(this, _MouseObserver_instances, mousePos_fn).call(this, event);
712
784
  if (__privateGet(this, _clicked)) {
713
785
  const delta = Zero();
714
786
  SubVector2(delta, pos, __privateGet(this, _lastMousePosition));
@@ -717,14 +789,80 @@ move_fn = function(event) {
717
789
  __privateGet(this, _moveCallback).call(this, pos);
718
790
  CopyVector2(__privateGet(this, _lastMousePosition), pos);
719
791
  };
720
- moveTouch_fn = function(event) {
721
- const rect = __privateGet(this, _ele).getBoundingClientRect();
722
- const pos = {
723
- x: event.touches[0].clientX - rect.left,
724
- y: event.touches[0].clientY - rect.top
725
- };
792
+ down_fn = function(event) {
793
+ if (event.button !== 0 || __privateMethod(this, _MouseObserver_instances, fromTouch_fn).call(this)) {
794
+ return;
795
+ }
796
+ __privateSet(this, _clicked, true);
797
+ __privateGet(this, _clickStart).call(this, __privateMethod(this, _MouseObserver_instances, mousePos_fn).call(this, event), event.ctrlKey || event.shiftKey);
798
+ };
799
+ up_fn = function(event) {
800
+ if (event.button !== 0 || __privateMethod(this, _MouseObserver_instances, fromTouch_fn).call(this)) {
801
+ return;
802
+ }
803
+ __privateSet(this, _clicked, false);
804
+ __privateGet(this, _clickStop).call(this);
805
+ };
806
+ touchStart_fn = function(event) {
807
+ __privateSet(this, _lastTouchAt, Date.now());
808
+ event.preventDefault();
809
+ if (event.touches.length >= 2) {
810
+ __privateMethod(this, _MouseObserver_instances, clearLongPress_fn).call(this);
811
+ __privateSet(this, _clicked, false);
812
+ __privateSet(this, _pinchDist, Distance(
813
+ __privateMethod(this, _MouseObserver_instances, touchPos_fn).call(this, event.touches[0]),
814
+ __privateMethod(this, _MouseObserver_instances, touchPos_fn).call(this, event.touches[1])
815
+ ));
816
+ return;
817
+ }
818
+ if (event.touches.length !== 1) {
819
+ return;
820
+ }
821
+ const pos = __privateMethod(this, _MouseObserver_instances, touchPos_fn).call(this, event.touches[0]);
822
+ CopyVector2(__privateGet(this, _longPressOrigin), pos);
823
+ CopyVector2(__privateGet(this, _lastTouch), pos);
824
+ __privateSet(this, _longPressFired, false);
825
+ __privateSet(this, _pinchDist, 0);
826
+ __privateMethod(this, _MouseObserver_instances, clearLongPress_fn).call(this);
827
+ const x = pos.x;
828
+ const y = pos.y;
829
+ __privateSet(this, _longPressTimer, setTimeout(() => {
830
+ __privateSet(this, _longPressTimer, null);
831
+ __privateSet(this, _longPressFired, true);
832
+ __privateSet(this, _clicked, false);
833
+ __privateGet(this, _clickStop).call(this);
834
+ __privateGet(this, _contextMenu).call(this, { x, y });
835
+ }, LONG_PRESS_MS));
836
+ __privateSet(this, _clicked, true);
726
837
  __privateGet(this, _moveCallback).call(this, pos);
727
- if (__privateGet(this, _clicked)) {
838
+ __privateGet(this, _clickStart).call(this, pos, false);
839
+ };
840
+ touchMove_fn = function(event) {
841
+ __privateSet(this, _lastTouchAt, Date.now());
842
+ event.preventDefault();
843
+ if (event.touches.length >= 2) {
844
+ __privateMethod(this, _MouseObserver_instances, clearLongPress_fn).call(this);
845
+ __privateSet(this, _clicked, false);
846
+ const a = __privateMethod(this, _MouseObserver_instances, touchPos_fn).call(this, event.touches[0]);
847
+ const b = __privateMethod(this, _MouseObserver_instances, touchPos_fn).call(this, event.touches[1]);
848
+ const dist = Distance(a, b);
849
+ const anchor = { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };
850
+ if (__privateGet(this, _pinchDist) > 0) {
851
+ __privateGet(this, _moveCallback).call(this, anchor);
852
+ __privateGet(this, _zoomCallback).call(this, (dist - __privateGet(this, _pinchDist)) / PINCH_SENSITIVITY, anchor);
853
+ }
854
+ __privateSet(this, _pinchDist, dist);
855
+ return;
856
+ }
857
+ if (event.touches.length !== 1) {
858
+ return;
859
+ }
860
+ const pos = __privateMethod(this, _MouseObserver_instances, touchPos_fn).call(this, event.touches[0]);
861
+ if (__privateGet(this, _longPressTimer) !== null && Distance(pos, __privateGet(this, _longPressOrigin)) > LONG_PRESS_SLOP) {
862
+ __privateMethod(this, _MouseObserver_instances, clearLongPress_fn).call(this);
863
+ }
864
+ __privateGet(this, _moveCallback).call(this, pos);
865
+ if (__privateGet(this, _clicked) && !__privateGet(this, _longPressFired)) {
728
866
  __privateGet(this, _dragCallback).call(this, {
729
867
  x: pos.x - __privateGet(this, _lastTouch).x,
730
868
  y: pos.y - __privateGet(this, _lastTouch).y
@@ -732,26 +870,19 @@ moveTouch_fn = function(event) {
732
870
  }
733
871
  CopyVector2(__privateGet(this, _lastTouch), pos);
734
872
  };
735
- down_fn = function(event) {
736
- if (event.button !== 0) {
737
- return;
738
- }
739
- __privateSet(this, _clicked, true);
740
- __privateGet(this, _clickStart).call(this, __privateMethod(this, _MouseObserver_instances, mousePosition_fn).call(this, event), event.ctrlKey || event.shiftKey);
741
- };
742
- touchDown_fn = function(event) {
743
- __privateSet(this, _clicked, true);
744
- const rect = __privateGet(this, _ele).getBoundingClientRect();
745
- __privateGet(this, _lastTouch).x = event.touches[0].clientX - rect.left;
746
- __privateGet(this, _lastTouch).y = event.touches[0].clientY - rect.top;
747
- __privateGet(this, _clickStart).call(this, __privateGet(this, _lastTouch), false);
748
- };
749
- up_fn = function(event) {
750
- if (event.button !== 0) {
873
+ touchEnd_fn = function(event) {
874
+ __privateSet(this, _lastTouchAt, Date.now());
875
+ __privateMethod(this, _MouseObserver_instances, clearLongPress_fn).call(this);
876
+ if (event.touches.length >= 1) {
877
+ __privateSet(this, _pinchDist, 0);
751
878
  return;
752
879
  }
880
+ __privateSet(this, _pinchDist, 0);
753
881
  __privateSet(this, _clicked, false);
754
- __privateGet(this, _clickStop).call(this);
882
+ if (!__privateGet(this, _longPressFired)) {
883
+ __privateGet(this, _clickStop).call(this);
884
+ }
885
+ __privateSet(this, _longPressFired, false);
755
886
  };
756
887
 
757
888
  // src/elements/interfaces.ts
@@ -2731,6 +2862,12 @@ GlobalWidgetFactory.register("image", (node, config) => new ImageWidget(config))
2731
2862
  GlobalWidgetFactory.register("text", (node, config) => new TextWidget(node, config));
2732
2863
 
2733
2864
  // src/connection.ts
2865
+ var BACKWARD_PORT_STUB = 30;
2866
+ var BACKWARD_STUB_RAMP = 80;
2867
+ function smoothstep(t) {
2868
+ const x = Clamp01(t);
2869
+ return x * x * (3 - 2 * x);
2870
+ }
2734
2871
  function DefaultConnectionRenderer(connectionSize, connectionColor, mouseOverSize, mouseOverColor) {
2735
2872
  return (params) => {
2736
2873
  var _a, _b;
@@ -2754,10 +2891,26 @@ function DefaultConnectionRenderer(connectionSize, connectionColor, mouseOverSiz
2754
2891
  }
2755
2892
  params.ctx.strokeStyle = color;
2756
2893
  params.ctx.lineWidth = lineSize;
2894
+ const inX = params.start.x;
2895
+ const inY = params.start.y;
2896
+ const outX = params.end.x;
2897
+ const outY = params.end.y;
2898
+ const overlap = outX - inX;
2899
+ const fullStub = BACKWARD_PORT_STUB * params.graphScale;
2900
+ const ramp = BACKWARD_STUB_RAMP * params.graphScale;
2901
+ const stub = overlap <= 0 ? 0 : fullStub * smoothstep(overlap / ramp);
2902
+ const curveStartX = inX - stub;
2903
+ const curveEndX = outX + stub;
2757
2904
  params.ctx.beginPath();
2758
- params.ctx.moveTo(params.start.x, params.start.y);
2759
- const midX = (params.start.x + params.end.x) / 2;
2760
- params.ctx.bezierCurveTo(midX, params.start.y, midX, params.end.y, params.end.x, params.end.y);
2905
+ params.ctx.moveTo(inX, inY);
2906
+ if (stub > 0) {
2907
+ params.ctx.lineTo(curveStartX, inY);
2908
+ }
2909
+ const midX = (curveStartX + curveEndX) / 2;
2910
+ params.ctx.bezierCurveTo(midX, inY, midX, outY, curveEndX, outY);
2911
+ if (stub > 0) {
2912
+ params.ctx.lineTo(outX, outY);
2913
+ }
2761
2914
  params.ctx.stroke();
2762
2915
  params.ctx.shadowBlur = 0;
2763
2916
  };
@@ -3245,7 +3398,7 @@ function BuildConnectionRenderer(config) {
3245
3398
  // config?.mouseOverColor === undefined ? "#00FF22" : config.mouseOverColor
3246
3399
  );
3247
3400
  }
3248
- 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;
3401
+ 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;
3249
3402
  var NodeSubsystem2 = class {
3250
3403
  // ========================================================================
3251
3404
  constructor(postProcessPass, config) {
@@ -3267,6 +3420,7 @@ var NodeSubsystem2 = class {
3267
3420
  __privateAdd(this, _boxSelectEnd_graphSpace);
3268
3421
  __privateAdd(this, _boxSelectionNodes);
3269
3422
  __privateAdd(this, _boxSelectStyle);
3423
+ __privateAdd(this, _lastCtx);
3270
3424
  // LISTENERS ==============================================================
3271
3425
  __privateAdd(this, _nodeRemovedCallbacks);
3272
3426
  __privateAdd(this, _registeredNodeAddedCallbacks);
@@ -3288,6 +3442,7 @@ var NodeSubsystem2 = class {
3288
3442
  __privateSet(this, _boxSelectStart_graphSpace, Zero());
3289
3443
  __privateSet(this, _boxSelectEnd_graphSpace, Zero());
3290
3444
  __privateSet(this, _boxSelectionNodes, new List());
3445
+ __privateSet(this, _lastCtx, null);
3291
3446
  __privateSet(this, _boxSelectStyle, new BoxStyle({
3292
3447
  border: {
3293
3448
  color: Theme.BoxSelect.Color,
@@ -3320,6 +3475,29 @@ var NodeSubsystem2 = class {
3320
3475
  }
3321
3476
  clickStart(mousePosition, camera, ctrlKey) {
3322
3477
  __privateSet(this, _boxSelect, false);
3478
+ __privateGet(this, _nodesGrabbed).Clear();
3479
+ if (__privateGet(this, _lastCtx) !== null) {
3480
+ __privateSet(this, _portHovering, null);
3481
+ __privateSet(this, _widgetHovering, null);
3482
+ __privateSet(this, _nodeHovering, -1);
3483
+ for (let i = 0; i < __privateGet(this, _nodes).length; i++) {
3484
+ const intersection = __privateGet(this, _nodes)[i].inBounds(__privateGet(this, _lastCtx), camera, mousePosition);
3485
+ if (intersection.Node !== void 0 && intersection.PortIndex === void 0 && intersection.Widget === void 0) {
3486
+ __privateSet(this, _nodeHovering, i);
3487
+ }
3488
+ if (intersection.Widget !== void 0) {
3489
+ __privateSet(this, _widgetHovering, intersection.Widget);
3490
+ }
3491
+ if (intersection.Port !== void 0 && intersection.Node !== void 0 && intersection.PortIndex !== void 0 && intersection.PortIsInput !== void 0) {
3492
+ __privateSet(this, _portHovering, {
3493
+ Index: intersection.PortIndex,
3494
+ Node: intersection.Node,
3495
+ Port: intersection.Port,
3496
+ InputPort: intersection.PortIsInput
3497
+ });
3498
+ }
3499
+ }
3500
+ }
3323
3501
  let hoveringSomething = false;
3324
3502
  if (__privateGet(this, _nodeHovering) > -1) {
3325
3503
  __privateMethod(this, _NodeSubsystem_instances, selectNodeByIndex_fn).call(this, __privateGet(this, _nodeHovering), !ctrlKey);
@@ -3494,6 +3672,19 @@ var NodeSubsystem2 = class {
3494
3672
  getNodes() {
3495
3673
  return __privateGet(this, _nodes);
3496
3674
  }
3675
+ /**
3676
+ * Returns currently selected nodes in stable graph order (same selection
3677
+ * state used by Ctrl+click and box-select styling via FlowNode.selected()).
3678
+ */
3679
+ getSelectedNodes() {
3680
+ const selected = new Array();
3681
+ for (let i = 0; i < __privateGet(this, _nodes).length; i++) {
3682
+ if (__privateGet(this, _nodes)[i].selected()) {
3683
+ selected.push(__privateGet(this, _nodes)[i]);
3684
+ }
3685
+ }
3686
+ return selected;
3687
+ }
3497
3688
  /**
3498
3689
  * Returns all nodes who are connected to the inputs of the
3499
3690
  * node in question
@@ -3640,6 +3831,7 @@ var NodeSubsystem2 = class {
3640
3831
  return config;
3641
3832
  }
3642
3833
  render(ctx, camera, mousePosition) {
3834
+ __privateSet(this, _lastCtx, ctx);
3643
3835
  __privateSet(this, _cursor, "default" /* Default */);
3644
3836
  TimeExecution("Render_Connections", () => {
3645
3837
  __privateMethod(this, _NodeSubsystem_instances, renderConnections_fn).call(this, ctx, camera, mousePosition);
@@ -3673,6 +3865,7 @@ _boxSelectStart_graphSpace = new WeakMap();
3673
3865
  _boxSelectEnd_graphSpace = new WeakMap();
3674
3866
  _boxSelectionNodes = new WeakMap();
3675
3867
  _boxSelectStyle = new WeakMap();
3868
+ _lastCtx = new WeakMap();
3676
3869
  _nodeRemovedCallbacks = new WeakMap();
3677
3870
  _registeredNodeAddedCallbacks = new WeakMap();
3678
3871
  _NodeSubsystem_instances = new WeakSet();
@@ -4329,42 +4522,44 @@ var FlowNode = class {
4329
4522
  // }
4330
4523
  calculateBounds(ctx, camera) {
4331
4524
  const tempMeasurement = Zero();
4332
- const doublePadding = __privateGet(this, _padding2) * 2;
4525
+ const zoom = camera.zoom;
4526
+ const scaledPadding = __privateGet(this, _padding2) * zoom;
4527
+ const doubleScaledPadding = scaledPadding * 2;
4528
+ const scaledElementSpacing = __privateGet(this, _elementSpacing) * zoom;
4333
4529
  const screenSpacePosition = Zero();
4334
4530
  camera.graphSpaceToScreenSpace(__privateGet(this, _position), screenSpacePosition);
4335
4531
  const size = Zero();
4336
- __privateGet(this, _title2).size(ctx, 1, size);
4532
+ __privateGet(this, _title2).size(ctx, zoom, size);
4337
4533
  const subtitleSize = Zero();
4338
- __privateGet(this, _subTitle).size(ctx, 1, subtitleSize);
4534
+ __privateGet(this, _subTitle).size(ctx, zoom, subtitleSize);
4339
4535
  size.x = Math.max(size.x, subtitleSize.x);
4340
4536
  if (__privateGet(this, _infoText) !== "") {
4341
4537
  size.x += size.y * 4;
4342
4538
  }
4343
- size.x += doublePadding;
4344
- size.y += doublePadding + __privateGet(this, _elementSpacing) * __privateGet(this, _input).length;
4539
+ size.x += doubleScaledPadding;
4540
+ size.y += doubleScaledPadding + scaledElementSpacing * __privateGet(this, _input).length;
4345
4541
  for (let i = 0; i < __privateGet(this, _input).length; i++) {
4346
4542
  const port = __privateGet(this, _input)[i];
4347
- __privateGet(this, _portTextStyle).measure(ctx, 1, port.getDisplayName(), tempMeasurement);
4543
+ __privateGet(this, _portTextStyle).measure(ctx, zoom, port.getDisplayName(), tempMeasurement);
4348
4544
  size.y += tempMeasurement.y;
4349
- size.x = Math.max(size.x, tempMeasurement.x + doublePadding);
4545
+ size.x = Math.max(size.x, tempMeasurement.x + doubleScaledPadding);
4350
4546
  }
4351
- size.y += __privateGet(this, _elementSpacing) * __privateGet(this, _output).length;
4547
+ size.y += scaledElementSpacing * __privateGet(this, _output).length;
4352
4548
  for (let i = 0; i < __privateGet(this, _output).length; i++) {
4353
4549
  const port = __privateGet(this, _output)[i];
4354
- __privateGet(this, _portTextStyle).measure(ctx, 1, port.getDisplayName(), tempMeasurement);
4550
+ __privateGet(this, _portTextStyle).measure(ctx, zoom, port.getDisplayName(), tempMeasurement);
4355
4551
  size.y += tempMeasurement.y;
4356
- size.x = Math.max(size.x, tempMeasurement.x + doublePadding);
4552
+ size.x = Math.max(size.x, tempMeasurement.x + doubleScaledPadding);
4357
4553
  }
4358
- size.y += __privateGet(this, _elementSpacing) * __privateGet(this, _widgets).length;
4554
+ size.y += scaledElementSpacing * __privateGet(this, _widgets).length;
4359
4555
  for (let i = 0; i < __privateGet(this, _widgets).length; i++) {
4360
4556
  const element = __privateGet(this, _widgets)[i];
4361
4557
  const eleSize = element.Size();
4362
- size.y += eleSize.y;
4363
- size.x = Math.max(size.x, eleSize.x + doublePadding);
4558
+ size.y += eleSize.y * zoom;
4559
+ size.x = Math.max(size.x, eleSize.x * zoom + doubleScaledPadding);
4364
4560
  }
4365
- size.y += __privateGet(this, _elementSpacing);
4366
- size.x = Math.max(size.x, MINIMUM_NODE_WIDTH);
4367
- ScaleVector(size, camera.zoom);
4561
+ size.y += scaledElementSpacing;
4562
+ size.x = Math.max(size.x, MINIMUM_NODE_WIDTH * zoom);
4368
4563
  return {
4369
4564
  Position: screenSpacePosition,
4370
4565
  Size: size
@@ -6324,9 +6519,9 @@ var NodeFlowGraph = class {
6324
6519
  __privateSet(this, _contextMenuConfig, CombineContextMenus({
6325
6520
  items: [
6326
6521
  {
6327
- name: "Reset View",
6522
+ name: "Center on Graph",
6328
6523
  group: contextMenuGroup,
6329
- callback: __privateGet(this, _camera).reset.bind(__privateGet(this, _camera))
6524
+ callback: this.centerOnGraph.bind(this)
6330
6525
  }
6331
6526
  ]
6332
6527
  }, config == null ? void 0 : config.contextMenu));
@@ -6346,21 +6541,19 @@ var NodeFlowGraph = class {
6346
6541
  __privateSet(this, _backgroundRenderer, BuildBackgroundRenderer(backgroundColor));
6347
6542
  }
6348
6543
  window.requestAnimationFrame(__privateMethod(this, _NodeFlowGraph_instances, render_fn).bind(this));
6349
- __privateGet(this, _canvas).addEventListener("wheel", (event) => {
6350
- event.preventDefault();
6351
- this.zoom(Math.sign(event.deltaY));
6352
- }, false);
6353
6544
  new MouseObserver(
6354
6545
  __privateGet(this, _canvas),
6355
6546
  __privateMethod(this, _NodeFlowGraph_instances, mouseDragEvent_fn).bind(this),
6356
- // Mouse move event
6357
6547
  (mousePosition) => {
6358
6548
  __privateSet(this, _mousePosition, mousePosition);
6359
6549
  },
6360
6550
  __privateMethod(this, _NodeFlowGraph_instances, clickStart_fn).bind(this),
6361
6551
  __privateMethod(this, _NodeFlowGraph_instances, clickEnd_fn).bind(this),
6362
6552
  __privateMethod(this, _NodeFlowGraph_instances, openContextMenu_fn).bind(this),
6363
- __privateMethod(this, _NodeFlowGraph_instances, fileDrop_fn).bind(this)
6553
+ __privateMethod(this, _NodeFlowGraph_instances, fileDrop_fn).bind(this),
6554
+ (amount, anchor) => {
6555
+ this.zoom(amount, anchor);
6556
+ }
6364
6557
  );
6365
6558
  document.addEventListener(
6366
6559
  "keydown",
@@ -6411,17 +6604,20 @@ var NodeFlowGraph = class {
6411
6604
  addNoteDragStopListener(callback) {
6412
6605
  __privateGet(this, _mainNoteSubsystem).addNoteDragStopListener(callback);
6413
6606
  }
6414
- zoom(amount) {
6607
+ zoom(amount, anchor) {
6608
+ const anchorPos = anchor != null ? anchor : __privateGet(this, _mousePosition);
6415
6609
  let oldPos = void 0;
6416
- if (__privateGet(this, _mousePosition)) {
6417
- oldPos = __privateMethod(this, _NodeFlowGraph_instances, sceenPositionToGraphPosition_fn).call(this, __privateGet(this, _mousePosition));
6418
- ;
6610
+ if (anchorPos !== void 0) {
6611
+ oldPos = __privateMethod(this, _NodeFlowGraph_instances, sceenPositionToGraphPosition_fn).call(this, anchorPos);
6419
6612
  }
6420
6613
  __privateGet(this, _camera).zoom += amount * __privateGet(this, _camera).zoom * 0.05;
6421
- if (!oldPos || !__privateGet(this, _mousePosition)) {
6614
+ if (!oldPos || anchorPos === void 0) {
6422
6615
  return;
6423
6616
  }
6424
- const newPos = __privateMethod(this, _NodeFlowGraph_instances, sceenPositionToGraphPosition_fn).call(this, __privateGet(this, _mousePosition));
6617
+ if (anchor !== void 0) {
6618
+ __privateSet(this, _mousePosition, anchor);
6619
+ }
6620
+ const newPos = __privateMethod(this, _NodeFlowGraph_instances, sceenPositionToGraphPosition_fn).call(this, anchorPos);
6425
6621
  __privateGet(this, _camera).position.x += (newPos.x - oldPos.x) * __privateGet(this, _camera).zoom;
6426
6622
  __privateGet(this, _camera).position.y += (newPos.y - oldPos.y) * __privateGet(this, _camera).zoom;
6427
6623
  }
@@ -6437,6 +6633,60 @@ var NodeFlowGraph = class {
6437
6633
  getNodes() {
6438
6634
  return __privateGet(this, _mainNodeSubsystem).getNodes();
6439
6635
  }
6636
+ /**
6637
+ * Returns currently selected nodes in stable graph order (same selection
6638
+ * state used by Ctrl+click and box-select styling via FlowNode.selected()).
6639
+ */
6640
+ getSelectedNodes() {
6641
+ return __privateGet(this, _mainNodeSubsystem).getSelectedNodes();
6642
+ }
6643
+ /**
6644
+ * Adjusts camera position and zoom so all nodes fit in view (~10% padding).
6645
+ * Falls back to camera.reset() when there are no nodes.
6646
+ */
6647
+ centerOnGraph() {
6648
+ const nodes = this.getNodes();
6649
+ if (nodes.length === 0) {
6650
+ __privateGet(this, _camera).reset();
6651
+ return;
6652
+ }
6653
+ const measureCamera = new Camera();
6654
+ let minX = Infinity;
6655
+ let minY = Infinity;
6656
+ let maxX = -Infinity;
6657
+ let maxY = -Infinity;
6658
+ for (let i = 0; i < nodes.length; i++) {
6659
+ const bounds = nodes[i].calculateBounds(__privateGet(this, _ctx), measureCamera);
6660
+ minX = Math.min(minX, bounds.Position.x);
6661
+ minY = Math.min(minY, bounds.Position.y);
6662
+ maxX = Math.max(maxX, bounds.Position.x + bounds.Size.x);
6663
+ maxY = Math.max(maxY, bounds.Position.y + bounds.Size.y);
6664
+ }
6665
+ let width2 = maxX - minX;
6666
+ let height2 = maxY - minY;
6667
+ if (width2 <= 0 || height2 <= 0) {
6668
+ __privateGet(this, _camera).reset();
6669
+ return;
6670
+ }
6671
+ const padX = width2 * 0.05;
6672
+ const padY = height2 * 0.05;
6673
+ minX -= padX;
6674
+ minY -= padY;
6675
+ width2 += padX * 2;
6676
+ height2 += padY * 2;
6677
+ const canvasWidth = __privateGet(this, _canvas).clientWidth;
6678
+ const canvasHeight = __privateGet(this, _canvas).clientHeight;
6679
+ if (canvasWidth <= 0 || canvasHeight <= 0) {
6680
+ __privateGet(this, _camera).reset();
6681
+ return;
6682
+ }
6683
+ const zoom = Math.min(canvasWidth / width2, canvasHeight / height2);
6684
+ const centerX = minX + width2 / 2;
6685
+ const centerY = minY + height2 / 2;
6686
+ __privateGet(this, _camera).zoom = zoom;
6687
+ __privateGet(this, _camera).position.x = canvasWidth / 2 - centerX * zoom;
6688
+ __privateGet(this, _camera).position.y = canvasHeight / 2 - centerY * zoom;
6689
+ }
6440
6690
  connectedInputsNodeReferences(nodeIndex) {
6441
6691
  return __privateGet(this, _mainNodeSubsystem).connectedInputsNodeReferencesByIndex(nodeIndex);
6442
6692
  }
@@ -6539,21 +6789,6 @@ openContextMenu_fn = function(position) {
6539
6789
  Position: contextMenuPosition
6540
6790
  });
6541
6791
  };
6542
- // Somethings wrong here. Needs more testing
6543
- // #fitView(): void {
6544
- // if (this.#nodes.length === 0) {
6545
- // return;
6546
- // }
6547
- // const curBox: Box = {
6548
- // Position: { x: 0, y: 0 },
6549
- // Size: { x: 0, y: 0 }
6550
- // };
6551
- // CopyBox(curBox, this.#nodes[0].calculateBounds(this.#ctx, this.#graphState.position, this.#graphState.scale));
6552
- // for (let i = 1; i < this.#nodes.length; i++) {
6553
- // ExpandBox(curBox, this.#nodes[i].calculateBounds(this.#ctx, this.#graphState.position, this.#graphState.scale));
6554
- // }
6555
- // CopyVector2(this.#graphState.position, curBox.Position);
6556
- // }
6557
6792
  clickEnd_fn = function() {
6558
6793
  this.currentView().clickEnd();
6559
6794
  };
@@ -6618,6 +6853,7 @@ renderQuickMenu_fn = function() {
6618
6853
  export {
6619
6854
  ButtonWidget,
6620
6855
  ColorWidget,
6856
+ ContextMenuItemState,
6621
6857
  FlowNode,
6622
6858
  FlowNote,
6623
6859
  GlobalWidgetFactory,