@foblex/flow 19.0.0 → 19.1.0

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.
@@ -4,7 +4,7 @@ import { TransformModelExtensions, PointExtensions, RectExtensions, GetIntersect
4
4
  import { __decorate } from 'tslib';
5
5
  import { FExecutionRegister, FMediator } from '@foblex/mediator';
6
6
  import { BrowserService, PlatformService, EOperationSystem } from '@foblex/platform';
7
- import { castToEnum, normalizeDomElementId, isClosestElementHasClass, flatMap, getOrCreateRootNodeForViewRef, deepCloneNode, disableDragInteractions, extendStyles, getDataAttrValueFromClosestElementWithClass } from '@foblex/utils';
7
+ import { castToEnum, normalizeDomElementId, isClosestElementHasClass, flatMap, getOrCreateRootNodeForViewRef, deepCloneNode, disableDragInteractions, extendStyles, getDataAttrValueFromClosestElementWithClass, generateGuid } from '@foblex/utils';
8
8
  import { DOCUMENT, CommonModule } from '@angular/common';
9
9
 
10
10
  const F_BACKGROUND_PATTERN = new InjectionToken('F_BACKGROUND_PATTERN');
@@ -26,6 +26,14 @@ class AddPatternToBackgroundRequest {
26
26
  class FIdRegistryBase {
27
27
  _items = [];
28
28
  _byId = new Map();
29
+ /**
30
+ * Removals are collected here and compacted out of `_items` in one pass on
31
+ * the next ordered read. A large teardown is O(n) total instead of the
32
+ * O(n^2) that per-removal indexOf+splice cost; `_byId` reflects removals
33
+ * immediately, so id lookups never see removed instances.
34
+ */
35
+ _pendingRemovals = new Set();
36
+ _isCompactionScheduled = false;
29
37
  get(id) {
30
38
  return this._byId.get(id);
31
39
  }
@@ -40,10 +48,11 @@ class FIdRegistryBase {
40
48
  return this._byId.has(id);
41
49
  }
42
50
  getAll() {
51
+ this._compact();
43
52
  return this._items;
44
53
  }
45
54
  size() {
46
- return this._items.length;
55
+ return this._byId.size;
47
56
  }
48
57
  /**
49
58
  * Adds an instance.
@@ -54,6 +63,11 @@ class FIdRegistryBase {
54
63
  if (this._byId.has(id)) {
55
64
  throw new Error(`${this.kind} already exists: ${id}`);
56
65
  }
66
+ // Re-adding an instance whose removal is still pending would leave two
67
+ // copies in the ordered list; settle the pending removal first.
68
+ if (this._pendingRemovals.has(instance)) {
69
+ this._compact();
70
+ }
57
71
  this._items.push(instance);
58
72
  this._byId.set(id, instance);
59
73
  }
@@ -75,10 +89,8 @@ class FIdRegistryBase {
75
89
  // Defensive: if another instance with same id is in registry (shouldn't happen),
76
90
  // we remove by id anyway.
77
91
  this._byId.delete(id);
78
- const index = this._items.indexOf(existing);
79
- if (index >= 0) {
80
- this._items.splice(index, 1);
81
- }
92
+ this._pendingRemovals.add(existing);
93
+ this._scheduleCompaction();
82
94
  return true;
83
95
  }
84
96
  /**
@@ -91,10 +103,8 @@ class FIdRegistryBase {
91
103
  return undefined;
92
104
  }
93
105
  this._byId.delete(id);
94
- const index = this._items.indexOf(existing);
95
- if (index >= 0) {
96
- this._items.splice(index, 1);
97
- }
106
+ this._pendingRemovals.add(existing);
107
+ this._scheduleCompaction();
98
108
  return existing;
99
109
  }
100
110
  /**
@@ -103,6 +113,32 @@ class FIdRegistryBase {
103
113
  clear() {
104
114
  this._items.length = 0;
105
115
  this._byId.clear();
116
+ this._pendingRemovals.clear();
117
+ }
118
+ /** Compacts in place so `getAll()` keeps one array identity across reads. */
119
+ _compact() {
120
+ if (!this._pendingRemovals.size) {
121
+ return;
122
+ }
123
+ let writeIndex = 0;
124
+ for (const item of this._items) {
125
+ if (!this._pendingRemovals.has(item)) {
126
+ this._items[writeIndex++] = item;
127
+ }
128
+ }
129
+ this._items.length = writeIndex;
130
+ this._pendingRemovals.clear();
131
+ }
132
+ /** Settles a removal batch before coalesced registry notifications run. */
133
+ _scheduleCompaction() {
134
+ if (this._isCompactionScheduled) {
135
+ return;
136
+ }
137
+ this._isCompactionScheduled = true;
138
+ queueMicrotask(() => {
139
+ this._isCompactionScheduled = false;
140
+ this._compact();
141
+ });
106
142
  }
107
143
  }
108
144
 
@@ -482,13 +518,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
482
518
  }] });
483
519
 
484
520
  class EmitConnectionsChangesRequest {
521
+ dirtyNodeId;
485
522
  static fToken = Symbol('EmitConnectionsChangesRequest');
523
+ /**
524
+ * When set, only connections touching this node need a redraw; omitted
525
+ * means "redraw everything" — the safe default every caller keeps unless
526
+ * it knows the change is local to one node.
527
+ */
528
+ constructor(dirtyNodeId) {
529
+ this.dirtyNodeId = dirtyNodeId;
530
+ }
486
531
  }
487
532
 
488
533
  let EmitConnectionsChanges = class EmitConnectionsChanges {
489
534
  _store = inject(FComponentsStore);
490
- handle(_) {
491
- this._store.emitConnectionChanges();
535
+ handle({ dirtyNodeId }) {
536
+ this._store.emitConnectionChanges(dirtyNodeId);
492
537
  }
493
538
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: EmitConnectionsChanges, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
494
539
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: EmitConnectionsChanges });
@@ -557,13 +602,54 @@ class FComponentsStore {
557
602
  connectors = new FConnectorRegistry('Connector');
558
603
  instances = new FSingleRegistryBase();
559
604
  fDraggable;
605
+ _isNodesNotifyScheduled = false;
606
+ _isConnectionsNotifyScheduled = false;
607
+ /**
608
+ * Change notifications are coalesced to one per microtask: mounting a node
609
+ * with K connectors used to fire K+1 synchronous notifications, each running
610
+ * every listener (semantics rebuild, layout, minimap) — O(N^2) work across
611
+ * an N-node initial render. Revisions still increment synchronously, so code
612
+ * comparing revisions never observes stale values.
613
+ */
560
614
  emitNodeChanges() {
561
615
  this._nodesRevision++;
562
- this.nodesChanges$.notify();
616
+ if (this._isNodesNotifyScheduled) {
617
+ return;
618
+ }
619
+ this._isNodesNotifyScheduled = true;
620
+ queueMicrotask(() => {
621
+ this._isNodesNotifyScheduled = false;
622
+ this.nodesChanges$.notify();
623
+ });
563
624
  }
564
- emitConnectionChanges() {
625
+ /**
626
+ * Node ids whose connections need a redraw; `null` means "everything".
627
+ * Only the single-node resize/state path narrows the scope — every other
628
+ * emitter keeps today's full-redraw semantics.
629
+ */
630
+ _dirtyConnectionNodeIds = null;
631
+ emitConnectionChanges(dirtyNodeId) {
632
+ if (dirtyNodeId === undefined) {
633
+ this._dirtyConnectionNodeIds = null;
634
+ }
635
+ else {
636
+ this._dirtyConnectionNodeIds?.add(dirtyNodeId);
637
+ }
565
638
  this._connectionsRevision++;
566
- this.connectionsChanges$.notify();
639
+ if (this._isConnectionsNotifyScheduled) {
640
+ return;
641
+ }
642
+ this._isConnectionsNotifyScheduled = true;
643
+ queueMicrotask(() => {
644
+ this._isConnectionsNotifyScheduled = false;
645
+ this.connectionsChanges$.notify();
646
+ });
647
+ }
648
+ /** Returns the accumulated scope and starts collecting a fresh one. */
649
+ takeConnectionsDirtyScope() {
650
+ const scope = this._dirtyConnectionNodeIds;
651
+ this._dirtyConnectionNodeIds = new Set();
652
+ return scope;
567
653
  }
568
654
  completeConnectionsRender(revision, nodesRevision) {
569
655
  if (revision < this._connectionsRenderedRevision ||
@@ -813,10 +899,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
813
899
  class CenterGroupOrNodeRequest {
814
900
  id;
815
901
  animated;
902
+ emitCanvasChange;
816
903
  static fToken = Symbol('CenterGroupOrNodeRequest');
817
- constructor(id, animated) {
904
+ constructor(id, animated, emitCanvasChange = true) {
818
905
  this.id = id;
819
906
  this.animated = animated;
907
+ this.emitCanvasChange = emitCanvasChange;
820
908
  }
821
909
  }
822
910
 
@@ -829,13 +917,13 @@ let CenterGroupOrNode = class CenterGroupOrNode {
829
917
  get _transform() {
830
918
  return this._store.transform;
831
919
  }
832
- handle({ id, animated }) {
920
+ handle({ id, animated, emitCanvasChange }) {
833
921
  const node = this._store.nodes.get(id);
834
922
  if (!node) {
835
923
  return;
836
924
  }
837
925
  this._toCenter(this._getNodeRect(node), this._getFlowRect(), node._position);
838
- this._mediator.execute(new RedrawCanvasWithAnimationRequest(animated, ECanvasRedrawContext.VIEWPORT_ONLY));
926
+ this._mediator.execute(new RedrawCanvasWithAnimationRequest(animated, ECanvasRedrawContext.VIEWPORT_ONLY, emitCanvasChange));
839
927
  }
840
928
  _toCenter(fNodeRect, fFlowRect, position) {
841
929
  this._transform.scaledPosition = PointExtensions.initialize();
@@ -860,10 +948,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
860
948
  class FitToFlowRequest {
861
949
  toCenter;
862
950
  animated;
951
+ emitCanvasChange;
863
952
  static fToken = Symbol('FitToFlowRequest');
864
- constructor(toCenter, animated) {
953
+ constructor(toCenter, animated, emitCanvasChange = true) {
865
954
  this.toCenter = toCenter;
866
955
  this.animated = animated;
956
+ this.emitCanvasChange = emitCanvasChange;
867
957
  }
868
958
  }
869
959
 
@@ -876,14 +966,14 @@ let FitToFlow = class FitToFlow {
876
966
  return this._store.transform;
877
967
  }
878
968
  _mediator = inject(FMediator);
879
- handle({ toCenter, animated }) {
969
+ handle({ toCenter, animated, emitCanvasChange }) {
880
970
  const fNodesRect = this._mediator.execute(new CalculateNodesBoundingBoxRequest()) ||
881
971
  RectExtensions.initialize();
882
972
  if (fNodesRect.width === 0 || fNodesRect.height === 0) {
883
973
  return;
884
974
  }
885
975
  this.fitToParent(fNodesRect, RectExtensions.fromElement(this._store.flowHost), this._store.nodes.getAll().map((x) => x._position), toCenter);
886
- this._mediator.execute(new RedrawCanvasWithAnimationRequest(animated, ECanvasRedrawContext.VIEWPORT_ONLY));
976
+ this._mediator.execute(new RedrawCanvasWithAnimationRequest(animated, ECanvasRedrawContext.VIEWPORT_ONLY, emitCanvasChange));
887
977
  }
888
978
  fitToParent(rect, parentRect, points, toCenter) {
889
979
  this._transform.scaledPosition = PointExtensions.initialize();
@@ -996,21 +1086,63 @@ var ECanvasRedrawContext;
996
1086
  class RedrawCanvasWithAnimationRequest {
997
1087
  animated;
998
1088
  context;
1089
+ emitCanvasChange;
999
1090
  static fToken = Symbol('RedrawCanvasWithAnimationRequest');
1000
- constructor(animated, context = ECanvasRedrawContext.WITH_CONNECTION_CHANGES) {
1091
+ constructor(animated, context = ECanvasRedrawContext.WITH_CONNECTION_CHANGES, emitCanvasChange = true) {
1001
1092
  this.animated = animated;
1002
1093
  this.context = context;
1094
+ this.emitCanvasChange = emitCanvasChange;
1003
1095
  }
1004
1096
  }
1005
1097
 
1098
+ const TRANSITION_END_GRACE_MS = 50;
1006
1099
  function transitionEnd(element, callback) {
1007
- const onTransitionEnd = (event) => {
1008
- if (event.propertyName === 'transform') {
1009
- element.removeEventListener('transitionend', onTransitionEnd);
1010
- callback(event);
1100
+ let completed = false;
1101
+ let fallbackTimer = null;
1102
+ const complete = () => {
1103
+ if (completed) {
1104
+ return;
1105
+ }
1106
+ completed = true;
1107
+ element.removeEventListener('transitionend', onTransitionFinished);
1108
+ element.removeEventListener('transitioncancel', onTransitionFinished);
1109
+ if (fallbackTimer !== null) {
1110
+ clearTimeout(fallbackTimer);
1111
+ }
1112
+ callback();
1113
+ };
1114
+ const onTransitionFinished = (event) => {
1115
+ if (event.target === element && event.propertyName === 'transform') {
1116
+ complete();
1011
1117
  }
1012
1118
  };
1013
- element.addEventListener('transitionend', onTransitionEnd);
1119
+ element.addEventListener('transitionend', onTransitionFinished);
1120
+ element.addEventListener('transitioncancel', onTransitionFinished);
1121
+ fallbackTimer = setTimeout(complete, _transitionTimeout(element) + TRANSITION_END_GRACE_MS);
1122
+ }
1123
+ function _transitionTimeout(element) {
1124
+ const view = element.ownerDocument.defaultView;
1125
+ if (!view) {
1126
+ return 0;
1127
+ }
1128
+ const styles = view.getComputedStyle(element);
1129
+ const durations = _transitionTimes(styles.transitionDuration);
1130
+ const delays = _transitionTimes(styles.transitionDelay);
1131
+ const count = Math.max(durations.length, delays.length);
1132
+ let result = 0;
1133
+ for (let index = 0; index < count; index++) {
1134
+ result = Math.max(result, durations[index % durations.length] + delays[index % delays.length]);
1135
+ }
1136
+ return result;
1137
+ }
1138
+ function _transitionTimes(value) {
1139
+ const times = value.split(',').map((part) => {
1140
+ const time = part.trim();
1141
+ const multiplier = time.endsWith('ms') ? 1 : 1000;
1142
+ const parsed = Number.parseFloat(time);
1143
+ return Number.isFinite(parsed) ? parsed * multiplier : 0;
1144
+ });
1145
+ return times.length ? times : [0];
1014
1146
  }
1015
1147
 
1016
1148
  /**
@@ -1025,9 +1157,16 @@ let RedrawCanvasWithAnimation = class RedrawCanvasWithAnimation {
1025
1157
  }
1026
1158
  handle(request) {
1027
1159
  request.animated ? this._redrawWithAnimation(request.context) : this._redraw(request.context);
1028
- this._canvas?.emitCanvasChangeEvent();
1160
+ if (request.emitCanvasChange) {
1161
+ this._canvas?.emitCanvasChangeEvent();
1162
+ }
1029
1163
  }
1030
1164
  _redrawWithAnimation(context) {
1165
+ const targetTransform = TransformModelExtensions.toString(this._canvas.transform);
1166
+ if (this._canvas.hostElement.style.transform === targetTransform) {
1167
+ this._redraw(context);
1168
+ return;
1169
+ }
1031
1170
  this._store.beginViewportAnimation();
1032
1171
  this._canvas?.redrawWithAnimation();
1033
1172
  transitionEnd(this._canvas.hostElement, () => {
@@ -1103,9 +1242,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
1103
1242
 
1104
1243
  class ResetScaleAndCenterRequest {
1105
1244
  animated;
1245
+ emitCanvasChange;
1106
1246
  static fToken = Symbol('ResetScaleAndCenterRequest');
1107
- constructor(animated) {
1247
+ constructor(animated, emitCanvasChange = true) {
1108
1248
  this.animated = animated;
1249
+ this.emitCanvasChange = emitCanvasChange;
1109
1250
  }
1110
1251
  }
1111
1252
 
@@ -1118,14 +1259,14 @@ let ResetScaleAndCenter = class ResetScaleAndCenter {
1118
1259
  get _transform() {
1119
1260
  return this._store.transform;
1120
1261
  }
1121
- handle({ animated }) {
1262
+ handle({ animated, emitCanvasChange }) {
1122
1263
  const nodesRect = this._mediator.execute(new CalculateNodesBoundingBoxRequest()) ||
1123
1264
  RectExtensions.initialize();
1124
1265
  if (nodesRect.width === 0 || nodesRect.height === 0) {
1125
1266
  return;
1126
1267
  }
1127
1268
  this._oneToOneCentering(nodesRect, RectExtensions.fromElement(this._store.flowHost), this._store.nodes.getAll().map((x) => x._position));
1128
- this._mediator.execute(new RedrawCanvasWithAnimationRequest(animated, ECanvasRedrawContext.VIEWPORT_ONLY));
1269
+ this._mediator.execute(new RedrawCanvasWithAnimationRequest(animated, ECanvasRedrawContext.VIEWPORT_ONLY, emitCanvasChange));
1129
1270
  }
1130
1271
  _oneToOneCentering(rect, parentRect, points) {
1131
1272
  this._transform.scaledPosition = PointExtensions.initialize();
@@ -3526,8 +3667,16 @@ function createSVGElement$1(tag, fBrowser) {
3526
3667
 
3527
3668
  class ConnectionRedrawState {
3528
3669
  renderTicket = 0;
3670
+ /**
3671
+ * False while a (possibly sliced/worker-async) pass is still running. A
3672
+ * scoped redraw starting now would invalidate that pass mid-flight and leave
3673
+ * its remaining connections undrawn, so pending scopes escalate to a full
3674
+ * pass until the previous one completed.
3675
+ */
3676
+ isPassCompleted = true;
3529
3677
  _connectedInPreviousRender = new Set();
3530
3678
  beginRender() {
3679
+ this.isPassCompleted = false;
3531
3680
  return ++this.renderTicket;
3532
3681
  }
3533
3682
  resetConnectedConnectors() {
@@ -4462,27 +4611,48 @@ let GetNormalizedConnectorRect = class GetNormalizedConnectorRect {
4462
4611
  this._mediator.execute(new UpdateFCacheRectByElementRequest(element, rect));
4463
4612
  return rect;
4464
4613
  }
4614
+ /**
4615
+ * Border radii are read through getComputedStyle — by far the priciest part
4616
+ * of a connector measurement — yet they practically never change. They are
4617
+ * cached per element and re-read only after the resize signal every node's
4618
+ * ResizeObserver already bumps, which also covers font-size/percentage-based
4619
+ * radii (those can only change alongside a layout change).
4620
+ */
4621
+ _rawRadiiCache = new WeakMap();
4622
+ _radiiRevision = -1;
4465
4623
  _getElementRoundedRect(element) {
4466
- return this._getRoundedRect(RectExtensions.fromElement(element), element, this._getComputedStyle(element));
4467
- }
4468
- _getRoundedRect(rect, element, styles) {
4469
- const [radius1, radius2, radius3, radius4] = this._normalizeCircularBorderRadii(rect.width, rect.height, [
4470
- this._getSystemRadius(styles.borderTopLeftRadius, element, styles.fontSize),
4471
- this._getSystemRadius(styles.borderTopRightRadius, element, styles.fontSize),
4472
- this._getSystemRadius(styles.borderBottomRightRadius, element, styles.fontSize),
4473
- this._getSystemRadius(styles.borderBottomLeftRadius, element, styles.fontSize),
4474
- ]);
4624
+ return this._getRoundedRect(RectExtensions.fromElement(element), element);
4625
+ }
4626
+ _getRoundedRect(rect, element) {
4627
+ const { scale } = this._transform;
4628
+ const rawRadii = this._resolveRawRadii(element);
4629
+ const [radius1, radius2, radius3, radius4] = this._normalizeCircularBorderRadii(rect.width, rect.height, [rawRadii[0] * scale, rawRadii[1] * scale, rawRadii[2] * scale, rawRadii[3] * scale]);
4475
4630
  return new RoundedRect(rect.x, rect.y, rect.width, rect.height, radius1, radius2, radius3, radius4);
4476
4631
  }
4632
+ _resolveRawRadii(element) {
4633
+ if (this._radiiRevision !== this._store.connectionsRevision) {
4634
+ this._radiiRevision = this._store.connectionsRevision;
4635
+ this._rawRadiiCache = new WeakMap();
4636
+ }
4637
+ let radii = this._rawRadiiCache.get(element);
4638
+ if (!radii) {
4639
+ const styles = this._getComputedStyle(element);
4640
+ radii = [
4641
+ this._toPixels(styles.borderTopLeftRadius, element, styles.fontSize),
4642
+ this._toPixels(styles.borderTopRightRadius, element, styles.fontSize),
4643
+ this._toPixels(styles.borderBottomRightRadius, element, styles.fontSize),
4644
+ this._toPixels(styles.borderBottomLeftRadius, element, styles.fontSize),
4645
+ ];
4646
+ this._rawRadiiCache.set(element, radii);
4647
+ }
4648
+ return radii;
4649
+ }
4477
4650
  _getComputedStyle(element) {
4478
4651
  return this._browser.window.getComputedStyle(element);
4479
4652
  }
4480
4653
  _toPixels(value, element, fontSize) {
4481
4654
  return this._browser.toPixels(value, element.clientWidth, element.clientHeight, fontSize) || 0;
4482
4655
  }
4483
- _getSystemRadius(value, element, fontSize) {
4484
- return this._toPixels(value, element, fontSize) * this._transform.scale;
4485
- }
4486
4656
  /**
4487
4657
  * Mirrors CSS border-radius normalization so oversized values like `999px`
4488
4658
  * collapse to the largest valid circular radii for the current rect.
@@ -4718,6 +4888,13 @@ class FNodeBase extends MIXIN_BASE {
4718
4888
  this.setStyle('width', '' + this._size.width + 'px');
4719
4889
  this.setStyle('height', '' + this._size.height + 'px');
4720
4890
  }
4891
+ else {
4892
+ // Size was cleared (e.g. an undo restoring an auto-fit node back to its
4893
+ // undefined, content-driven size) — drop the stale explicit dimensions
4894
+ // instead of leaving the last measured box frozen on the element.
4895
+ this.removeStyle('width');
4896
+ this.removeStyle('height');
4897
+ }
4721
4898
  this.setStyle('transform', `translate(${this._position.x}px,${this._position.y}px) rotate(${this._rotate}deg)`);
4722
4899
  }
4723
4900
  resetSize() {
@@ -4753,11 +4930,10 @@ class FNodeBase extends MIXIN_BASE {
4753
4930
  }
4754
4931
 
4755
4932
  let uniqueId$c = 0;
4756
- const _DEBOUNCE_TIME$1 = 3;
4757
4933
  class FGroupDirective extends FNodeBase {
4758
- _debounceTimer = null;
4759
4934
  _destroyRef = inject(DestroyRef);
4760
4935
  _mediator = inject(FMediator);
4936
+ _sidesScheduler = inject(ConnectableSidesScheduler);
4761
4937
  fId = input(`f-group-${uniqueId$c++}`, ...(ngDevMode ? [{ debugName: "fId", alias: 'fGroupId' }] : [{ alias: 'fGroupId' }]));
4762
4938
  fParentId = input(null, ...(ngDevMode ? [{ debugName: "fParentId", alias: 'fGroupParentId' }] : [{
4763
4939
  alias: 'fGroupParentId',
@@ -4823,13 +4999,7 @@ class FGroupDirective extends FNodeBase {
4823
4999
  if (!this.connectors.length) {
4824
5000
  return;
4825
5001
  }
4826
- if (this._debounceTimer) {
4827
- clearTimeout(this._debounceTimer);
4828
- }
4829
- this._debounceTimer = setTimeout(() => this._calculateNodeConnectorsConnectableSides(), _DEBOUNCE_TIME$1);
4830
- }
4831
- _calculateNodeConnectorsConnectableSides() {
4832
- this._mediator.execute(new CalculateConnectorsConnectableSidesRequest(this));
5002
+ this._sidesScheduler.schedule(this);
4833
5003
  }
4834
5004
  ngAfterViewInit() {
4835
5005
  if (!this.browser.isBrowser()) {
@@ -4867,11 +5037,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
4867
5037
  }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { fId: [{ type: i0.Input, args: [{ isSignal: true, alias: "fGroupId", required: false }] }], fParentId: [{ type: i0.Input, args: [{ isSignal: true, alias: "fGroupParentId", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "fGroupPosition", required: false }] }, { type: i0.Output, args: ["fGroupPositionChange"] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "fGroupSize", required: false }] }], sizeChange: [{ type: i0.Output, args: ["fGroupSizeChange"] }], rotate: [{ type: i0.Input, args: [{ isSignal: true, alias: "fGroupRotate", required: false }] }, { type: i0.Output, args: ["fGroupRotateChange"] }], fConnectOnNode: [{ type: i0.Input, args: [{ isSignal: true, alias: "fConnectOnNode", required: false }] }], fMinimapClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "fMinimapClass", required: false }] }], fDraggingDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "fGroupDraggingDisabled", required: false }] }], fSelectionDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "fGroupSelectionDisabled", required: false }] }], fIncludePadding: [{ type: i0.Input, args: [{ isSignal: true, alias: "fIncludePadding", required: false }] }], fAutoExpandOnChildHit: [{ type: i0.Input, args: [{ isSignal: true, alias: "fAutoExpandOnChildHit", required: false }] }], fAutoSizeToFitChildren: [{ type: i0.Input, args: [{ isSignal: true, alias: "fAutoSizeToFitChildren", required: false }] }] } });
4868
5038
 
4869
5039
  let uniqueId$b = 0;
4870
- const _DEBOUNCE_TIME = 3;
4871
5040
  class FNodeDirective extends FNodeBase {
4872
- _debounceTimer = null;
4873
5041
  _destroyRef = inject(DestroyRef);
4874
5042
  _mediator = inject(FMediator);
5043
+ _sidesScheduler = inject(ConnectableSidesScheduler);
4875
5044
  fId = input(`f-node-${uniqueId$b++}`, ...(ngDevMode ? [{ debugName: "fId", alias: 'fNodeId',
4876
5045
  transform: (value) => stringAttribute(value) || `f-node-${uniqueId$b++}` }] : [{
4877
5046
  alias: 'fNodeId',
@@ -4941,13 +5110,7 @@ class FNodeDirective extends FNodeBase {
4941
5110
  if (!this.connectors.length) {
4942
5111
  return;
4943
5112
  }
4944
- if (this._debounceTimer) {
4945
- clearTimeout(this._debounceTimer);
4946
- }
4947
- this._debounceTimer = setTimeout(() => this._calculateNodeConnectorsConnectableSides(), _DEBOUNCE_TIME);
4948
- }
4949
- _calculateNodeConnectorsConnectableSides() {
4950
- this._mediator.execute(new CalculateConnectorsConnectableSidesRequest(this));
5113
+ this._sidesScheduler.schedule(this);
4951
5114
  }
4952
5115
  ngAfterViewInit() {
4953
5116
  if (!this.browser.isBrowser()) {
@@ -4984,6 +5147,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
4984
5147
  }]
4985
5148
  }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { fId: [{ type: i0.Input, args: [{ isSignal: true, alias: "fNodeId", required: false }] }], fParentId: [{ type: i0.Input, args: [{ isSignal: true, alias: "fNodeParentId", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "fNodePosition", required: false }] }, { type: i0.Output, args: ["fNodePositionChange"] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "fNodeSize", required: false }] }], sizeChange: [{ type: i0.Output, args: ["fNodeSizeChange"] }], rotate: [{ type: i0.Input, args: [{ isSignal: true, alias: "fNodeRotate", required: false }] }, { type: i0.Output, args: ["fNodeRotateChange"] }], fConnectOnNode: [{ type: i0.Input, args: [{ isSignal: true, alias: "fConnectOnNode", required: false }] }], fMinimapClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "fMinimapClass", required: false }] }], fDraggingDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "fNodeDraggingDisabled", required: false }] }], fSelectionDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "fNodeSelectionDisabled", required: false }] }], fIncludePadding: [{ type: i0.Input, args: [{ isSignal: true, alias: "fIncludePadding", required: false }] }], fAutoExpandOnChildHit: [{ type: i0.Input, args: [{ isSignal: true, alias: "fAutoExpandOnChildHit", required: false }] }], fAutoSizeToFitChildren: [{ type: i0.Input, args: [{ isSignal: true, alias: "fAutoSizeToFitChildren", required: false }] }] } });
4986
5149
 
5150
+ const NODE_OR_GROUP_HOST_SELECTOR = '[data-f-node-id], [data-f-group-id]';
5151
+ /**
5152
+ * Resolves the node or group whose host contains the given element in
5153
+ * O(DOM depth) via the host id attributes, instead of scanning every
5154
+ * registered node with `hostElement.contains` on each pointerdown.
5155
+ *
5156
+ * Node and group hosts are siblings inside their layer containers, so an
5157
+ * element belongs to at most one host; the instance check keeps the lookup
5158
+ * correct when several flows share the page and reuse ids.
5159
+ */
5160
+ function findNodeOrGroupContaining(store, element) {
5161
+ const host = element.closest(NODE_OR_GROUP_HOST_SELECTOR);
5162
+ if (!host) {
5163
+ return undefined;
5164
+ }
5165
+ const id = host.getAttribute('data-f-node-id') ?? host.getAttribute('data-f-group-id');
5166
+ if (id === null) {
5167
+ return undefined;
5168
+ }
5169
+ const node = store.nodes.get(id);
5170
+ return node?.hostElement === host ? node : undefined;
5171
+ }
5172
+
4987
5173
  function isNode(element) {
4988
5174
  return !!element.closest('[fNode]');
4989
5175
  }
@@ -5031,7 +5217,11 @@ class FConnectorBase {
5031
5217
  }
5032
5218
  setConnected(toConnector) {
5033
5219
  this._isConnected = true;
5034
- this.toConnector.push(toConnector);
5220
+ // Idempotent so scoped connection redraws can re-mark endpoints without
5221
+ // resetting the whole graph's connected state first.
5222
+ if (!this.toConnector.includes(toConnector)) {
5223
+ this.toConnector.push(toConnector);
5224
+ }
5035
5225
  }
5036
5226
  resetConnected() {
5037
5227
  this._isConnected = false;
@@ -5960,10 +6150,12 @@ class CompleteConnectionRedrawRequest {
5960
6150
  let CompleteConnectionRedraw = class CompleteConnectionRedraw {
5961
6151
  _mediator = inject(FMediator);
5962
6152
  _store = inject(FComponentsStore);
6153
+ _state = inject(ConnectionRedrawState);
5963
6154
  handle({ session }) {
5964
6155
  if (!this._mediator.execute(new IsConnectionRedrawCurrentRequest(session))) {
5965
6156
  return;
5966
6157
  }
6158
+ this._state.isPassCompleted = true;
5967
6159
  this._store.completeConnectionsRender(session.connectionsRevision, session.nodesRevision);
5968
6160
  }
5969
6161
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: CompleteConnectionRedraw, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
@@ -6104,14 +6296,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
6104
6296
  }] });
6105
6297
 
6106
6298
  class StartConnectionRedrawRequest {
6299
+ resetConnectedState;
6107
6300
  static fToken = Symbol('StartConnectionRedrawRequest');
6301
+ /**
6302
+ * Scoped passes keep the connected state of untouched connections intact,
6303
+ * so they must not reset the whole graph's connected connectors.
6304
+ */
6305
+ constructor(resetConnectedState = true) {
6306
+ this.resetConnectedState = resetConnectedState;
6307
+ }
6108
6308
  }
6109
6309
 
6110
6310
  let StartConnectionRedraw = class StartConnectionRedraw {
6111
6311
  _store = inject(FComponentsStore);
6112
6312
  _state = inject(ConnectionRedrawState);
6113
- handle(_) {
6114
- this._state.resetConnectedConnectors();
6313
+ handle({ resetConnectedState }) {
6314
+ if (resetConnectedState) {
6315
+ this._state.resetConnectedConnectors();
6316
+ }
6115
6317
  return {
6116
6318
  renderTicket: this._state.beginRender(),
6117
6319
  connectionsRevision: this._store.connectionsRevision,
@@ -6579,11 +6781,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
6579
6781
  let RedrawConnections = class RedrawConnections {
6580
6782
  _mediator = inject(FMediator);
6581
6783
  _store = inject(FComponentsStore);
6784
+ _state = inject(ConnectionRedrawState);
6582
6785
  handle(_) {
6583
- const session = this._mediator.execute(new StartConnectionRedrawRequest());
6786
+ const scope = this._resolveScope();
6787
+ const session = this._mediator.execute(new StartConnectionRedrawRequest(scope === null));
6584
6788
  this._createMarkersForCreate();
6585
6789
  this._createMarkersForSnap();
6586
- const connections = [...this._store.connections.getAll()];
6790
+ const connections = scope === null ? [...this._store.connections.getAll()] : this._connectionsTouching(scope);
6587
6791
  const connectorRectCache = new Map();
6588
6792
  if (!connections.length) {
6589
6793
  this._mediator.execute(new CompleteConnectionRedrawRequest(session));
@@ -6596,6 +6800,64 @@ let RedrawConnections = class RedrawConnections {
6596
6800
  this._redrawWithoutWorker(connections, connectorRectCache, session);
6597
6801
  }
6598
6802
  }
6803
+ /**
6804
+ * A pass narrowed to the nodes whose geometry actually changed (single-node
6805
+ * resizes/state changes); `null` = redraw everything. Escalates to a full
6806
+ * pass while a previous pass is still in flight, because starting a new
6807
+ * session aborts the running one mid-slice.
6808
+ */
6809
+ _resolveScope() {
6810
+ const scope = this._store.takeConnectionsDirtyScope();
6811
+ if (scope === null || !this._state.isPassCompleted) {
6812
+ return null;
6813
+ }
6814
+ return scope;
6815
+ }
6816
+ _connectionsTouching(nodeIds) {
6817
+ if (!nodeIds.size) {
6818
+ return [];
6819
+ }
6820
+ const hierarchyDirtyCache = new Map();
6821
+ return this._store.connections.getAll().filter((connection) => {
6822
+ const source = findSourceConnector(this._store, connection.sourceId());
6823
+ const target = findTargetConnector(this._store, connection.targetId());
6824
+ // Unresolved endpoints keep full-pass behavior for this connection.
6825
+ if (!source || !target) {
6826
+ return true;
6827
+ }
6828
+ return (this._isNodeHierarchyDirty(source.fNodeId, nodeIds, hierarchyDirtyCache) ||
6829
+ this._isNodeHierarchyDirty(target.fNodeId, nodeIds, hierarchyDirtyCache));
6830
+ });
6831
+ }
6832
+ /** A group geometry change also moves every endpoint owned by its descendants. */
6833
+ _isNodeHierarchyDirty(nodeId, dirtyNodeIds, cache) {
6834
+ const cached = cache.get(nodeId);
6835
+ if (cached !== undefined) {
6836
+ return cached;
6837
+ }
6838
+ const path = [];
6839
+ const visited = new Set();
6840
+ let currentId = nodeId;
6841
+ let isDirty = false;
6842
+ while (currentId && !visited.has(currentId)) {
6843
+ const currentCached = cache.get(currentId);
6844
+ if (currentCached !== undefined) {
6845
+ isDirty = currentCached;
6846
+ break;
6847
+ }
6848
+ path.push(currentId);
6849
+ visited.add(currentId);
6850
+ if (dirtyNodeIds.has(currentId)) {
6851
+ isDirty = true;
6852
+ break;
6853
+ }
6854
+ currentId = this._store.nodes.get(currentId)?.fParentId();
6855
+ }
6856
+ for (const id of path) {
6857
+ cache.set(id, isDirty);
6858
+ }
6859
+ return isDirty;
6860
+ }
6599
6861
  _createMarkersForCreate() {
6600
6862
  const instance = this._store.connections.getForCreate();
6601
6863
  if (instance) {
@@ -7332,14 +7594,31 @@ class DragCanvasFinalizeRequest {
7332
7594
  }
7333
7595
  }
7334
7596
 
7597
+ /** Returns `event.target`, falling back to its composed path only after Shadow DOM retargeting. */
7598
+ function getEventTargetElement(event, boundarySelector) {
7599
+ const target = event.target;
7600
+ const targetElement = target instanceof HTMLElement || target instanceof SVGElement ? target : null;
7601
+ if (targetElement && (!boundarySelector || targetElement.closest(boundarySelector))) {
7602
+ return targetElement;
7603
+ }
7604
+ const path = typeof event.composedPath === 'function' ? event.composedPath() : [];
7605
+ for (const pathTarget of path) {
7606
+ if (pathTarget instanceof HTMLElement || pathTarget instanceof SVGElement) {
7607
+ if (!boundarySelector || pathTarget.closest(boundarySelector)) {
7608
+ return pathTarget;
7609
+ }
7610
+ }
7611
+ }
7612
+ return targetElement;
7613
+ }
7614
+
7335
7615
  class IPointerEvent {
7336
7616
  _event;
7337
- _target;
7338
7617
  get originalEvent() {
7339
7618
  return this._event;
7340
7619
  }
7341
7620
  get targetElement() {
7342
- return this._target || this.originalEvent.target;
7621
+ return this._target;
7343
7622
  }
7344
7623
  get touchEvent() {
7345
7624
  return this._event;
@@ -7347,9 +7626,12 @@ class IPointerEvent {
7347
7626
  get touches() {
7348
7627
  return this.touchEvent.touches;
7349
7628
  }
7350
- constructor(_event, _target) {
7629
+ _target;
7630
+ constructor(_event, target) {
7351
7631
  this._event = _event;
7352
- this._target = _target;
7632
+ // Drag preparation may run after dispatch, when composedPath() is already empty.
7633
+ this._target =
7634
+ target ?? getEventTargetElement(_event, 'f-flow, .f-external-item');
7353
7635
  }
7354
7636
  setTarget(target) {
7355
7637
  this._target = target;
@@ -8411,7 +8693,7 @@ let CreateConnectionPreparation = class CreateConnectionPreparation {
8411
8693
  }
8412
8694
  }
8413
8695
  _findOwnerNode(target) {
8414
- return this._store.nodes.getAll().find((n) => n.isContains(target));
8696
+ return findNodeOrGroupContaining(this._store, target);
8415
8697
  }
8416
8698
  _isValidConditions() {
8417
8699
  // A session armed by another gesture (e.g. click-to-connect) must not be
@@ -9514,6 +9796,12 @@ class DragNodeItemHandler extends DragHandlerBase {
9514
9796
  continue;
9515
9797
  }
9516
9798
  const soft = this._constraints.soft[i];
9799
+ // When the group also auto-sizes to its children, the post-drop fit
9800
+ // emits the settled size — skip this transient expanded rect so the
9801
+ // consumer sees one final `sizeChange` per drag, not expand-then-fit.
9802
+ if (soft.nodeOrGroup.fAutoSizeToFitChildren()) {
9803
+ continue;
9804
+ }
9517
9805
  const expandedRect = expandRectByOverflow(soft.boundingRect, r.overflow, r.edges);
9518
9806
  soft.nodeOrGroup.sizeChange.emit(expandedRect);
9519
9807
  }
@@ -11163,16 +11451,8 @@ let DragNodePreparation = class DragNodePreparation {
11163
11451
  return isClosestElementHasClass(element, '.f-drag-handle');
11164
11452
  }
11165
11453
  _findDraggableNode(target) {
11166
- const nodes = this._store.nodes.getAll();
11167
- for (const node of nodes) {
11168
- if (node.fDraggingDisabled()) {
11169
- continue;
11170
- }
11171
- if (node.isContains(target)) {
11172
- return node;
11173
- }
11174
- }
11175
- return undefined;
11454
+ const node = findNodeOrGroupContaining(this._store, target);
11455
+ return node && !node.fDraggingDisabled() ? node : undefined;
11176
11456
  }
11177
11457
  _storePointerDownContext(event) {
11178
11458
  this._dragSession.onPointerDownScale = this._store.transform.scale;
@@ -11541,6 +11821,33 @@ function isDragExternalItemHandler(value) {
11541
11821
  value.getEvent().fEventType === DRAG_EXTERNAL_ITEM_HANDLER_TYPE);
11542
11822
  }
11543
11823
 
11824
+ /**
11825
+ * Returns hit-test results across nested open shadow roots, ordered from the
11826
+ * deepest matching element to the outermost one.
11827
+ */
11828
+ function getDeepElementsFromPoint(root, x, y) {
11829
+ const result = [];
11830
+ const visitedElements = new Set();
11831
+ const visitedRoots = new Set();
11832
+ const collect = (currentRoot) => {
11833
+ if (visitedRoots.has(currentRoot)) {
11834
+ return;
11835
+ }
11836
+ visitedRoots.add(currentRoot);
11837
+ for (const element of currentRoot.elementsFromPoint(x, y)) {
11838
+ if (element.shadowRoot) {
11839
+ collect(element.shadowRoot);
11840
+ }
11841
+ if (!visitedElements.has(element)) {
11842
+ visitedElements.add(element);
11843
+ result.push(element);
11844
+ }
11845
+ }
11846
+ };
11847
+ collect(root);
11848
+ return result;
11849
+ }
11850
+
11544
11851
  let DragExternalItemFinalize = class DragExternalItemFinalize {
11545
11852
  _result = inject(FDragHandlerResult);
11546
11853
  _mediator = inject(FMediator);
@@ -11577,9 +11884,7 @@ let DragExternalItemFinalize = class DragExternalItemFinalize {
11577
11884
  return result;
11578
11885
  }
11579
11886
  _getElementsFromPoint(position) {
11580
- return this._browser.document
11581
- .elementsFromPoint(position.x, position.y)
11582
- .filter((x) => !x.closest('.f-external-item') && !x.closest('.f-external-item-preview'));
11887
+ return getDeepElementsFromPoint(this._browser.document, position.x, position.y).filter((x) => !x.closest('.f-external-item') && !x.closest('.f-external-item-preview'));
11583
11888
  }
11584
11889
  _emitEvent(elements, destinationNodeOrGroupId, eventPosition) {
11585
11890
  if (this._isPointerInCanvasRect(elements)) {
@@ -12096,7 +12401,17 @@ let DropToGroupPreparation = class DropToGroupPreparation {
12096
12401
  if (!this._canPrepare()) {
12097
12402
  return;
12098
12403
  }
12099
- const dragTargetNode = this._allNodes.find((n) => n.isContains(event.targetElement));
12404
+ // Drop-to-group can be switched off (`fDropToGroup` = false). We still
12405
+ // register the handler — the external-item finalize asks it for a target
12406
+ // container and throws if none exists — but with no candidates it never
12407
+ // activates a target, so nothing is reparented and no highlight appears.
12408
+ if (!this._isDropToGroupEnabled()) {
12409
+ const handler = this._dragInjector.get(DropToGroupHandler);
12410
+ handler.initialize([]);
12411
+ this._dragContext.draggableItems.push(handler);
12412
+ return;
12413
+ }
12414
+ const dragTargetNode = findNodeOrGroupContaining(this._store, event.targetElement);
12100
12415
  // If this is not an external drag and we can't resolve a target node — it's an invalid state.
12101
12416
  if (!dragTargetNode && !this._hasExternalDrag()) {
12102
12417
  throw new Error('Drag target node not found');
@@ -12114,6 +12429,9 @@ let DropToGroupPreparation = class DropToGroupPreparation {
12114
12429
  handler.initialize(targets);
12115
12430
  this._dragContext.draggableItems.push(handler);
12116
12431
  }
12432
+ _isDropToGroupEnabled() {
12433
+ return this._store.fDraggable?.dropToGroup() !== false;
12434
+ }
12117
12435
  _canPrepare() {
12118
12436
  return this._hasMoveDrag() || this._hasExternalDrag();
12119
12437
  }
@@ -14245,6 +14563,7 @@ var EFFlowFeatureKind;
14245
14563
  EFFlowFeatureKind["CONTROL_SCHEME"] = "control-scheme";
14246
14564
  EFFlowFeatureKind["CONNECTION_FLOW"] = "connection-flow";
14247
14565
  EFFlowFeatureKind["A11Y"] = "a11y";
14566
+ EFFlowFeatureKind["STATE"] = "state";
14248
14567
  })(EFFlowFeatureKind || (EFFlowFeatureKind = {}));
14249
14568
 
14250
14569
  function provideFFlow(configOrFeature, ...rest) {
@@ -14654,7 +14973,7 @@ let ResizeNodePreparation = class ResizeNodePreparation {
14654
14973
  return isClosestElementHasClass(target, '.f-resize-handle');
14655
14974
  }
14656
14975
  _findResizableNode(target) {
14657
- const nodeOrGroup = this._store.nodes.getAll().find((x) => x.isContains(target));
14976
+ const nodeOrGroup = findNodeOrGroupContaining(this._store, target);
14658
14977
  if (!nodeOrGroup) {
14659
14978
  return undefined;
14660
14979
  }
@@ -14874,15 +15193,8 @@ let RotateNodePreparation = class RotateNodePreparation {
14874
15193
  isValidEventTrigger(event.originalEvent, fTrigger));
14875
15194
  }
14876
15195
  _findRotatableNode(target) {
14877
- for (const node of this._store.nodes.getAll()) {
14878
- if (node.fDraggingDisabled()) {
14879
- continue;
14880
- }
14881
- if (node.isContains(target)) {
14882
- return node;
14883
- }
14884
- }
14885
- return undefined;
15196
+ const node = findNodeOrGroupContaining(this._store, target);
15197
+ return node && !node.fDraggingDisabled() ? node : undefined;
14886
15198
  }
14887
15199
  _selectBeforeRotate(node) {
14888
15200
  queueMicrotask(() => {
@@ -15330,7 +15642,7 @@ let DragCanvasPreparation = class DragCanvasPreparation {
15330
15642
  return this._store.flowHost.contains(targetElement) && !this._getNode(targetElement);
15331
15643
  }
15332
15644
  _getNode(targetElement) {
15333
- let result = this._store.nodes.getAll().find((x) => x.isContains(targetElement));
15645
+ let result = findNodeOrGroupContaining(this._store, targetElement);
15334
15646
  if (result && result.fDraggingDisabled()) {
15335
15647
  result = undefined;
15336
15648
  }
@@ -15433,7 +15745,7 @@ let SelectByPointer = class SelectByPointer {
15433
15745
  return this._findNodeOrGroupAt(target) ?? this._findConnectionAt(target);
15434
15746
  }
15435
15747
  _findNodeOrGroupAt(target) {
15436
- return this._store.nodes.getAll().find((x) => x.isContains(target));
15748
+ return findNodeOrGroupContaining(this._store, target);
15437
15749
  }
15438
15750
  _findConnectionAt(target) {
15439
15751
  return this._store.connections.getAll().find((x) => x.isContains(target));
@@ -15560,7 +15872,7 @@ const F_DEFAULT_CONTROL_SCHEME = {
15560
15872
  * while a left-drag on a node still moves it.
15561
15873
  */
15562
15874
  function isOnFlowBackground(event) {
15563
- const target = event.target;
15875
+ const target = getEventTargetElement(event, 'f-flow');
15564
15876
  return (!!target && !isNode(target) && !target.closest('[fGroup]') && !target.closest('.f-connection'));
15565
15877
  }
15566
15878
 
@@ -15728,7 +16040,10 @@ class FClickConnectFlow {
15728
16040
  if (traveled > CLICK_MOVE_TOLERANCE) {
15729
16041
  return;
15730
16042
  }
15731
- const target = event.target;
16043
+ const target = getEventTargetElement(event, 'f-flow');
16044
+ if (!target) {
16045
+ return;
16046
+ }
15732
16047
  if (!this._store.flowHost?.contains(target)) {
15733
16048
  return;
15734
16049
  }
@@ -15778,10 +16093,11 @@ class FClickConnectFlow {
15778
16093
  return;
15779
16094
  }
15780
16095
  // Clicking another source connector re-arms from it; anything else cancels.
15781
- const nextSource = this._resolveSource(event.target);
16096
+ const target = getEventTargetElement(event, 'f-flow');
16097
+ const nextSource = target ? this._resolveSource(target) : undefined;
15782
16098
  this._cancel();
15783
- if (nextSource) {
15784
- this._arm(event, event.target);
16099
+ if (nextSource && target) {
16100
+ this._arm(event, target);
15785
16101
  }
15786
16102
  }
15787
16103
  _cancel() {
@@ -15910,6 +16226,12 @@ class FDraggableDirective extends FDraggableBase {
15910
16226
  _nodeMoveTrigger;
15911
16227
  _canvasMoveTrigger;
15912
16228
  disabled = false;
16229
+ /** Turns the drop-to-group gesture on/off. See `FDraggableBase.dropToGroup`. */
16230
+ dropToGroup = input(true, ...(ngDevMode ? [{ debugName: "dropToGroup", transform: (value) => booleanAttribute(value),
16231
+ alias: 'fDropToGroup' }] : [{
16232
+ transform: (value) => booleanAttribute(value),
16233
+ alias: 'fDropToGroup',
16234
+ }]));
15913
16235
  fMultiSelectTrigger = (event) => {
15914
16236
  return this._platform.getOS() === EOperationSystem.MAC_OS ? event.metaKey : event.ctrlKey;
15915
16237
  };
@@ -16010,6 +16332,46 @@ class FDraggableDirective extends FDraggableBase {
16010
16332
  this._connectionFlow.initialize();
16011
16333
  }
16012
16334
  }
16335
+ /**
16336
+ * Gesture claim chain, phase by phase. WITHIN EACH LIST THE ORDER IS THE
16337
+ * PRIORITY CONTRACT: every preparation guards itself with
16338
+ * `FDraggableDataContext.isEmpty()`, so the first entry that claims the
16339
+ * pointer wins and everything after it backs off. The three phases are
16340
+ * intentionally ordered independently — finalization is not a mirror of
16341
+ * preparation (e.g. pinch-to-zoom finalizes last so slower gestures settle
16342
+ * first).
16343
+ */
16344
+ _pointerDownClaimants = [
16345
+ (event) => this._mediator.execute(new SelectionAreaPreparationRequest(event)),
16346
+ (event) => this._mediator.execute(new DragMinimapPreparationRequest(event)),
16347
+ (event) => this._mediator.execute(new PinchToZoomPreparationRequest(event)),
16348
+ (event) => this._mediator.execute(new SelectByPointerRequest(event, this.fMultiSelectTrigger)),
16349
+ (event) => this._mediator.execute(new ReassignConnectionPreparationRequest(event, this.fReassignConnectionTrigger)),
16350
+ (event) => this._mediator.execute(new CreateConnectionPreparationRequest(event, this.fCreateConnectionTrigger)),
16351
+ (event) => this._mediator.execute(new DragConnectionWaypointPreparationRequest(event, this.fConnectionWaypointsTrigger())),
16352
+ ];
16353
+ _thresholdClaimants = [
16354
+ (event) => this._mediator.execute(new ResizeNodePreparationRequest(event, this.fNodeResizeTrigger)),
16355
+ (event) => this._mediator.execute(new RotateNodePreparationRequest(event, this.fNodeRotateTrigger)),
16356
+ (event) => this._mediator.execute(new DragNodePreparationRequest(event, this.fNodeMoveTrigger)),
16357
+ (event) => this._mediator.execute(new DragExternalItemPreparationRequest(event, this.fExternalItemTrigger)),
16358
+ (event) => this._mediator.execute(new DropToGroupPreparationRequest(event)),
16359
+ (event) => this._mediator.execute(new DragCanvasPreparationRequest(event, this.fCanvasMoveTrigger)),
16360
+ ];
16361
+ _pointerUpFinalizers = [
16362
+ (event) => this._mediator.execute(new DragMinimapFinalizeRequest(event)),
16363
+ (event) => this._mediator.execute(new SelectionAreaFinalizeRequest(event)),
16364
+ (event) => this._mediator.execute(new ReassignConnectionFinalizeRequest(event)),
16365
+ (event) => this._mediator.execute(new CreateConnectionFinalizeRequest(event)),
16366
+ (event) => this._mediator.execute(new ResizeNodeFinalizeRequest(event)),
16367
+ (event) => this._mediator.execute(new RotateNodeFinalizeRequest(event)),
16368
+ (event) => this._mediator.execute(new DragNodeFinalizeRequest(event)),
16369
+ (event) => this._mediator.execute(new DragExternalItemFinalizeRequest(event)),
16370
+ (event) => this._mediator.execute(new DropToGroupFinalizeRequest(event)),
16371
+ (event) => this._mediator.execute(new DragCanvasFinalizeRequest(event)),
16372
+ (event) => this._mediator.execute(new PinchToZoomFinalizeRequest(event)),
16373
+ (event) => this._mediator.execute(new DragConnectionWaypointFinalizeRequest(event)),
16374
+ ];
16013
16375
  onPointerDown(event) {
16014
16376
  if (isDragBlocker(event.targetElement)) {
16015
16377
  return false;
@@ -16017,13 +16379,7 @@ class FDraggableDirective extends FDraggableBase {
16017
16379
  this._dragHandlerInjector.create();
16018
16380
  this._result.clear();
16019
16381
  this._mediator.execute(new InitializeDragSequenceRequest());
16020
- this._mediator.execute(new SelectionAreaPreparationRequest(event));
16021
- this._mediator.execute(new DragMinimapPreparationRequest(event));
16022
- this._mediator.execute(new PinchToZoomPreparationRequest(event));
16023
- this._mediator.execute(new SelectByPointerRequest(event, this.fMultiSelectTrigger));
16024
- this._mediator.execute(new ReassignConnectionPreparationRequest(event, this.fReassignConnectionTrigger));
16025
- this._mediator.execute(new CreateConnectionPreparationRequest(event, this.fCreateConnectionTrigger));
16026
- this._mediator.execute(new DragConnectionWaypointPreparationRequest(event, this.fConnectionWaypointsTrigger()));
16382
+ this._pointerDownClaimants.forEach((claim) => claim(event));
16027
16383
  // The left button and touch drive every interaction. The middle button joins only
16028
16384
  // when the active scheme's `canvasMove` gesture claims it (e.g. middle-drag pan in
16029
16385
  // the scroll-pan / drag-select schemes); with the default scheme it stays inert.
@@ -16035,12 +16391,7 @@ class FDraggableDirective extends FDraggableBase {
16035
16391
  return isDraggableButton;
16036
16392
  }
16037
16393
  prepareDragSequence(event) {
16038
- this._mediator.execute(new ResizeNodePreparationRequest(event, this.fNodeResizeTrigger));
16039
- this._mediator.execute(new RotateNodePreparationRequest(event, this.fNodeRotateTrigger));
16040
- this._mediator.execute(new DragNodePreparationRequest(event, this.fNodeMoveTrigger));
16041
- this._mediator.execute(new DragExternalItemPreparationRequest(event, this.fExternalItemTrigger));
16042
- this._mediator.execute(new DropToGroupPreparationRequest(event));
16043
- this._mediator.execute(new DragCanvasPreparationRequest(event, this.fCanvasMoveTrigger));
16394
+ this._thresholdClaimants.forEach((claim) => claim(event));
16044
16395
  this._mediator.execute(new PrepareDragSequenceRequest());
16045
16396
  }
16046
16397
  onSelect(event) {
@@ -16051,18 +16402,7 @@ class FDraggableDirective extends FDraggableBase {
16051
16402
  this._mediator.execute(new ScheduleAutoPanFrameRequest());
16052
16403
  }
16053
16404
  onPointerUp(event) {
16054
- this._mediator.execute(new DragMinimapFinalizeRequest(event));
16055
- this._mediator.execute(new SelectionAreaFinalizeRequest(event));
16056
- this._mediator.execute(new ReassignConnectionFinalizeRequest(event));
16057
- this._mediator.execute(new CreateConnectionFinalizeRequest(event));
16058
- this._mediator.execute(new ResizeNodeFinalizeRequest(event));
16059
- this._mediator.execute(new RotateNodeFinalizeRequest(event));
16060
- this._mediator.execute(new DragNodeFinalizeRequest(event));
16061
- this._mediator.execute(new DragExternalItemFinalizeRequest(event));
16062
- this._mediator.execute(new DropToGroupFinalizeRequest(event));
16063
- this._mediator.execute(new DragCanvasFinalizeRequest(event));
16064
- this._mediator.execute(new PinchToZoomFinalizeRequest(event));
16065
- this._mediator.execute(new DragConnectionWaypointFinalizeRequest(event));
16405
+ this._pointerUpFinalizers.forEach((finalize) => finalize(event));
16066
16406
  this._mediator.execute(new EmitEndDragSequenceEventRequest());
16067
16407
  }
16068
16408
  finalizeDragSequence() {
@@ -16078,7 +16418,7 @@ class FDraggableDirective extends FDraggableBase {
16078
16418
  super.unsubscribe();
16079
16419
  }
16080
16420
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FDraggableDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
16081
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.9", type: FDraggableDirective, isStandalone: false, selector: "f-flow[fDraggable]", inputs: { disabled: { classPropertyName: "disabled", publicName: "fDraggableDisabled", isSignal: false, isRequired: false, transformFunction: booleanAttribute }, fMultiSelectTrigger: { classPropertyName: "fMultiSelectTrigger", publicName: "fMultiSelectTrigger", isSignal: false, isRequired: false, transformFunction: null }, fReassignConnectionTrigger: { classPropertyName: "fReassignConnectionTrigger", publicName: "fReassignConnectionTrigger", isSignal: false, isRequired: false, transformFunction: null }, fCreateConnectionTrigger: { classPropertyName: "fCreateConnectionTrigger", publicName: "fCreateConnectionTrigger", isSignal: false, isRequired: false, transformFunction: null }, fConnectionWaypointsTrigger: { classPropertyName: "fConnectionWaypointsTrigger", publicName: "fConnectionWaypointsTrigger", isSignal: true, isRequired: false, transformFunction: null }, fMoveControlPointTrigger: { classPropertyName: "fMoveControlPointTrigger", publicName: "fMoveControlPointTrigger", isSignal: false, isRequired: false, transformFunction: null }, fNodeResizeTrigger: { classPropertyName: "fNodeResizeTrigger", publicName: "fNodeResizeTrigger", isSignal: false, isRequired: false, transformFunction: null }, fNodeRotateTrigger: { classPropertyName: "fNodeRotateTrigger", publicName: "fNodeRotateTrigger", isSignal: false, isRequired: false, transformFunction: null }, fNodeMoveTrigger: { classPropertyName: "fNodeMoveTrigger", publicName: "fNodeMoveTrigger", isSignal: false, isRequired: false, transformFunction: null }, fCanvasMoveTrigger: { classPropertyName: "fCanvasMoveTrigger", publicName: "fCanvasMoveTrigger", isSignal: false, isRequired: false, transformFunction: null }, fExternalItemTrigger: { classPropertyName: "fExternalItemTrigger", publicName: "fExternalItemTrigger", isSignal: false, isRequired: false, transformFunction: null }, fEmitOnNodeIntersect: { classPropertyName: "fEmitOnNodeIntersect", publicName: "fEmitOnNodeIntersect", isSignal: false, isRequired: false, transformFunction: booleanAttribute }, vCellSize: { classPropertyName: "vCellSize", publicName: "vCellSize", isSignal: true, isRequired: false, transformFunction: null }, hCellSize: { classPropertyName: "hCellSize", publicName: "hCellSize", isSignal: true, isRequired: false, transformFunction: null }, fCellSizeWhileDragging: { classPropertyName: "fCellSizeWhileDragging", publicName: "fCellSizeWhileDragging", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fSelectionChange: "fSelectionChange", fDeleteSelected: "fDeleteSelected", fNodeIntersectedWithConnections: "fNodeIntersectedWithConnections", fNodeConnectionsIntersection: "fNodeConnectionsIntersection", fCreateNode: "fCreateNode", fMoveNodes: "fMoveNodes", fReassignConnection: "fReassignConnection", fCreateConnection: "fCreateConnection", fConnectionWaypointsChanged: "fConnectionWaypointsChanged", fDropToGroup: "fDropToGroup", fDragStarted: "fDragStarted", fDragEnded: "fDragEnded" }, providers: [FDragHandlerResult, DragHandlerInjector], exportAs: ["fDraggable"], usesInheritance: true, ngImport: i0 });
16421
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.9", type: FDraggableDirective, isStandalone: false, selector: "f-flow[fDraggable]", inputs: { disabled: { classPropertyName: "disabled", publicName: "fDraggableDisabled", isSignal: false, isRequired: false, transformFunction: booleanAttribute }, dropToGroup: { classPropertyName: "dropToGroup", publicName: "fDropToGroup", isSignal: true, isRequired: false, transformFunction: null }, fMultiSelectTrigger: { classPropertyName: "fMultiSelectTrigger", publicName: "fMultiSelectTrigger", isSignal: false, isRequired: false, transformFunction: null }, fReassignConnectionTrigger: { classPropertyName: "fReassignConnectionTrigger", publicName: "fReassignConnectionTrigger", isSignal: false, isRequired: false, transformFunction: null }, fCreateConnectionTrigger: { classPropertyName: "fCreateConnectionTrigger", publicName: "fCreateConnectionTrigger", isSignal: false, isRequired: false, transformFunction: null }, fConnectionWaypointsTrigger: { classPropertyName: "fConnectionWaypointsTrigger", publicName: "fConnectionWaypointsTrigger", isSignal: true, isRequired: false, transformFunction: null }, fMoveControlPointTrigger: { classPropertyName: "fMoveControlPointTrigger", publicName: "fMoveControlPointTrigger", isSignal: false, isRequired: false, transformFunction: null }, fNodeResizeTrigger: { classPropertyName: "fNodeResizeTrigger", publicName: "fNodeResizeTrigger", isSignal: false, isRequired: false, transformFunction: null }, fNodeRotateTrigger: { classPropertyName: "fNodeRotateTrigger", publicName: "fNodeRotateTrigger", isSignal: false, isRequired: false, transformFunction: null }, fNodeMoveTrigger: { classPropertyName: "fNodeMoveTrigger", publicName: "fNodeMoveTrigger", isSignal: false, isRequired: false, transformFunction: null }, fCanvasMoveTrigger: { classPropertyName: "fCanvasMoveTrigger", publicName: "fCanvasMoveTrigger", isSignal: false, isRequired: false, transformFunction: null }, fExternalItemTrigger: { classPropertyName: "fExternalItemTrigger", publicName: "fExternalItemTrigger", isSignal: false, isRequired: false, transformFunction: null }, fEmitOnNodeIntersect: { classPropertyName: "fEmitOnNodeIntersect", publicName: "fEmitOnNodeIntersect", isSignal: false, isRequired: false, transformFunction: booleanAttribute }, vCellSize: { classPropertyName: "vCellSize", publicName: "vCellSize", isSignal: true, isRequired: false, transformFunction: null }, hCellSize: { classPropertyName: "hCellSize", publicName: "hCellSize", isSignal: true, isRequired: false, transformFunction: null }, fCellSizeWhileDragging: { classPropertyName: "fCellSizeWhileDragging", publicName: "fCellSizeWhileDragging", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fSelectionChange: "fSelectionChange", fDeleteSelected: "fDeleteSelected", fNodeIntersectedWithConnections: "fNodeIntersectedWithConnections", fNodeConnectionsIntersection: "fNodeConnectionsIntersection", fCreateNode: "fCreateNode", fMoveNodes: "fMoveNodes", fReassignConnection: "fReassignConnection", fCreateConnection: "fCreateConnection", fConnectionWaypointsChanged: "fConnectionWaypointsChanged", fDropToGroup: "fDropToGroup", fDragStarted: "fDragStarted", fDragEnded: "fDragEnded" }, host: { properties: { "class.f-drop-to-group": "dropToGroup()" } }, providers: [FDragHandlerResult, DragHandlerInjector], exportAs: ["fDraggable"], usesInheritance: true, ngImport: i0 });
16082
16422
  }
16083
16423
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FDraggableDirective, decorators: [{
16084
16424
  type: Directive,
@@ -16087,11 +16427,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
16087
16427
  selector: 'f-flow[fDraggable]',
16088
16428
  exportAs: 'fDraggable',
16089
16429
  providers: [FDragHandlerResult, DragHandlerInjector],
16430
+ host: {
16431
+ // On by default: marks the flow so the grouping styles (drop-target
16432
+ // highlight) apply. Cleared reactively when `fDropToGroup` is set to false.
16433
+ '[class.f-drop-to-group]': 'dropToGroup()',
16434
+ },
16090
16435
  }]
16091
16436
  }], propDecorators: { disabled: [{
16092
16437
  type: Input,
16093
16438
  args: [{ transform: booleanAttribute, alias: 'fDraggableDisabled' }]
16094
- }], fMultiSelectTrigger: [{
16439
+ }], dropToGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "fDropToGroup", required: false }] }], fMultiSelectTrigger: [{
16095
16440
  type: Input
16096
16441
  }], fReassignConnectionTrigger: [{
16097
16442
  type: Input
@@ -16437,7 +16782,7 @@ let FindConnectableConnectorUsingPriorityAndPosition = class FindConnectableConn
16437
16782
  .find((x) => !!x);
16438
16783
  }
16439
16784
  _getElementsFromPoint(position) {
16440
- return this._browser.document.elementsFromPoint(position.x, position.y);
16785
+ return getDeepElementsFromPoint(this._browser.document, position.x, position.y);
16441
16786
  }
16442
16787
  _findConnectableNode(element) {
16443
16788
  return this._fNodes.find((x) => x.isContains(element) && x.fConnectOnNode());
@@ -16836,8 +17181,11 @@ let OnPointerMove = class OnPointerMove {
16836
17181
  this._setDifferenceToDraggableItems(this._getDifferenceBetweenPointerAndPointerDown(event), event);
16837
17182
  }
16838
17183
  _setDifferenceToDraggableItems(difference, event) {
17184
+ // One object per event, shared read-only by every handler: spreading a copy
17185
+ // per handler allocated hundreds of points per pointermove on multi-select
17186
+ // drags, and no handler mutates the difference.
16839
17187
  this._dragContext.draggableItems.forEach((item) => {
16840
- item.onPointerMove({ ...difference }, event);
17188
+ item.onPointerMove(difference, event);
16841
17189
  });
16842
17190
  }
16843
17191
  _getDifferenceBetweenPointerAndPointerDown(event) {
@@ -17157,6 +17505,44 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
17157
17505
  type: Injectable
17158
17506
  }] });
17159
17507
 
17508
+ const DEBOUNCE_TIME_MS = 3;
17509
+ /**
17510
+ * Debounces connectable-side recalculation for all nodes through ONE timer.
17511
+ * Every node used to own a clearTimeout+setTimeout pair re-armed on each
17512
+ * redraw — a multi-node drag churned N timers per pointer event. Nodes are
17513
+ * collected into a set and flushed together 3ms after the last redraw.
17514
+ */
17515
+ class ConnectableSidesScheduler {
17516
+ _mediator = inject(FMediator);
17517
+ _store = inject(FComponentsStore);
17518
+ _pending = new Set();
17519
+ _timer = null;
17520
+ schedule(node) {
17521
+ this._pending.add(node);
17522
+ if (this._timer !== null) {
17523
+ clearTimeout(this._timer);
17524
+ }
17525
+ this._timer = setTimeout(() => {
17526
+ this._timer = null;
17527
+ this._flush();
17528
+ }, DEBOUNCE_TIME_MS);
17529
+ }
17530
+ _flush() {
17531
+ for (const node of this._pending) {
17532
+ // A node destroyed while queued must not be recalculated.
17533
+ if (this._store.nodes.get(node.fId()) === node) {
17534
+ this._mediator.execute(new CalculateConnectorsConnectableSidesRequest(node));
17535
+ }
17536
+ }
17537
+ this._pending.clear();
17538
+ }
17539
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ConnectableSidesScheduler, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
17540
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ConnectableSidesScheduler });
17541
+ }
17542
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ConnectableSidesScheduler, decorators: [{
17543
+ type: Injectable
17544
+ }] });
17545
+
17160
17546
  class CalculateNodesBoundingBoxRequest {
17161
17547
  static fToken = Symbol('CalculateNodesBoundingBoxRequest');
17162
17548
  }
@@ -17333,10 +17719,24 @@ let FitToChildNodesAndGroups = class FitToChildNodesAndGroups {
17333
17719
  if (directChildren.length) {
17334
17720
  const currentBounding = this._boundingRect(nodeOrGroup);
17335
17721
  const childrenBounding = this._calculateChildrenBounding(directChildren, this._paddings(nodeOrGroup, currentBounding));
17722
+ // Capture the node's OWN stored rect before applying the fit. The DOM
17723
+ // measurement (`currentBounding`) lags a frame behind `redraw`, so the
17724
+ // convergence pass (redraw → ResizeObserver → fit again) would still
17725
+ // see the old measurement and re-emit the same size — a duplicate.
17726
+ const previousRect = this._storedRect(nodeOrGroup);
17336
17727
  nodeOrGroup.updatePosition(childrenBounding);
17337
17728
  nodeOrGroup.updateSize(childrenBounding);
17338
17729
  nodeOrGroup.redraw();
17730
+ // Auto-size is a resize like any other: notify `fNodeSizeChange` /
17731
+ // `fGroupSizeChange`, but only when the fit actually changed the box,
17732
+ // so a settled fit stays silent and can't feed a resize loop.
17733
+ if (!previousRect || !this._isSameRect(previousRect, childrenBounding)) {
17734
+ nodeOrGroup.sizeChange.emit(childrenBounding);
17735
+ }
17339
17736
  }
17737
+ // No children: nothing to fit to. The group keeps whatever size it was
17738
+ // told to have via `fGroupSize` — the binding (e.g. restored by undo)
17739
+ // is the source of truth; the fit must not invent a size here.
17340
17740
  }
17341
17741
  const parent = nodeOrGroup.fParentId();
17342
17742
  if (!parent) {
@@ -17366,6 +17766,17 @@ let FitToChildNodesAndGroups = class FitToChildNodesAndGroups {
17366
17766
  childrenBounding = RectExtensions.initialize(childrenBounding.x - left, childrenBounding.y - top, childrenBounding.width + left + right, childrenBounding.height + top + bottom);
17367
17767
  return childrenBounding;
17368
17768
  }
17769
+ _storedRect(nodeOrGroup) {
17770
+ return nodeOrGroup._size
17771
+ ? RectExtensions.initialize(nodeOrGroup._position.x, nodeOrGroup._position.y, nodeOrGroup._size.width, nodeOrGroup._size.height)
17772
+ : null;
17773
+ }
17774
+ _isSameRect(a, b) {
17775
+ return (Math.round(a.x) === Math.round(b.x) &&
17776
+ Math.round(a.y) === Math.round(b.y) &&
17777
+ Math.round(a.width) === Math.round(b.width) &&
17778
+ Math.round(a.height) === Math.round(b.height));
17779
+ }
17369
17780
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FitToChildNodesAndGroups, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
17370
17781
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FitToChildNodesAndGroups });
17371
17782
  };
@@ -17484,6 +17895,7 @@ class UpdateNodeWhenStateOrSizeChangedRequest {
17484
17895
  let UpdateNodeWhenStateOrSizeChanged = class UpdateNodeWhenStateOrSizeChanged {
17485
17896
  _mediator = inject(FMediator);
17486
17897
  _reflowOrchestrator = inject(FReflowOrchestrator);
17898
+ _injector = inject(Injector);
17487
17899
  /**
17488
17900
  * Handles the request to update the node's connectors based on state or size changes.
17489
17901
  * It listens for resize events and recalculates the connectable sides of the connectors.
@@ -17494,11 +17906,25 @@ let UpdateNodeWhenStateOrSizeChanged = class UpdateNodeWhenStateOrSizeChanged {
17494
17906
  new FChannelHub(new FResizeChannel(hostElement), stateChanges)
17495
17907
  // .pipe(afterNextPaint()) // Removed: caused ~32ms lag on resize/toggle. Debounce is sufficient for DOM stability.
17496
17908
  .listen(destroyRef, () => {
17497
- this._mediator.execute(new EmitConnectionsChangesRequest());
17909
+ // Scoped: a single node's resize/state change only needs its own
17910
+ // connections redrawn, not a whole-graph pass.
17911
+ this._mediator.execute(new EmitConnectionsChangesRequest(nodeOrGroup.fId()));
17498
17912
  if (!this._isDragging()) {
17499
17913
  this._mediator.execute(new InvalidateFCacheNodeRequest(nodeOrGroup.fId(), 'UpdateNodeWhenStateOrSizeChanged'));
17500
17914
  this._mediator.execute(new CalculateConnectorsConnectableSidesRequest(nodeOrGroup));
17501
- this._mediator.execute(new FitToChildNodesAndGroupsRequest(nodeOrGroup));
17915
+ // Auto-fit must read FRESH child parentage. On a state-driven change
17916
+ // (e.g. undo re-parenting a child out), the fit would otherwise run
17917
+ // inside this same synchronous tick — before Angular propagates the
17918
+ // new `[fNodeParentId]` into the child directives — and count a
17919
+ // just-removed child, re-shrinking the group. Deferring only the fit
17920
+ // to the next render hook (same CD cycle, before paint) lets it see
17921
+ // the settled parentage. Content/plain resizes keep today's sync path.
17922
+ if (nodeOrGroup.fAutoSizeToFitChildren()) {
17923
+ afterNextRender(() => this._mediator.execute(new FitToChildNodesAndGroupsRequest(nodeOrGroup)), { injector: this._injector });
17924
+ }
17925
+ else {
17926
+ this._mediator.execute(new FitToChildNodesAndGroupsRequest(nodeOrGroup));
17927
+ }
17502
17928
  this._reflowOrchestrator.handleResize(nodeOrGroup);
17503
17929
  }
17504
17930
  });
@@ -17554,6 +17980,7 @@ const F_NODE_FEATURES = [
17554
17980
  CalculateConnectableSideByInternalPosition,
17555
17981
  CalculateInputConnections,
17556
17982
  CalculateConnectorsConnectableSides,
17983
+ ConnectableSidesScheduler,
17557
17984
  CalculateNodesBoundingBox,
17558
17985
  CalculateNodesBoundingBoxNormalizedPosition,
17559
17986
  CalculateOutputConnections,
@@ -19379,40 +19806,194 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
19379
19806
  const F_ZOOM_FEATURES = [ResetZoom, SetZoom];
19380
19807
 
19381
19808
  class MinimapDrawNodesRequest {
19809
+ hostElement;
19382
19810
  static fToken = Symbol('MinimapDrawNodesRequest');
19811
+ constructor(hostElement) {
19812
+ this.hostElement = hostElement;
19813
+ }
19814
+ }
19815
+
19816
+ /**
19817
+ * Flow-space node rects for the minimap, computed from the model instead of
19818
+ * per-frame DOM measurement.
19819
+ *
19820
+ * Positions come straight from `node._position`; sizes are read from layout
19821
+ * once (offsetWidth/offsetHeight are unaffected by the canvas CSS transform)
19822
+ * and cached until a node resize invalidates them via `connectionsRevision` —
19823
+ * the same signal every node's ResizeObserver already bumps. Pan/zoom therefore
19824
+ * costs zero DOM reads per node, which is what previously forced the minimap
19825
+ * to bail out above `fNodeRenderLimit`.
19826
+ */
19827
+ class MinimapNodeRects {
19828
+ _store = inject(FComponentsStore);
19829
+ _sizes = new WeakMap();
19830
+ _sizesRevision = -1;
19831
+ /** Drops stale cached sizes when any node resized since the last pass. */
19832
+ ensureFresh() {
19833
+ const revision = this._store.connectionsRevision;
19834
+ if (revision !== this._sizesRevision) {
19835
+ this._sizesRevision = revision;
19836
+ this._sizes = new WeakMap();
19837
+ }
19838
+ }
19839
+ /**
19840
+ * The minimap draws nodes in flow coordinates and shifts the whole layer by
19841
+ * this offset, so panning moves one `<g>` transform instead of every rect.
19842
+ */
19843
+ viewOffset() {
19844
+ const transform = this._store.transform;
19845
+ if (!transform) {
19846
+ return { x: 0, y: 0 };
19847
+ }
19848
+ const scale = transform.scale || 1;
19849
+ return {
19850
+ x: (transform.position.x + transform.scaledPosition.x) / scale,
19851
+ y: (transform.position.y + transform.scaledPosition.y) / scale,
19852
+ };
19853
+ }
19854
+ /** Rotation-aware AABB of a node in flow coordinates. */
19855
+ rectOf(node) {
19856
+ const size = this._sizeOf(node);
19857
+ const { x, y } = node._position;
19858
+ if (!node._rotate) {
19859
+ return RectExtensions.initialize(x, y, size.width, size.height);
19860
+ }
19861
+ // transform: translate(p) rotate(deg) spins the node around its center;
19862
+ // mirror that math so rotated nodes keep the same minimap footprint the
19863
+ // old getBoundingClientRect path produced.
19864
+ const radians = (node._rotate * Math.PI) / 180;
19865
+ const cos = Math.abs(Math.cos(radians));
19866
+ const sin = Math.abs(Math.sin(radians));
19867
+ const width = size.width * cos + size.height * sin;
19868
+ const height = size.width * sin + size.height * cos;
19869
+ return RectExtensions.initialize(x + size.width / 2 - width / 2, y + size.height / 2 - height / 2, width, height);
19870
+ }
19871
+ /** Union of all node rects in flow coordinates; null when there are no nodes. */
19872
+ contentRect() {
19873
+ const nodes = this._store.nodes.getAll();
19874
+ if (!nodes.length) {
19875
+ return null;
19876
+ }
19877
+ let minX = Infinity;
19878
+ let minY = Infinity;
19879
+ let maxX = -Infinity;
19880
+ let maxY = -Infinity;
19881
+ for (const node of nodes) {
19882
+ const rect = this.rectOf(node);
19883
+ minX = Math.min(minX, rect.x);
19884
+ minY = Math.min(minY, rect.y);
19885
+ maxX = Math.max(maxX, rect.x + rect.width);
19886
+ maxY = Math.max(maxY, rect.y + rect.height);
19887
+ }
19888
+ return RectExtensions.initialize(minX, minY, maxX - minX, maxY - minY);
19889
+ }
19890
+ _sizeOf(node) {
19891
+ if (node._size) {
19892
+ return node._size;
19893
+ }
19894
+ const cached = this._sizes.get(node);
19895
+ if (cached) {
19896
+ return cached;
19897
+ }
19898
+ const measured = this._measure(node);
19899
+ this._sizes.set(node, measured);
19900
+ return measured;
19901
+ }
19902
+ _measure(node) {
19903
+ const host = node.hostElement;
19904
+ if (typeof host.offsetWidth === 'number') {
19905
+ return { width: host.offsetWidth, height: host.offsetHeight };
19906
+ }
19907
+ // SVG hosts have no offset geometry; fall back to one unscaled gBCR.
19908
+ const rect = host.getBoundingClientRect();
19909
+ const scale = this._store.transform?.scale || 1;
19910
+ return { width: rect.width / scale, height: rect.height / scale };
19911
+ }
19912
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: MinimapNodeRects, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
19913
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: MinimapNodeRects });
19383
19914
  }
19915
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: MinimapNodeRects, decorators: [{
19916
+ type: Injectable
19917
+ }] });
19384
19918
 
19919
+ /**
19920
+ * Keeps one `<rect>` per node and updates it in place. Rects live in flow
19921
+ * coordinates; panning/zooming only moves the group transform, so a transform
19922
+ * change writes ONE attribute instead of rebuilding N elements — the previous
19923
+ * implementation re-measured (2 x getBoundingClientRect) and re-created every
19924
+ * node rect on every animation frame.
19925
+ */
19385
19926
  let MinimapDrawNodes = class MinimapDrawNodes {
19386
19927
  _browser = inject(BrowserService);
19387
19928
  _store = inject(FComponentsStore);
19388
- handle(_) {
19389
- const flow = this._store.fFlow;
19390
- const canvas = this._store.fCanvas;
19391
- if (!flow || !canvas) {
19392
- return [];
19393
- }
19929
+ _rects = inject(MinimapNodeRects);
19930
+ _entries = new Map();
19931
+ _membershipRevision = -1;
19932
+ handle({ hostElement }) {
19933
+ this._rects.ensureFresh();
19394
19934
  const nodes = this._store.nodes.getAll();
19395
- return nodes.map((node) => this._renderNode(node, flow, canvas));
19396
- }
19397
- _renderNode(node, flow, canvas) {
19398
- const rect = createSVGElement('rect', this._browser);
19399
- setRectToElement(this._nodeRect(node, flow, canvas), rect);
19400
- const isNode = node instanceof FNodeDirective;
19401
- rect.classList.add('f-component', isNode ? 'f-minimap-node' : 'f-minimap-group');
19402
- rect.classList.add(...this._minimapClasses(node));
19403
- if (node.isSelected()) {
19404
- rect.classList.add('f-selected');
19935
+ if (this._membershipRevision !== this._store.nodesRevision) {
19936
+ this._membershipRevision = this._store.nodesRevision;
19937
+ this._removeStaleEntries(nodes);
19938
+ }
19939
+ const offset = this._rects.viewOffset();
19940
+ hostElement.setAttribute('transform', `translate(${offset.x} ${offset.y})`);
19941
+ for (const node of nodes) {
19942
+ this._updateNode(node, hostElement);
19405
19943
  }
19406
- return rect;
19407
19944
  }
19408
- _nodeRect(node, flow, canvas) {
19409
- const inFlow = RectExtensions.elementTransform(RectExtensions.fromElement(node.hostElement), flow.hostElement);
19410
- return RectExtensions.div(inFlow, canvas.transform.scale);
19945
+ _updateNode(node, hostElement) {
19946
+ let entry = this._entries.get(node);
19947
+ if (!entry) {
19948
+ entry = {
19949
+ element: createSVGElement('rect', this._browser),
19950
+ lastRect: RectExtensions.initialize(NaN, NaN),
19951
+ lastClassName: '',
19952
+ };
19953
+ this._entries.set(node, entry);
19954
+ }
19955
+ const rect = this._rects.rectOf(node);
19956
+ if (!this._isSameRect(rect, entry.lastRect)) {
19957
+ setRectToElement(rect, entry.element);
19958
+ entry.lastRect = rect;
19959
+ }
19960
+ const className = this._className(node);
19961
+ if (className !== entry.lastClassName) {
19962
+ entry.element.setAttribute('class', className);
19963
+ entry.lastClassName = className;
19964
+ }
19965
+ // Also self-heals after an external clear() (e.g. the render-limit bailout).
19966
+ if (entry.element.parentNode !== hostElement) {
19967
+ hostElement.appendChild(entry.element);
19968
+ }
19969
+ }
19970
+ _removeStaleEntries(nodes) {
19971
+ const alive = new Set(nodes);
19972
+ for (const [node, entry] of this._entries) {
19973
+ if (!alive.has(node)) {
19974
+ entry.element.remove();
19975
+ this._entries.delete(node);
19976
+ }
19977
+ }
19978
+ }
19979
+ _className(node) {
19980
+ const parts = [
19981
+ 'f-component',
19982
+ node instanceof FNodeDirective ? 'f-minimap-node' : 'f-minimap-group',
19983
+ ...this._minimapClasses(node),
19984
+ ];
19985
+ if (node.isSelected()) {
19986
+ parts.push('f-selected');
19987
+ }
19988
+ return parts.join(' ');
19411
19989
  }
19412
19990
  _minimapClasses(node) {
19413
19991
  const classes = node.fMinimapClass();
19414
19992
  return Array.isArray(classes) ? classes : [classes];
19415
19993
  }
19994
+ _isSameRect(a, b) {
19995
+ return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
19996
+ }
19416
19997
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: MinimapDrawNodes, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
19417
19998
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: MinimapDrawNodes });
19418
19999
  };
@@ -19434,30 +20015,32 @@ class MinimapCalculateViewportRequest {
19434
20015
  }
19435
20016
 
19436
20017
  let MinimapCalculateViewport = class MinimapCalculateViewport {
19437
- _mediator = inject(FMediator);
19438
20018
  _store = inject(FComponentsStore);
20019
+ _rects = inject(MinimapNodeRects);
19439
20020
  handle({ svg, minSize }) {
19440
20021
  const flow = this._store.fFlow;
19441
20022
  const canvas = this._store.fCanvas;
19442
20023
  if (!flow || !canvas) {
19443
20024
  return { scale: 1, viewBox: RectExtensions.initialize(0, 0, 0, 0) };
19444
20025
  }
19445
- const contentRect = this._contentRectInMinimapSpace(flow, canvas, minSize);
20026
+ const contentRect = this._contentRectInMinimapSpace(minSize);
19446
20027
  const minimapRect = this._minimapRectInFlowSpace(svg, flow);
19447
20028
  const scale = this._viewportScale(contentRect, minimapRect);
19448
20029
  const viewBox = this._viewportViewBox(contentRect, minimapRect, scale);
19449
20030
  return { scale, viewBox };
19450
20031
  }
19451
- _contentRectInMinimapSpace(flow, canvas, minSize) {
19452
- const global = this._nodesBoundingBox();
19453
- const inFlow = RectExtensions.elementTransform(global, flow.hostElement);
19454
- const inMinimap = RectExtensions.div(inFlow, canvas.transform.scale);
20032
+ /**
20033
+ * Model-space union of node rects shifted by the view offset — numerically
20034
+ * the same rect the old DOM path produced (screen union normalized into the
20035
+ * flow and divided by scale), without measuring a single element.
20036
+ */
20037
+ _contentRectInMinimapSpace(minSize) {
20038
+ this._rects.ensureFresh();
20039
+ const content = this._rects.contentRect() ?? RectExtensions.initialize(0, 0, 0, 0);
20040
+ const offset = this._rects.viewOffset();
20041
+ const inMinimap = RectExtensions.initialize(content.x + offset.x, content.y + offset.y, content.width, content.height);
19455
20042
  return adjustRectToMinSize(inMinimap, minSize);
19456
20043
  }
19457
- _nodesBoundingBox() {
19458
- return (this._mediator.execute(new CalculateNodesBoundingBoxRequest()) ??
19459
- RectExtensions.initialize(0, 0, 0, 0));
19460
- }
19461
20044
  _minimapRectInFlowSpace(svg, flow) {
19462
20045
  return RectExtensions.elementTransform(RectExtensions.fromElement(svg), flow.hostElement);
19463
20046
  }
@@ -19529,6 +20112,7 @@ const F_MINIMAP_FEATURES = [
19529
20112
  MinimapDrawNodes,
19530
20113
  MinimapCalculateViewport,
19531
20114
  MinimapCalculateViewRect,
20115
+ MinimapNodeRects,
19532
20116
  ];
19533
20117
 
19534
20118
  class GetNormalizedPointRequest {
@@ -20387,6 +20971,7 @@ class FCanvasComponent extends FCanvasBase {
20387
20971
  * Centers the specified group or node on the canvas.
20388
20972
  * @param groupOrNodeId - The ID of the group or node to center.
20389
20973
  * @param animated - If true, the centering will be animated; otherwise, it will be instantaneous.
20974
+ * @param emitCanvasChange - If false, does not emit `fCanvasChange` for this programmatic move.
20390
20975
  */
20391
20976
  /**
20392
20977
  * FF1009 — viewport helpers compute from the nodes bounding box, so calling them
@@ -20399,21 +20984,22 @@ class FCanvasComponent extends FCanvasBase {
20399
20984
  fWarnOnce('FF1009', method, `${method} was called before the nodes were rendered, so it computes against an incomplete node set. Call it from the (fNodesRendered) or (fFullRendered) output of <f-flow>.`);
20400
20985
  }
20401
20986
  }
20402
- centerGroupOrNode(groupOrNodeId, animated = true) {
20987
+ centerGroupOrNode(groupOrNodeId, animated = true, emitCanvasChange = true) {
20403
20988
  this._warnWhenCalledBeforeNodesRender('centerGroupOrNode()');
20404
20989
  this._afterRedraw(() => {
20405
- this._mediator.execute(new CenterGroupOrNodeRequest(groupOrNodeId, animated));
20990
+ this._mediator.execute(new CenterGroupOrNodeRequest(groupOrNodeId, animated, emitCanvasChange));
20406
20991
  });
20407
20992
  }
20408
20993
  /**
20409
20994
  * Fits the canvas to the screen by adjusting the scale and position.
20410
20995
  * @param padding - paddings from the bounds of the canvas
20411
20996
  * @param animated - If true, the fit will be animated; otherwise, it will be instantaneous.
20997
+ * @param emitCanvasChange - If false, does not emit `fCanvasChange` for this programmatic move.
20412
20998
  */
20413
- fitToScreen(padding = PointExtensions.initialize(), animated = true) {
20999
+ fitToScreen(padding = PointExtensions.initialize(), animated = true, emitCanvasChange = true) {
20414
21000
  this._warnWhenCalledBeforeNodesRender('fitToScreen()');
20415
21001
  this._afterRedraw(() => {
20416
- this._mediator.execute(new FitToFlowRequest(padding, animated));
21002
+ this._mediator.execute(new FitToFlowRequest(padding, animated, emitCanvasChange));
20417
21003
  });
20418
21004
  }
20419
21005
  /**
@@ -20421,12 +21007,13 @@ class FCanvasComponent extends FCanvasBase {
20421
21007
  * This method is used to restore the canvas to its default scale and position,
20422
21008
  * allowing users to quickly return to a standard view of the canvas content.
20423
21009
  * @param animated - If true, the reset will be animated; otherwise, it will be instantaneous.
21010
+ * @param emitCanvasChange - If false, does not emit `fCanvasChange` for this programmatic move.
20424
21011
  * This is useful for providing a smooth user experience when resetting the view.
20425
21012
  */
20426
- resetScaleAndCenter(animated = true) {
21013
+ resetScaleAndCenter(animated = true, emitCanvasChange = true) {
20427
21014
  this._warnWhenCalledBeforeNodesRender('resetScaleAndCenter()');
20428
21015
  this._afterRedraw(() => {
20429
- this._mediator.execute(new ResetScaleAndCenterRequest(animated));
21016
+ this._mediator.execute(new ResetScaleAndCenterRequest(animated, emitCanvasChange));
20430
21017
  });
20431
21018
  }
20432
21019
  /**
@@ -21898,18 +22485,1041 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
21898
22485
 
21899
22486
  const F_MAGNETIC_RECTS_PROVIDERS = [FMagneticRects];
21900
22487
 
21901
- class FMinimapFlowDirective {
21902
- fMinSize = input(1000, ...(ngDevMode ? [{ debugName: "fMinSize" }] : []));
21903
- _mediator = inject(FMediator);
21904
- hostElement = inject((ElementRef)).nativeElement;
21905
- model = new FMinimapState(this.hostElement);
21906
- redraw() {
21907
- const { scale, viewBox } = this._mediator.execute(new MinimapCalculateViewportRequest(this.hostElement, this.fMinSize()));
21908
- this.model = new FMinimapState(this.hostElement, scale, viewBox);
21909
- setRectToViewBox(viewBox, this.hostElement);
21910
- }
21911
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FMinimapFlowDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
21912
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.9", type: FMinimapFlowDirective, isStandalone: true, selector: "svg[fMinimapFlow]", inputs: { fMinSize: { classPropertyName: "fMinSize", publicName: "fMinSize", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
22488
+ function mergeFlowStateConfig(config) {
22489
+ return {
22490
+ historyLimit: 50,
22491
+ selectionInHistory: true,
22492
+ canvasTransformInHistory: true,
22493
+ canvasTransformDebounce: 0,
22494
+ dropToGroup: false,
22495
+ ...config,
22496
+ };
22497
+ }
22498
+ /**
22499
+ * Resolved state-plugin configuration. Present in the injector only when
22500
+ * `withFlowState()` is installed — its absence keeps `FFlowStateController`
22501
+ * inert.
22502
+ */
22503
+ const F_FLOW_STATE_CONFIG = new InjectionToken('F_FLOW_STATE_CONFIG');
22504
+
22505
+ const EMPTY_SELECTION = Object.freeze({
22506
+ nodeIds: [],
22507
+ groupIds: [],
22508
+ connectionIds: [],
22509
+ });
22510
+ const DEFAULT_TRANSFORM = Object.freeze({
22511
+ position: undefined,
22512
+ scale: 1,
22513
+ });
22514
+ /**
22515
+ * The data store of the state plugin (`provideFFlow(withFlowState())`).
22516
+ *
22517
+ * Holds the whole graph as plain records behind the signals `nodes`,
22518
+ * `groups` and `connections` that the template renders with `@for`. Records
22519
+ * are your own shape — extend `IFStateNode`/`IFStateGroup`/`IFStateConnection`
22520
+ * with any fields and type them through `injectFlowState<MyNode>()`; the store
22521
+ * only reads the framework keys and carries the rest through untouched.
22522
+ *
22523
+ * Every mutation — its own methods or the gestures `FFlowStateController`
22524
+ * forwards into the `apply*` handlers — is ONE undoable history step: records
22525
+ * are updated immutably, so a history entry is just the previous shape
22526
+ * reference. `undo`/`redo` with `canUndo`/`canRedo` signals come built in;
22527
+ * `changes` ticks once when a standalone mutation or outer batch settles, so a
22528
+ * single effect can persist the graph. Load data with `load(...)`, take it back
22529
+ * with `snapshot()`.
22530
+ *
22531
+ * EVERY method is designed for overriding. Subclass the store, override any
22532
+ * CRUD method, any `apply*` gesture handler or any protected building block,
22533
+ * and install the subclass via `withFlowState({ stateClass: MyFlowState })` —
22534
+ * the auto-wiring and the templates then use your behavior.
22535
+ */
22536
+ class FFlowState {
22537
+ config = inject(F_FLOW_STATE_CONFIG, { optional: true });
22538
+ /**
22539
+ * Resolves the node owning a connector; installed by the controller from
22540
+ * the live registries so node removal can cascade to attached connections.
22541
+ */
22542
+ _connectorOwnerResolver = null;
22543
+ _shape = signal({
22544
+ nodes: {},
22545
+ groups: {},
22546
+ connections: {},
22547
+ selection: EMPTY_SELECTION,
22548
+ transform: DEFAULT_TRANSFORM,
22549
+ }, ...(ngDevMode ? [{ debugName: "_shape" }] : []));
22550
+ _undoStack = [];
22551
+ _redoStack = [];
22552
+ _canUndo = signal(false, ...(ngDevMode ? [{ debugName: "_canUndo" }] : []));
22553
+ _canRedo = signal(false, ...(ngDevMode ? [{ debugName: "_canRedo" }] : []));
22554
+ _changes = signal(0, ...(ngDevMode ? [{ debugName: "_changes" }] : []));
22555
+ /** Live selection when `selectionInHistory` is off (kept out of history). */
22556
+ _liveSelection = signal(EMPTY_SELECTION, ...(ngDevMode ? [{ debugName: "_liveSelection" }] : []));
22557
+ /** Live transform when `canvasTransformInHistory` is off (kept out of history). */
22558
+ _liveTransform = signal(DEFAULT_TRANSFORM, ...(ngDevMode ? [{ debugName: "_liveTransform" }] : []));
22559
+ /** Called when `undo` empties the history; the controller may reset the view. */
22560
+ _onUndoToStart = null;
22561
+ /**
22562
+ * Establishes the actual canvas transform before its first user-driven
22563
+ * change. Programmatic centering can intentionally suppress fCanvasChange,
22564
+ * so the state may still hold an unset transform while the rendered canvas
22565
+ * is already centered. This updates that baseline without history or a
22566
+ * changes() tick.
22567
+ */
22568
+ _initializeTransform(transform) {
22569
+ const next = _copyTransform(transform);
22570
+ if (!this.config?.canvasTransformInHistory) {
22571
+ if (this._liveTransform().position === undefined) {
22572
+ this._liveTransform.set(next);
22573
+ }
22574
+ return;
22575
+ }
22576
+ const shape = this._shape();
22577
+ if (shape.transform.position !== undefined) {
22578
+ return;
22579
+ }
22580
+ this._shape.set({ ...shape, transform: next });
22581
+ if (this._batchOpen && this._undoStack.length) {
22582
+ const index = this._undoStack.length - 1;
22583
+ const baseline = this._undoStack[index];
22584
+ if (baseline.transform.position === undefined) {
22585
+ this._undoStack[index] = { ...baseline, transform: _copyTransform(next) };
22586
+ }
22587
+ }
22588
+ }
22589
+ /** Open-transaction depth; commits inside a batch collapse into one step. */
22590
+ _batchDepth = 0;
22591
+ _batchOpen = false;
22592
+ /** A mutation occurred inside the current outer batch. */
22593
+ _batchDirty = false;
22594
+ // Records are memoized so a selection-only change never re-emits the graph.
22595
+ _nodesRecord = computed(() => this._shape().nodes, ...(ngDevMode ? [{ debugName: "_nodesRecord" }] : []));
22596
+ _groupsRecord = computed(() => this._shape().groups, ...(ngDevMode ? [{ debugName: "_groupsRecord" }] : []));
22597
+ _connectionsRecord = computed(() => this._shape().connections, ...(ngDevMode ? [{ debugName: "_connectionsRecord" }] : []));
22598
+ /** All nodes, re-emitted after every mutation, undo and redo. */
22599
+ nodes = computed(() => Object.values(this._nodesRecord()), ...(ngDevMode ? [{ debugName: "nodes" }] : []));
22600
+ /** All groups, re-emitted after every mutation, undo and redo. */
22601
+ groups = computed(() => Object.values(this._groupsRecord()), ...(ngDevMode ? [{ debugName: "groups" }] : []));
22602
+ /** All connections, re-emitted after every mutation, undo and redo. */
22603
+ connections = computed(() => Object.values(this._connectionsRecord()), ...(ngDevMode ? [{ debugName: "connections" }] : []));
22604
+ /** The current selection; historized only when `selectionInHistory` is on. */
22605
+ selection = computed(() => this.config?.selectionInHistory ? this._shape().selection : this._liveSelection(), ...(ngDevMode ? [{ debugName: "selection" }] : []));
22606
+ /** The current canvas transform; historized only when `canvasTransformInHistory` is on. */
22607
+ transform = computed(() => this.config?.canvasTransformInHistory ? this._shape().transform : this._liveTransform(), ...(ngDevMode ? [{ debugName: "transform" }] : []));
22608
+ /** Ticks when a standalone mutation or outer batch settles, and on `load`. */
22609
+ changes = this._changes.asReadonly();
22610
+ canUndo = this._canUndo.asReadonly();
22611
+ canRedo = this._canRedo.asReadonly();
22612
+ // ------------------------------------------------------------------
22613
+ // Data in / data out
22614
+ // ------------------------------------------------------------------
22615
+ /** Replaces the whole graph and resets the undo history. */
22616
+ load(data) {
22617
+ this._undoStack.length = 0;
22618
+ this._redoStack.length = 0;
22619
+ this._batchDirty = false;
22620
+ const transform = _copyTransform(data.transform ?? DEFAULT_TRANSFORM);
22621
+ this._liveSelection.set(EMPTY_SELECTION);
22622
+ this._liveTransform.set(transform);
22623
+ this._shape.set({
22624
+ nodes: _byId(data.nodes ?? []),
22625
+ groups: _byId(data.groups ?? []),
22626
+ connections: _byId(data.connections ?? []),
22627
+ selection: EMPTY_SELECTION,
22628
+ transform,
22629
+ });
22630
+ this._syncHistorySignals();
22631
+ this._bumpChanges();
22632
+ }
22633
+ /**
22634
+ * The whole graph as plain arrays — safe to persist. Records and their
22635
+ * geometry are copied; nested payloads stay yours by reference.
22636
+ */
22637
+ snapshot() {
22638
+ const { nodes, groups, connections } = this._shape();
22639
+ return {
22640
+ nodes: Object.values(nodes).map(_copyBox),
22641
+ groups: Object.values(groups).map(_copyBox),
22642
+ connections: Object.values(connections).map((connection) => ({ ...connection })),
22643
+ transform: _copyTransform(this.transform()),
22644
+ };
22645
+ }
22646
+ getNode(id) {
22647
+ return this._shape().nodes[id];
22648
+ }
22649
+ getGroup(id) {
22650
+ return this._shape().groups[id];
22651
+ }
22652
+ getConnection(id) {
22653
+ return this._shape().connections[id];
22654
+ }
22655
+ // ------------------------------------------------------------------
22656
+ // Mutations — each call is ONE undoable history step
22657
+ // ------------------------------------------------------------------
22658
+ addNodes(...nodes) {
22659
+ if (!nodes.length) {
22660
+ return;
22661
+ }
22662
+ const shape = this.currentShape();
22663
+ this.commit({ ...shape, nodes: { ...shape.nodes, ..._byId(nodes) } });
22664
+ }
22665
+ /** Shallow-merges the patch into the node: provided keys replace as a whole. */
22666
+ updateNode(id, patch) {
22667
+ const shape = this.currentShape();
22668
+ const existing = shape.nodes[id];
22669
+ if (!existing) {
22670
+ return;
22671
+ }
22672
+ this.commit({
22673
+ ...shape,
22674
+ nodes: { ...shape.nodes, [id]: { ...existing, ...patch, id } },
22675
+ });
22676
+ }
22677
+ /**
22678
+ * Applies new positions to known nodes and groups as ONE history step. A
22679
+ * dragged group arrives here alongside nodes, so both maps are updated.
22680
+ */
22681
+ moveNodes(positions) {
22682
+ const shape = this.currentShape();
22683
+ let nodes = shape.nodes;
22684
+ let groups = shape.groups;
22685
+ let changed = false;
22686
+ for (const { id, position } of positions) {
22687
+ if (shape.nodes[id]) {
22688
+ if (nodes === shape.nodes) {
22689
+ nodes = { ...shape.nodes };
22690
+ }
22691
+ nodes[id] = { ...nodes[id], position: { ...position } };
22692
+ changed = true;
22693
+ }
22694
+ else if (shape.groups[id]) {
22695
+ if (groups === shape.groups) {
22696
+ groups = { ...shape.groups };
22697
+ }
22698
+ groups[id] = { ...groups[id], position: { ...position } };
22699
+ changed = true;
22700
+ }
22701
+ }
22702
+ if (!changed) {
22703
+ return;
22704
+ }
22705
+ this.commit({ ...shape, nodes, groups });
22706
+ }
22707
+ /**
22708
+ * Removes nodes and, when the connector-owner resolver is available (the
22709
+ * plugin is attached to a rendered flow), every connection attached to them
22710
+ * — all as ONE history step.
22711
+ */
22712
+ removeNodes(ids) {
22713
+ this.applyRemoval({ nodeIds: ids });
22714
+ }
22715
+ addGroups(...groups) {
22716
+ if (!groups.length) {
22717
+ return;
22718
+ }
22719
+ const shape = this.currentShape();
22720
+ this.commit({ ...shape, groups: { ...shape.groups, ..._byId(groups) } });
22721
+ }
22722
+ /** Shallow-merges the patch into the group. */
22723
+ updateGroup(id, patch) {
22724
+ const shape = this.currentShape();
22725
+ const existing = shape.groups[id];
22726
+ if (!existing) {
22727
+ return;
22728
+ }
22729
+ this.commit({
22730
+ ...shape,
22731
+ groups: { ...shape.groups, [id]: { ...existing, ...patch, id } },
22732
+ });
22733
+ }
22734
+ /** Removes groups (with connection cascade and child un-parenting) as ONE step. */
22735
+ removeGroups(ids) {
22736
+ this.applyRemoval({ groupIds: ids });
22737
+ }
22738
+ addConnections(...connections) {
22739
+ if (!connections.length) {
22740
+ return;
22741
+ }
22742
+ const shape = this.currentShape();
22743
+ this.commit({
22744
+ ...shape,
22745
+ connections: { ...shape.connections, ..._byId(connections) },
22746
+ });
22747
+ }
22748
+ /** Shallow-merges the patch into the connection. */
22749
+ updateConnection(id, patch) {
22750
+ const shape = this.currentShape();
22751
+ const existing = shape.connections[id];
22752
+ if (!existing) {
22753
+ return;
22754
+ }
22755
+ this.commit({
22756
+ ...shape,
22757
+ connections: { ...shape.connections, [id]: { ...existing, ...patch, id } },
22758
+ });
22759
+ }
22760
+ removeConnections(ids) {
22761
+ this.applyRemoval({ connectionIds: ids });
22762
+ }
22763
+ /** Removes nodes (with connection cascade) and explicit connections as ONE history step. */
22764
+ removeItems(nodeIds, connectionIds) {
22765
+ this.applyRemoval({ nodeIds, connectionIds });
22766
+ }
22767
+ // ------------------------------------------------------------------
22768
+ // History
22769
+ // ------------------------------------------------------------------
22770
+ undo() {
22771
+ const previous = this._undoStack.pop();
22772
+ if (!previous) {
22773
+ return;
22774
+ }
22775
+ this._redoStack.push(this._shape());
22776
+ this._shape.set(previous);
22777
+ this._syncHistorySignals();
22778
+ this._bumpChanges();
22779
+ if (!this._canUndo()) {
22780
+ this._onUndoToStart?.();
22781
+ }
22782
+ }
22783
+ redo() {
22784
+ const next = this._redoStack.pop();
22785
+ if (!next) {
22786
+ return;
22787
+ }
22788
+ this._undoStack.push(this._shape());
22789
+ this._shape.set(next);
22790
+ this._syncHistorySignals();
22791
+ this._bumpChanges();
22792
+ }
22793
+ clearHistory() {
22794
+ this._undoStack.length = 0;
22795
+ this._redoStack.length = 0;
22796
+ this._syncHistorySignals();
22797
+ }
22798
+ // ------------------------------------------------------------------
22799
+ // Transactions — collapse several mutations into ONE undoable step
22800
+ // ------------------------------------------------------------------
22801
+ /**
22802
+ * Opens a transaction: every `commit` until the matching `endBatch` records
22803
+ * only ONE history step (the shape before the batch). Used by the controller
22804
+ * to fold the events of a single drag session (e.g. move + drop-to-group, or
22805
+ * a historized selection + move) into one undoable action. Nestable.
22806
+ */
22807
+ beginBatch() {
22808
+ this._batchDepth++;
22809
+ }
22810
+ /** Closes the transaction opened by `beginBatch`. */
22811
+ endBatch() {
22812
+ if (this._batchDepth > 0) {
22813
+ this._batchDepth--;
22814
+ }
22815
+ if (this._batchDepth === 0) {
22816
+ this._batchOpen = false;
22817
+ if (this._batchDirty) {
22818
+ this._batchDirty = false;
22819
+ this._bumpChanges();
22820
+ }
22821
+ }
22822
+ }
22823
+ /** Runs `work` inside a transaction so all its mutations are one step. */
22824
+ batch(work) {
22825
+ this.beginBatch();
22826
+ try {
22827
+ return work();
22828
+ }
22829
+ finally {
22830
+ this.endBatch();
22831
+ }
22832
+ }
22833
+ // ------------------------------------------------------------------
22834
+ // Gesture handlers — the controller forwards finished gestures here.
22835
+ // Override any of them to change what a gesture means for your data.
22836
+ // ------------------------------------------------------------------
22837
+ /** A create-connection gesture finished. Default: add unless dropped to nowhere. */
22838
+ applyCreateConnection(event) {
22839
+ if (!event.targetId) {
22840
+ return;
22841
+ }
22842
+ const connection = this.config?.connectionFactory
22843
+ ? this.config.connectionFactory(event)
22844
+ : this.createConnectionRecord(event);
22845
+ if (connection) {
22846
+ this.addConnections(connection);
22847
+ }
22848
+ }
22849
+ /** A reassign gesture finished. Default: update the moved endpoint. */
22850
+ applyReassignConnection(event) {
22851
+ if (event.endpoint === 'source' && event.nextSourceId) {
22852
+ this.updateConnection(event.connectionId, {
22853
+ sourceId: event.nextSourceId,
22854
+ });
22855
+ }
22856
+ else if (event.endpoint === 'target' && event.nextTargetId) {
22857
+ this.updateConnection(event.connectionId, {
22858
+ targetId: event.nextTargetId,
22859
+ });
22860
+ }
22861
+ }
22862
+ /** A node drag finished. Default: apply all positions as one step. */
22863
+ applyMoveNodes(event) {
22864
+ this.moveNodes(event.nodes);
22865
+ }
22866
+ /** The user requested removal of the selection. Default: remove with cascade. */
22867
+ applyDeleteSelected(event) {
22868
+ this.applyRemoval({
22869
+ nodeIds: event.nodeIds,
22870
+ groupIds: event.groupIds,
22871
+ connectionIds: event.connectionIds,
22872
+ });
22873
+ }
22874
+ /**
22875
+ * Nodes/groups were dropped into a group. Reparents them as one step when
22876
+ * `dropToGroup` is enabled; a no-op otherwise (it's off by default). This
22877
+ * only touches items that already exist — a brand-new item from a palette is
22878
+ * created by `applyCreateNode`, not here.
22879
+ */
22880
+ applyDropToGroup(event) {
22881
+ if (this.config?.dropToGroup === false) {
22882
+ return;
22883
+ }
22884
+ const shape = this.currentShape();
22885
+ let nodes = shape.nodes;
22886
+ let groups = shape.groups;
22887
+ let changed = false;
22888
+ for (const id of event.nodeIds) {
22889
+ if (shape.nodes[id]) {
22890
+ if (nodes === shape.nodes) {
22891
+ nodes = { ...shape.nodes };
22892
+ }
22893
+ nodes[id] = { ...nodes[id], parentId: event.targetGroupId };
22894
+ changed = true;
22895
+ }
22896
+ else if (shape.groups[id]) {
22897
+ if (groups === shape.groups) {
22898
+ groups = { ...shape.groups };
22899
+ }
22900
+ groups[id] = { ...groups[id], parentId: event.targetGroupId };
22901
+ changed = true;
22902
+ }
22903
+ }
22904
+ if (!changed) {
22905
+ return;
22906
+ }
22907
+ this.commit({ ...shape, nodes, groups });
22908
+ }
22909
+ /** An external item was dropped onto the canvas. Default: add a node for it. */
22910
+ applyCreateNode(event) {
22911
+ const node = this.config?.nodeFactory
22912
+ ? this.config.nodeFactory(event)
22913
+ : this.createNodeRecord(event);
22914
+ if (node) {
22915
+ this.addNodes(node);
22916
+ }
22917
+ }
22918
+ /** The flow selection changed. Historized only when `selectionInHistory` is on. */
22919
+ applySelectionChange(event) {
22920
+ const next = {
22921
+ nodeIds: [...event.nodeIds],
22922
+ groupIds: [...event.groupIds],
22923
+ connectionIds: [...event.connectionIds],
22924
+ };
22925
+ if (this.config?.selectionInHistory) {
22926
+ this.commit({ ...this.currentShape(), selection: next });
22927
+ }
22928
+ else {
22929
+ this._liveSelection.set(next);
22930
+ }
22931
+ }
22932
+ /**
22933
+ * The canvas was panned or zoomed (`fCanvasChange`). Historized as its own
22934
+ * step when `canvasTransformInHistory` is on; otherwise tracked live, out of
22935
+ * history. A no-op when the transform is unchanged, so a binding pushing the
22936
+ * current value back can't create a redundant step.
22937
+ */
22938
+ applyTransform(transform) {
22939
+ const next = _copyTransform(transform);
22940
+ if (this.config?.canvasTransformInHistory) {
22941
+ if (_isSameTransform(this.currentShape().transform, next)) {
22942
+ return;
22943
+ }
22944
+ this.commit({ ...this.currentShape(), transform: next });
22945
+ }
22946
+ else {
22947
+ if (_isSameTransform(this._liveTransform(), next)) {
22948
+ return;
22949
+ }
22950
+ this._liveTransform.set(next);
22951
+ }
22952
+ }
22953
+ /**
22954
+ * A node or group reported a new measured rect (`fNodeSizeChange` /
22955
+ * `fGroupSizeChange`) — e.g. a group auto-fitting after a child was added.
22956
+ * Folded into the CURRENT shape WITHOUT its own history step, so the resize
22957
+ * rides along with the action that triggered it (one `undo` reverts both).
22958
+ */
22959
+ applyResize(id, rect) {
22960
+ const shape = this.currentShape();
22961
+ const patch = {
22962
+ position: { x: rect.x, y: rect.y },
22963
+ size: { width: rect.width, height: rect.height },
22964
+ };
22965
+ if (shape.nodes[id]) {
22966
+ if (_isSameGeometry(shape.nodes[id], patch)) {
22967
+ return;
22968
+ }
22969
+ this.amendCurrent({
22970
+ ...shape,
22971
+ nodes: { ...shape.nodes, [id]: { ...shape.nodes[id], ...patch } },
22972
+ });
22973
+ }
22974
+ else if (shape.groups[id]) {
22975
+ if (_isSameGeometry(shape.groups[id], patch)) {
22976
+ return;
22977
+ }
22978
+ this.amendCurrent({
22979
+ ...shape,
22980
+ groups: { ...shape.groups, [id]: { ...shape.groups[id], ...patch } },
22981
+ });
22982
+ }
22983
+ }
22984
+ // ------------------------------------------------------------------
22985
+ // Overridable building blocks
22986
+ // ------------------------------------------------------------------
22987
+ /** Builds the record for a gesture-created connection. */
22988
+ createConnectionRecord(event) {
22989
+ return {
22990
+ id: generateGuid(),
22991
+ sourceId: event.sourceId,
22992
+ targetId: event.targetId,
22993
+ };
22994
+ }
22995
+ /**
22996
+ * Builds the record for an external-item drop. The item's `fData` is spread
22997
+ * onto the node, so a palette payload becomes the node's own fields. The
22998
+ * drop target nests the node only when `dropToGroup` is enabled (off by
22999
+ * default); otherwise the node lands at the top level.
23000
+ *
23001
+ * Position comes from `externalItemRect`, which is already in flow
23002
+ * coordinates (pan/zoom corrected) for every drop — over empty canvas or
23003
+ * over a node/group alike. (`dropPosition` is the raw pointer position and
23004
+ * only present on container drops, so it isn't used here.)
23005
+ */
23006
+ createNodeRecord(event) {
23007
+ return {
23008
+ ...event.data,
23009
+ id: generateGuid(),
23010
+ position: { x: event.externalItemRect.x, y: event.externalItemRect.y },
23011
+ parentId: this.config?.dropToGroup === false ? null : (event.targetContainerId ?? null),
23012
+ };
23013
+ }
23014
+ /**
23015
+ * Removes nodes, groups and connections as ONE history step: cascades the
23016
+ * connections attached to removed nodes/groups, un-parents any child that
23017
+ * pointed at a removed group, and prunes the removed ids from the selection.
23018
+ */
23019
+ applyRemoval(items) {
23020
+ const shape = this.currentShape();
23021
+ const removedNodes = new Set((items.nodeIds ?? []).filter((id) => shape.nodes[id]));
23022
+ const removedGroups = new Set((items.groupIds ?? []).filter((id) => shape.groups[id]));
23023
+ const removedConnections = new Set((items.connectionIds ?? []).filter((id) => shape.connections[id]));
23024
+ for (const id of this.cascadeConnectionIds([...removedNodes, ...removedGroups], shape)) {
23025
+ removedConnections.add(id);
23026
+ }
23027
+ if (!removedNodes.size && !removedGroups.size && !removedConnections.size) {
23028
+ return;
23029
+ }
23030
+ const nodes = _clearParent(_without(shape.nodes, removedNodes), removedGroups);
23031
+ const groups = _clearParent(_without(shape.groups, removedGroups), removedGroups);
23032
+ const connections = _without(shape.connections, removedConnections);
23033
+ const selection = _pruneSelection(shape.selection, removedNodes, removedGroups, removedConnections);
23034
+ this.commit({ nodes, groups, connections, selection, transform: shape.transform });
23035
+ if (!this.config?.selectionInHistory) {
23036
+ this._liveSelection.set(_pruneSelection(this._liveSelection(), removedNodes, removedGroups, removedConnections));
23037
+ }
23038
+ }
23039
+ /** The current shape, for custom mutations in subclasses. */
23040
+ currentShape() {
23041
+ return this._shape();
23042
+ }
23043
+ /**
23044
+ * Records the current shape into the history and applies the next one.
23045
+ * Route custom subclass mutations through here to make them undoable.
23046
+ * Inside a `beginBatch`/`endBatch` transaction only the first commit records
23047
+ * a history step, so the whole batch undoes in one go.
23048
+ */
23049
+ commit(next) {
23050
+ if (this._batchDepth === 0 || !this._batchOpen) {
23051
+ this._undoStack.push(this._shape());
23052
+ const limit = this.config?.historyLimit ?? 50;
23053
+ if (this._undoStack.length > limit) {
23054
+ this._undoStack.shift();
23055
+ }
23056
+ this._redoStack.length = 0;
23057
+ if (this._batchDepth > 0) {
23058
+ this._batchOpen = true;
23059
+ }
23060
+ }
23061
+ this._shape.set(next);
23062
+ this._syncHistorySignals();
23063
+ this._markChanged();
23064
+ }
23065
+ /**
23066
+ * Replaces the current shape WITHOUT recording a history step, so the change
23067
+ * folds into the last committed step. Used by `applyResize`.
23068
+ */
23069
+ amendCurrent(next) {
23070
+ this._shape.set(next);
23071
+ this._markChanged();
23072
+ }
23073
+ /** Connections attached to the given nodes/groups, per the connector-owner resolver. */
23074
+ cascadeConnectionIds(ownerIds, shape) {
23075
+ const resolver = this._connectorOwnerResolver;
23076
+ if (!resolver || !ownerIds.length) {
23077
+ return [];
23078
+ }
23079
+ const removed = new Set(ownerIds);
23080
+ return Object.values(shape.connections)
23081
+ .filter((connection) => {
23082
+ const sourceNode = resolver(connection.sourceId);
23083
+ const targetNode = resolver(connection.targetId);
23084
+ return ((sourceNode !== undefined && removed.has(sourceNode)) ||
23085
+ (targetNode !== undefined && removed.has(targetNode)));
23086
+ })
23087
+ .map((connection) => connection.id);
23088
+ }
23089
+ _syncHistorySignals() {
23090
+ this._canUndo.set(this._undoStack.length > 0);
23091
+ this._canRedo.set(this._redoStack.length > 0);
23092
+ }
23093
+ _markChanged() {
23094
+ if (this._batchDepth > 0) {
23095
+ this._batchDirty = true;
23096
+ return;
23097
+ }
23098
+ this._bumpChanges();
23099
+ }
23100
+ _bumpChanges() {
23101
+ this._changes.update((value) => value + 1);
23102
+ }
23103
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FFlowState, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
23104
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FFlowState });
23105
+ }
23106
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FFlowState, decorators: [{
23107
+ type: Injectable
23108
+ }] });
23109
+ function _byId(items) {
23110
+ return Object.fromEntries(items.map((item) => [item.id, item]));
23111
+ }
23112
+ function _without(records, ids) {
23113
+ if (!ids.size) {
23114
+ return records;
23115
+ }
23116
+ return Object.fromEntries(Object.entries(records).filter(([id]) => !ids.has(id)));
23117
+ }
23118
+ /** Copies a transform so the stored value can't be mutated from outside. */
23119
+ function _copyTransform(transform) {
23120
+ return {
23121
+ position: transform.position ? { x: transform.position.x, y: transform.position.y } : undefined,
23122
+ scale: transform.scale,
23123
+ };
23124
+ }
23125
+ function _isSameTransform(a, b) {
23126
+ return _isSamePoint(a.position, b.position) && a.scale === b.scale;
23127
+ }
23128
+ function _isSamePoint(a, b) {
23129
+ if (!a || !b) {
23130
+ // Both unset → same; exactly one set → different.
23131
+ return a === b;
23132
+ }
23133
+ return a.x === b.x && a.y === b.y;
23134
+ }
23135
+ /** Copies a box record with fresh geometry; nested payloads stay by reference. */
23136
+ function _copyBox(box) {
23137
+ return {
23138
+ ...box,
23139
+ position: { ...box.position },
23140
+ size: box.size ? { ...box.size } : undefined,
23141
+ };
23142
+ }
23143
+ /** Clears `parentId` on records that pointed at a removed group. */
23144
+ function _clearParent(records, removedGroups) {
23145
+ if (!removedGroups.size) {
23146
+ return records;
23147
+ }
23148
+ let next = records;
23149
+ for (const [id, record] of Object.entries(records)) {
23150
+ if (record.parentId != null && removedGroups.has(record.parentId)) {
23151
+ if (next === records) {
23152
+ next = { ...records };
23153
+ }
23154
+ next[id] = { ...record, parentId: null };
23155
+ }
23156
+ }
23157
+ return next;
23158
+ }
23159
+ /** Drops removed ids from a selection; returns the same reference if unchanged. */
23160
+ function _pruneSelection(selection, removedNodes, removedGroups, removedConnections) {
23161
+ const nodeIds = selection.nodeIds.filter((id) => !removedNodes.has(id));
23162
+ const groupIds = selection.groupIds.filter((id) => !removedGroups.has(id));
23163
+ const connectionIds = selection.connectionIds.filter((id) => !removedConnections.has(id));
23164
+ if (nodeIds.length === selection.nodeIds.length &&
23165
+ groupIds.length === selection.groupIds.length &&
23166
+ connectionIds.length === selection.connectionIds.length) {
23167
+ return selection;
23168
+ }
23169
+ return { nodeIds, groupIds, connectionIds };
23170
+ }
23171
+ function _isSameGeometry(record, patch) {
23172
+ return (record.position.x === patch.position.x &&
23173
+ record.position.y === patch.position.y &&
23174
+ record.size?.width === patch.size.width &&
23175
+ record.size?.height === patch.size.height);
23176
+ }
23177
+ /**
23178
+ * Typed accessor for the state store provided by `withFlowState()`.
23179
+ *
23180
+ * ```typescript
23181
+ * protected readonly state = injectFlowState<MyNode, MyConnection>();
23182
+ * ```
23183
+ */
23184
+ function injectFlowState() {
23185
+ return inject(FFlowState);
23186
+ }
23187
+
23188
+ /**
23189
+ * Auto-wiring between the flow's gesture events and `FFlowState` (active only
23190
+ * when `withFlowState()` is installed).
23191
+ *
23192
+ * This is what removes the handler boilerplate: every finished gesture is
23193
+ * forwarded into the state's overridable `apply*` methods — the application
23194
+ * only loads data and reads it back. Subclass `FFlowState` to change what any
23195
+ * gesture means for your data; this controller stays a thin dispatcher.
23196
+ */
23197
+ class FFlowStateController {
23198
+ _config = inject(F_FLOW_STATE_CONFIG, { optional: true });
23199
+ _state = inject(FFlowState, { optional: true });
23200
+ _store = inject(FComponentsStore);
23201
+ _browser = inject(BrowserService);
23202
+ _injector = inject(Injector);
23203
+ _disposers = [];
23204
+ _subscriptions = [];
23205
+ /** Per-node/group `sizeChange` subscriptions, keyed by id. */
23206
+ _sizeSubscriptions = new Map();
23207
+ _isWired = false;
23208
+ /** The canvas `fCanvasChange` subscription is in place. */
23209
+ _isCanvasWired = false;
23210
+ /** A state transaction is currently open (beginBatch without endBatch). */
23211
+ _batchActive = false;
23212
+ /** Inside a drag session (fDragStarted → fDragEnded). */
23213
+ _dragActive = false;
23214
+ /** Canvas transform captured at drag start, to detect a change during the drag. */
23215
+ _dragStartTransform = null;
23216
+ /** Latest canvas transform awaiting a (possibly debounced) capture. */
23217
+ _pendingTransform = null;
23218
+ _transformDebounceTimer = null;
23219
+ /** A microtask is queued to close a non-drag batch at the end of the tick. */
23220
+ _closeScheduled = false;
23221
+ /** Called once by `FFlowComponent` after content init (browser only). */
23222
+ initialize() {
23223
+ if (!this._config || !this._state || !this._browser.isBrowser()) {
23224
+ return;
23225
+ }
23226
+ this._state._connectorOwnerResolver = (connectorId) => this._resolveOwnerNode(connectorId);
23227
+ this._state._onUndoToStart = () => this._resetAndRenderFlow();
23228
+ this._wireDraggableEvents();
23229
+ this._wireCanvasEvents();
23230
+ this._wireSizeChanges();
23231
+ // The draggable directive, canvas and nodes/groups register over time;
23232
+ // re-wire on every registry change (`_wire*` are idempotent).
23233
+ this._disposers.push(this._store.nodesChanges$.listen(() => {
23234
+ this._wireDraggableEvents();
23235
+ this._wireCanvasEvents();
23236
+ this._wireSizeChanges();
23237
+ }));
23238
+ if (this._config.selectionInHistory) {
23239
+ this._wireSelectionRestore();
23240
+ }
23241
+ }
23242
+ destroy() {
23243
+ this._disposers.forEach((dispose) => dispose());
23244
+ this._disposers.length = 0;
23245
+ this._subscriptions.forEach((subscription) => subscription.unsubscribe());
23246
+ this._subscriptions.length = 0;
23247
+ this._sizeSubscriptions.forEach((subscription) => subscription.unsubscribe());
23248
+ this._sizeSubscriptions.clear();
23249
+ if (this._transformDebounceTimer !== null) {
23250
+ clearTimeout(this._transformDebounceTimer);
23251
+ this._transformDebounceTimer = null;
23252
+ }
23253
+ this._pendingTransform = null;
23254
+ this._isWired = false;
23255
+ this._isCanvasWired = false;
23256
+ this._dragActive = false;
23257
+ this._closeScheduled = false;
23258
+ this._closeBatch();
23259
+ if (this._state) {
23260
+ this._state._connectorOwnerResolver = null;
23261
+ this._state._onUndoToStart = null;
23262
+ }
23263
+ }
23264
+ _wireDraggableEvents() {
23265
+ const draggable = this._store.fDraggable;
23266
+ if (this._isWired || !draggable) {
23267
+ return;
23268
+ }
23269
+ this._isWired = true;
23270
+ const state = this._state;
23271
+ this._subscriptions.push(draggable.fCreateConnection.subscribe((event) => this._dispatch(() => state.applyCreateConnection(event))), draggable.fReassignConnection.subscribe((event) => this._dispatch(() => state.applyReassignConnection(event))), draggable.fMoveNodes.subscribe((event) => this._dispatch(() => state.applyMoveNodes(event))), draggable.fDeleteSelected.subscribe((event) => this._dispatch(() => state.applyDeleteSelected(event))), draggable.fDropToGroup.subscribe((event) => this._dispatch(() => state.applyDropToGroup(event))), draggable.fCreateNode.subscribe((event) => this._dispatch(() => state.applyCreateNode(event))), draggable.fSelectionChange.subscribe((event) => this._dispatch(() => state.applySelectionChange(event))),
23272
+ // Drag lifecycle brackets the batch across ticks: the drag-start
23273
+ // selection and the pointer-up move live in different ticks, so the
23274
+ // batch must survive the gap between them.
23275
+ draggable.fDragStarted.subscribe(() => this._onDragStarted()), draggable.fDragEnded.subscribe(() => this._onDragEnded()));
23276
+ }
23277
+ /**
23278
+ * Captures canvas pan/zoom (`fCanvasChange`) into the state. Routed through
23279
+ * `_dispatch` so a pan-drag folds into one step. Restore is binding-driven:
23280
+ * bind the canvas `[position]`/`[scale]` to `state.transform()` and undo/redo
23281
+ * flows back through the guarded input path — no imperative push needed.
23282
+ */
23283
+ _wireCanvasEvents() {
23284
+ const canvas = this._store.fCanvas;
23285
+ if (this._isCanvasWired || !canvas) {
23286
+ return;
23287
+ }
23288
+ this._isCanvasWired = true;
23289
+ this._subscriptions.push(canvas.fCanvasChange.subscribe((event) => this._onCanvasChange(event)));
23290
+ }
23291
+ /**
23292
+ * Records a canvas pan/zoom, optionally debounced (`canvasTransformDebounce`)
23293
+ * so a zoom/pan burst collapses into one step once it settles.
23294
+ */
23295
+ _onCanvasChange(event) {
23296
+ this._pendingTransform = { position: event.position, scale: event.scale };
23297
+ const debounce = this._config?.canvasTransformDebounce ?? 0;
23298
+ if (debounce <= 0) {
23299
+ if (this._transformDebounceTimer !== null) {
23300
+ clearTimeout(this._transformDebounceTimer);
23301
+ this._transformDebounceTimer = null;
23302
+ }
23303
+ this._flushCanvasChange();
23304
+ return;
23305
+ }
23306
+ if (this._transformDebounceTimer !== null) {
23307
+ clearTimeout(this._transformDebounceTimer);
23308
+ }
23309
+ this._transformDebounceTimer = setTimeout(() => {
23310
+ this._transformDebounceTimer = null;
23311
+ this._flushCanvasChange();
23312
+ }, debounce);
23313
+ }
23314
+ _flushCanvasChange() {
23315
+ const transform = this._pendingTransform;
23316
+ this._pendingTransform = null;
23317
+ if (!transform) {
23318
+ return;
23319
+ }
23320
+ this._dispatch(() => this._state.applyTransform(transform));
23321
+ }
23322
+ /**
23323
+ * Subscribes to every node's and group's `sizeChange` (a per-directive
23324
+ * output, not a draggable event) so a resize — most often a group
23325
+ * auto-fitting after a child was added — is folded into the last history
23326
+ * step via `applyResize`. Re-runs as nodes/groups register; drops removed.
23327
+ */
23328
+ _wireSizeChanges() {
23329
+ const state = this._state;
23330
+ const alive = new Set();
23331
+ for (const node of this._store.nodes.getAll()) {
23332
+ const id = node.fId();
23333
+ alive.add(id);
23334
+ if (!this._sizeSubscriptions.has(id)) {
23335
+ this._sizeSubscriptions.set(id, node.sizeChange.subscribe((rect) => state.applyResize(id, rect)));
23336
+ }
23337
+ }
23338
+ for (const [id, subscription] of this._sizeSubscriptions) {
23339
+ if (!alive.has(id)) {
23340
+ subscription.unsubscribe();
23341
+ this._sizeSubscriptions.delete(id);
23342
+ }
23343
+ }
23344
+ }
23345
+ /**
23346
+ * Folds every event of one drag session into a single undoable step.
23347
+ *
23348
+ * The events don't share a tick: the selection change is emitted at drag
23349
+ * START (before `fDragStarted`), while the move / drop-to-group land at drag
23350
+ * END (pointer-up). So the batch opens on the first event of the tick and,
23351
+ * once `fDragStarted` marks a drag in progress, stays open until `fDragEnded`
23352
+ * — spanning the whole drag. Outside a drag (e.g. a keyboard delete) it
23353
+ * closes on the next microtask, so unrelated same-tick bursts still collapse.
23354
+ * Programmatic app mutations don't run through here, so they stay separate.
23355
+ */
23356
+ _dispatch(apply) {
23357
+ this._openBatch();
23358
+ if (!this._dragActive && !this._closeScheduled) {
23359
+ this._closeScheduled = true;
23360
+ queueMicrotask(() => {
23361
+ this._closeScheduled = false;
23362
+ if (!this._dragActive) {
23363
+ this._closeBatch();
23364
+ }
23365
+ });
23366
+ }
23367
+ apply();
23368
+ }
23369
+ _onDragStarted() {
23370
+ this._dragActive = true;
23371
+ // The leading selection has usually opened the batch already; if not
23372
+ // (e.g. dragging an already-selected node), open it now.
23373
+ this._openBatch();
23374
+ this._dragStartTransform = this._readCanvasTransform();
23375
+ }
23376
+ _onDragEnded() {
23377
+ this._dragActive = false;
23378
+ // Fold any canvas transform change from this drag (auto-pan, or a mid-drag
23379
+ // zoom) into the same step. `fCanvasChange` is debounced onto a macrotask,
23380
+ // so it arrives AFTER this handler has closed the batch — read the settled
23381
+ // transform straight from the canvas now instead. The later `fCanvasChange`
23382
+ // carrying the same value is a no-op (`applyTransform` skips it).
23383
+ this._captureCanvasTransform();
23384
+ this._closeBatch();
23385
+ this._dragStartTransform = null;
23386
+ }
23387
+ /** The canvas transform right now, or `null` when there is no canvas. */
23388
+ _readCanvasTransform() {
23389
+ const canvas = this._store.fCanvas;
23390
+ if (!canvas) {
23391
+ return null;
23392
+ }
23393
+ const transform = canvas.transform;
23394
+ return {
23395
+ position: PointExtensions.sum(transform.position, transform.scaledPosition),
23396
+ scale: transform.scale,
23397
+ };
23398
+ }
23399
+ /**
23400
+ * Folds a drag's canvas transform into its step, but only when the transform
23401
+ * actually moved during the drag. A plain node drag leaves the canvas alone,
23402
+ * so we must NOT capture it — that would solidify an as-yet-unset (undefined)
23403
+ * position to the origin.
23404
+ */
23405
+ _captureCanvasTransform() {
23406
+ const state = this._state;
23407
+ const current = this._readCanvasTransform();
23408
+ const start = this._dragStartTransform;
23409
+ if (!current ||
23410
+ !start ||
23411
+ (current.position.x === start.position.x &&
23412
+ current.position.y === start.position.y &&
23413
+ current.scale === start.scale)) {
23414
+ return;
23415
+ }
23416
+ state._initializeTransform(start);
23417
+ state.applyTransform(current);
23418
+ }
23419
+ _openBatch() {
23420
+ if (!this._batchActive) {
23421
+ this._batchActive = true;
23422
+ this._state.beginBatch();
23423
+ }
23424
+ }
23425
+ _closeBatch() {
23426
+ if (this._batchActive) {
23427
+ this._batchActive = false;
23428
+ this._state.endBatch();
23429
+ }
23430
+ }
23431
+ /**
23432
+ * When selection is part of the history, `undo`/`redo` land on a shape with
23433
+ * its own selection — push it back into the flow so the highlight follows.
23434
+ * `isSelectedChanged: false` keeps this from re-emitting a selection change.
23435
+ */
23436
+ _wireSelectionRestore() {
23437
+ const state = this._state;
23438
+ const ref = effect(() => {
23439
+ const selection = state.selection();
23440
+ this._restoreSelection(selection);
23441
+ }, ...(ngDevMode ? [{ debugName: "ref", injector: this._injector }] : [{ injector: this._injector }]));
23442
+ this._disposers.push(() => ref.destroy());
23443
+ }
23444
+ _restoreSelection(selection) {
23445
+ this._store.fFlow?.select([...selection.nodeIds, ...selection.groupIds], selection.connectionIds, false);
23446
+ }
23447
+ /** Resets lifecycle flags and starts a render pass for the restored initial state. */
23448
+ _resetAndRenderFlow() {
23449
+ const flow = this._store.fFlow;
23450
+ if (!flow) {
23451
+ return;
23452
+ }
23453
+ flow.reset();
23454
+ this._store.emitNodeChanges();
23455
+ }
23456
+ _resolveOwnerNode(connectorId) {
23457
+ const connector = this._store.connectors.get(connectorId) ??
23458
+ this._store.outputs.get(connectorId) ??
23459
+ this._store.inputs.get(connectorId) ??
23460
+ this._store.outlets.get(connectorId);
23461
+ return connector?.fNodeId;
23462
+ }
23463
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FFlowStateController, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
23464
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FFlowStateController });
23465
+ }
23466
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FFlowStateController, decorators: [{
23467
+ type: Injectable
23468
+ }] });
23469
+
23470
+ /**
23471
+ * Turns on the managed graph state inside `provideFFlow(...)`.
23472
+ *
23473
+ * ```typescript
23474
+ * @Component({
23475
+ * providers: [provideFFlow(withFlowState())],
23476
+ * })
23477
+ * export class MyFlow {
23478
+ * protected readonly state = injectFlowState<MyNodeData>();
23479
+ *
23480
+ * constructor() {
23481
+ * this.state.load({ nodes: [...], connections: [...] });
23482
+ * }
23483
+ * }
23484
+ * ```
23485
+ *
23486
+ * The template renders `state.nodes()` / `state.connections()` with `@for`,
23487
+ * and that is the whole integration: finished gestures (create/reassign
23488
+ * connection, node moves, drops into groups, external-item drops, delete
23489
+ * requests) are applied to the state automatically, each as one undoable
23490
+ * step. `undo()`/`redo()` with `canUndo`/`canRedo` signals come built in;
23491
+ * `snapshot()` returns the graph as plain arrays for persistence.
23492
+ *
23493
+ * Every store behavior is overridable: subclass `FFlowState` (any CRUD
23494
+ * method, any `apply*` gesture handler, any protected building block) and
23495
+ * install it via `withFlowState({ stateClass: MyFlowState })`.
23496
+ *
23497
+ * The classic event-driven API keeps working unchanged — this plugin is for
23498
+ * apps that would rather hand the data bookkeeping to the library.
23499
+ */
23500
+ function withFlowState(config) {
23501
+ const resolved = mergeFlowStateConfig(config);
23502
+ return {
23503
+ kind: EFFlowFeatureKind.STATE,
23504
+ providers: [
23505
+ { provide: FFlowState, useClass: resolved.stateClass ?? FFlowState },
23506
+ { provide: F_FLOW_STATE_CONFIG, useValue: resolved },
23507
+ ],
23508
+ };
23509
+ }
23510
+
23511
+ class FMinimapFlowDirective {
23512
+ fMinSize = input(1000, ...(ngDevMode ? [{ debugName: "fMinSize" }] : []));
23513
+ _mediator = inject(FMediator);
23514
+ hostElement = inject((ElementRef)).nativeElement;
23515
+ model = new FMinimapState(this.hostElement);
23516
+ redraw() {
23517
+ const { scale, viewBox } = this._mediator.execute(new MinimapCalculateViewportRequest(this.hostElement, this.fMinSize()));
23518
+ this.model = new FMinimapState(this.hostElement, scale, viewBox);
23519
+ setRectToViewBox(viewBox, this.hostElement);
23520
+ }
23521
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FMinimapFlowDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
23522
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.9", type: FMinimapFlowDirective, isStandalone: true, selector: "svg[fMinimapFlow]", inputs: { fMinSize: { classPropertyName: "fMinSize", publicName: "fMinSize", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
21913
23523
  }
21914
23524
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FMinimapFlowDirective, decorators: [{
21915
23525
  type: Directive,
@@ -21924,12 +23534,7 @@ class FMinimapCanvasDirective {
21924
23534
  _elementRef = inject((ElementRef));
21925
23535
  hostElement = this._elementRef.nativeElement;
21926
23536
  redraw() {
21927
- this.clear();
21928
- const fragment = this._elementRef.nativeElement.ownerDocument.createDocumentFragment();
21929
- this._mediator.execute(new MinimapDrawNodesRequest()).forEach((x) => {
21930
- fragment.appendChild(x);
21931
- });
21932
- this.hostElement.appendChild(fragment);
23537
+ this._mediator.execute(new MinimapDrawNodesRequest(this.hostElement));
21933
23538
  }
21934
23539
  clear() {
21935
23540
  this.hostElement.replaceChildren();
@@ -21984,7 +23589,14 @@ class FMinimapComponent extends FMinimapBase {
21984
23589
  _flow = viewChild.required(FMinimapFlowDirective);
21985
23590
  _minimapView = viewChild.required(FMinimapViewDirective);
21986
23591
  fMinSize = input(1000, ...(ngDevMode ? [{ debugName: "fMinSize" }] : []));
21987
- fNodeRenderLimit = input(1500, ...(ngDevMode ? [{ debugName: "fNodeRenderLimit", transform: numberAttribute }] : [{ transform: numberAttribute }]));
23592
+ /**
23593
+ * Above this node count the minimap stops rendering node rects. The limit
23594
+ * guards against extreme graphs; since node rects are now computed from the
23595
+ * model and reused between frames (no per-frame DOM measurement), the
23596
+ * default is an order of magnitude higher than the old DOM-measured path
23597
+ * allowed.
23598
+ */
23599
+ fNodeRenderLimit = input(10000, ...(ngDevMode ? [{ debugName: "fNodeRenderLimit", transform: numberAttribute }] : [{ transform: numberAttribute }]));
21988
23600
  get state() {
21989
23601
  return this._flow().model;
21990
23602
  }
@@ -22097,6 +23709,7 @@ class FFlowComponent extends FFlowBase {
22097
23709
  _injector = inject(Injector);
22098
23710
  _flowConfig = inject(F_FLOW_CONFIG, { optional: true });
22099
23711
  _a11y = inject(FA11yController);
23712
+ _flowState = inject(FFlowStateController);
22100
23713
  fId = input(this._flowConfig?.id ?? `f-flow-${uniqueId++}`, ...(ngDevMode ? [{ debugName: "fId", alias: 'fFlowId' }] : [{
22101
23714
  alias: 'fFlowId',
22102
23715
  }]));
@@ -22119,6 +23732,7 @@ class FFlowComponent extends FFlowBase {
22119
23732
  this._listenNodesChanges();
22120
23733
  this._listenConnectionsChanges();
22121
23734
  this._a11y.initialize();
23735
+ this._flowState.initialize();
22122
23736
  this._warnWhenHostHasNoHeight();
22123
23737
  }
22124
23738
  /**
@@ -22223,6 +23837,7 @@ class FFlowComponent extends FFlowBase {
22223
23837
  }
22224
23838
  ngOnDestroy() {
22225
23839
  this._a11y.destroy();
23840
+ this._flowState.destroy();
22226
23841
  this._mediator.execute(new RemoveFlowFromStoreRequest(this));
22227
23842
  }
22228
23843
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FFlowComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
@@ -22237,6 +23852,7 @@ class FFlowComponent extends FFlowBase {
22237
23852
  ...F_REFLOW_PROVIDERS,
22238
23853
  FA11yAnnouncer,
22239
23854
  FA11yController,
23855
+ FFlowStateController,
22240
23856
  { provide: F_FLOW, useExisting: FFlowComponent },
22241
23857
  ], usesInheritance: true, ngImport: i0, template: "<ng-container>\n <ng-content select=\"[fDefinitions]\"/>\n\n <ng-content select=\"f-background\"/>\n\n <ng-content select=\"f-line-alignment\"/>\n\n <ng-content select=\"f-canvas\"/>\n\n <ng-content select=\"f-selection-area\"/>\n\n <ng-content/>\n</ng-container>\n", styles: [":host{display:block;position:relative;width:100%;height:100%;overflow:hidden;pointer-events:all;-webkit-user-select:none;user-select:none;touch-action:none}:host:focus,:host:focus-visible{outline:2px solid transparent}:host(.f-dragging) ::ng-deep .f-connection .f-connection-group,:host(.f-dragging) ::ng-deep .f-connection .f-connection-content,:host(.f-dragging) ::ng-deep .f-connection svg *,:host(.f-connections-dragging) ::ng-deep .f-connection .f-connection-group,:host(.f-connections-dragging) ::ng-deep .f-connection .f-connection-content,:host(.f-connections-dragging) ::ng-deep .f-connection svg *{pointer-events:none!important}::ng-deep .f-connection-content{position:absolute;left:0;top:0;inline-size:max-content;pointer-events:all;transform-origin:50% 50%}::ng-deep .f-node,::ng-deep .f-group{position:absolute!important;transform-origin:center;-webkit-user-select:none;user-select:none;pointer-events:all;left:0!important;top:0!important;box-sizing:border-box}::ng-deep .f-group{z-index:1}::ng-deep .f-connection-content{z-index:3}::ng-deep .f-node{z-index:4}.hidden{opacity:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
22242
23858
  }
@@ -22256,6 +23872,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
22256
23872
  ...F_REFLOW_PROVIDERS,
22257
23873
  FA11yAnnouncer,
22258
23874
  FA11yController,
23875
+ FFlowStateController,
22259
23876
  { provide: F_FLOW, useExisting: FFlowComponent },
22260
23877
  ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container>\n <ng-content select=\"[fDefinitions]\"/>\n\n <ng-content select=\"f-background\"/>\n\n <ng-content select=\"f-line-alignment\"/>\n\n <ng-content select=\"f-canvas\"/>\n\n <ng-content select=\"f-selection-area\"/>\n\n <ng-content/>\n</ng-container>\n", styles: [":host{display:block;position:relative;width:100%;height:100%;overflow:hidden;pointer-events:all;-webkit-user-select:none;user-select:none;touch-action:none}:host:focus,:host:focus-visible{outline:2px solid transparent}:host(.f-dragging) ::ng-deep .f-connection .f-connection-group,:host(.f-dragging) ::ng-deep .f-connection .f-connection-content,:host(.f-dragging) ::ng-deep .f-connection svg *,:host(.f-connections-dragging) ::ng-deep .f-connection .f-connection-group,:host(.f-connections-dragging) ::ng-deep .f-connection .f-connection-content,:host(.f-connections-dragging) ::ng-deep .f-connection svg *{pointer-events:none!important}::ng-deep .f-connection-content{position:absolute;left:0;top:0;inline-size:max-content;pointer-events:all;transform-origin:50% 50%}::ng-deep .f-node,::ng-deep .f-group{position:absolute!important;transform-origin:center;-webkit-user-select:none;user-select:none;pointer-events:all;left:0!important;top:0!important;box-sizing:border-box}::ng-deep .f-group{z-index:1}::ng-deep .f-connection-content{z-index:3}::ng-deep .f-node{z-index:4}.hidden{opacity:0}\n"] }]
22261
23878
  }], propDecorators: { fId: [{ type: i0.Input, args: [{ isSignal: true, alias: "fFlowId", required: false }] }], fCache: [{ type: i0.Input, args: [{ isSignal: true, alias: "fCache", required: false }] }], fNodesRendered: [{ type: i0.Output, args: ["fNodesRendered"] }], fFullRendered: [{ type: i0.Output, args: ["fFullRendered"] }], fLoaded: [{ type: i0.Output, args: ["fLoaded"] }] } });
@@ -22693,5 +24310,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
22693
24310
  * Generated bundle index. Do not edit.
22694
24311
  */
22695
24312
 
22696
- export { AddCanvasToStore, AddCanvasToStoreRequest, AddConnectionForCreateToStore, AddConnectionForCreateToStoreRequest, AddConnectionMarkerToStore, AddConnectionMarkerToStoreRequest, AddConnectionToStore, AddConnectionToStoreRequest, AddConnectorToStore, AddConnectorToStoreRequest, AddDndToStore, AddDndToStoreRequest, AddFlowToStore, AddFlowToStoreRequest, AddNodeToStore, AddNodeToStoreRequest, AddPatternToBackground, AddPatternToBackgroundRequest, AddSnapConnectionToStore, AddSnapConnectionToStoreRequest, ApplyChildResizeConstraints, ApplyChildResizeConstraintsRequest, ApplyConnectionRender, ApplyConnectionRenderRequest, ApplyConnectionWorkerResult, ApplyConnectionWorkerResultRequest, ApplyParentResizeConstraints, ApplyParentResizeConstraintsRequest, AttachDragNodeHandlerFromSelection, AttachDragNodeHandlerFromSelectionRequest, AttachResizeConnectionDragHandlersToNode, AttachResizeConnectionDragHandlersToNodeRequest, AttachSoftParentConnectionDragHandlersToNode, AttachSoftParentConnectionDragHandlersToNodeRequest, AttachSourceConnectionDragHandlersToNode, AttachSourceConnectionDragHandlersToNodeRequest, AttachTargetConnectionDragHandlersToNode, AttachTargetConnectionDragHandlersToNodeRequest, BuildConnectionLine, BuildConnectionLineRequest, BuildConnectionWorkerBatch, BuildConnectionWorkerBatchRequest, BuildConnectionWorkerPayloadItem, BuildConnectionWorkerPayloadItemRequest, BuildDragNodeConstraints, BuildDragNodeConstraintsRequest, CALCULATABLE_SIDES, COMMON_PROVIDERS, CONNECTABLE_SIDE_EPSILON, CREATE_MOVE_NODE_DRAG_MODEL_FROM_SELECTION_PROVIDERS, CalculateAdaptiveCurveData, CalculateBezierCurveData, CalculateChangedRectFromDifference, CalculateChangedRectFromDifferenceRequest, CalculateClosestConnector, CalculateClosestConnectorRequest, CalculateConnectableSideByConnectedPositions, CalculateConnectableSideByConnectedPositionsRequest, CalculateConnectableSideByInternalPosition, CalculateConnectableSideByInternalPositionRequest, CalculateConnectionsState, CalculateConnectionsStateRequest, CalculateConnectorsConnectableSides, CalculateConnectorsConnectableSidesRequest, CalculateDirectChildrenUnionRect, CalculateDirectChildrenUnionRectRequest, CalculateFlowPointFromMinimapPoint, CalculateFlowPointFromMinimapPointRequest, CalculateFlowState, CalculateFlowStateRequest, CalculateInputConnections, CalculateInputConnectionsRequest, CalculateNodesBoundingBox, CalculateNodesBoundingBoxNormalizedPosition, CalculateNodesBoundingBoxNormalizedPositionRequest, CalculateNodesBoundingBoxRequest, CalculateNodesState, CalculateNodesStateRequest, CalculateOutputConnections, CalculateOutputConnectionsRequest, CalculateResizeLimits, CalculateResizeLimitsRequest, CalculateSegmentLineData, CalculateSelectableItems, CalculateSelectableItemsRequest, CalculateSourceConnectorsToConnect, CalculateSourceConnectorsToConnectRequest, CalculateStraightLineData, CalculateTargetConnectorsToConnect, CalculateTargetConnectorsToConnectRequest, CenterBasedDeltaCalculator, CenterGroupOrNode, CenterGroupOrNodeRequest, CenterOfMassSelectionStrategy, ChainPushCollisionResolver, ClearSelection, ClearSelectionRequest, CompleteConnectionRedraw, CompleteConnectionRedrawRequest, ConnectedSubgraphScopeFilter, ConnectionBehaviourBuilder, ConnectionBehaviourBuilderRequest, ConnectionContentLayoutEngine, ConnectionLineBuilder, ConnectionLineBuilderRequest, ConnectionRedrawState, ConnectionWorkerState, CreateConnectionCreateDragHandler, CreateConnectionCreateDragHandlerRequest, CreateConnectionFinalize, CreateConnectionFinalizeRequest, CreateConnectionFromConnectorPreparation, CreateConnectionFromConnectorPreparationRequest, CreateConnectionFromOutletPreparation, CreateConnectionFromOutletPreparationRequest, CreateConnectionFromOutputPreparation, CreateConnectionFromOutputPreparationRequest, CreateConnectionHandler, CreateConnectionMarkers, CreateConnectionMarkersRequest, CreateConnectionPreparation, CreateConnectionPreparationRequest, CreateDragNodeHandler, CreateDragNodeHandlerRequest, CreateDragNodeHierarchy, CreateDragNodeHierarchyRequest, DRAG_AND_DROP_COMMON_PROVIDERS, DRAG_AUTO_PAN_PROVIDERS, DRAG_CANVAS_PROVIDERS, DRAG_CONNECTIONS_PROVIDERS, DRAG_DROP_TO_GROUP_PROVIDERS, DRAG_EXTERNAL_ITEM_HANDLER_KIND, DRAG_EXTERNAL_ITEM_HANDLER_TYPE, DRAG_EXTERNAL_ITEM_PROVIDERS, DRAG_MINIMAP_HANDLER_KIND, DRAG_MINIMAP_HANDLER_TYPE, DRAG_MINIMAP_PROVIDERS, DRAG_NODE_HANDLER_KIND, DRAG_NODE_HANDLER_TYPE, DRAG_SELECTION_AREA_PROVIDERS, DRAG_SELECT_BY_POINTER_PROVIDERS, DeltaClamp, Deprecated, DetectConnectionsUnderDragNode, DetectConnectionsUnderDragNodeRequest, DisableConnectionWorker, DisableConnectionWorkerRequest, DownstreamConnectionsSelectionStrategy, DragAndDropBase, DragCanvasFinalize, DragCanvasFinalizeRequest, DragCanvasHandler, DragCanvasPreparation, DragCanvasPreparationRequest, DragConnectionWaypointFinalize, DragConnectionWaypointFinalizeRequest, DragConnectionWaypointHandler, DragConnectionWaypointPreparation, DragConnectionWaypointPreparationRequest, DragExternalItemCreatePlaceholder, DragExternalItemCreatePlaceholderRequest, DragExternalItemCreatePreview, DragExternalItemCreatePreviewRequest, DragExternalItemFinalize, DragExternalItemFinalizeRequest, DragExternalItemHandler, DragExternalItemPreparation, DragExternalItemPreparationRequest, DragHandlerBase, DragHandlerInjector, DragMinimapFinalize, DragMinimapFinalizeRequest, DragMinimapHandler, DragMinimapPreparation, DragMinimapPreparationRequest, DragNodeConnectionBothSidesHandler, DragNodeConnectionHandlerBase, DragNodeConnectionSourceHandler, DragNodeConnectionTargetHandler, DragNodeDeltaConstraints, DragNodeFinalize, DragNodeFinalizeRequest, DragNodeHandler, DragNodeHierarchy, DragNodeItemHandler, DragNodePreparation, DragNodePreparationRequest, DropToGroupFinalize, DropToGroupFinalizeRequest, DropToGroupHandler, DropToGroupPreparation, DropToGroupPreparationRequest, ECanvasRedrawContext, EFCanvasLayer, EFConnectableSide, EFConnectionBehavior, EFConnectionConnectableSide, EFConnectionType, EFFlowFeatureKind, EFLayoutDirection, EFLayoutMode, EFMarkerType, EFReflowAxis, EFReflowCollision, EFReflowDeltaSource, EFReflowMode, EFReflowScope, EFResizeHandleType, EFZoomDirection, EMPTY_REFLOW_PLAN, EdgeBasedDeltaCalculator, EmitConnectionsChanges, EmitConnectionsChangesRequest, EmitEndDragSequenceEvent, EmitEndDragSequenceEventRequest, EmitSelectionChangeEvent, EmitSelectionChangeEventRequest, EmitStartDragSequenceEvent, EmitStartDragSequenceEventRequest, EnsureConnectionWorker, EnsureConnectionWorkerRequest, EventExtensions, ExternalRectConstraint, FA11yAnnouncer, FA11yController, FAutoPan, FAutoPanBase, FBackgroundBase, FBackgroundComponent, FCache, FCacheConnector, FCacheConnectorKeyFactory, FCacheNode, FCanvasBase, FCanvasChangeEvent, FCanvasComponent, FChannel, FChannelHub, FCirclePatternComponent, FClickConnectFlow, FComponentsStore, FConnectionBase, FConnectionComponent, FConnectionComponentsParent, FConnectionContent, FConnectionContentBase, FConnectionDragHandleBase, FConnectionDragHandleEnd, FConnectionDragHandleStart, FConnectionForCreateComponent, FConnectionGradient, FConnectionGradientBase, FConnectionGradientRenderer, FConnectionGradientRendererBase, FConnectionMarker, FConnectionMarkerArrow, FConnectionMarkerBase, FConnectionMarkerCircle, FConnectionMarkerRegistry, FConnectionPath, FConnectionPathBase, FConnectionRegistry, FConnectionSelection, FConnectionSelectionBase, FConnectionWaypoints, FConnectionWaypointsBase, FConnectionWaypointsChangedEvent, FConnectorBase, FConnectorDirective, FConnectorRegistry, FControlSchemeController, FCreateConnectionEvent, FCreateConnectionSession, FCreateNodeEvent, FDeleteSelectedEvent, FDragBlockerDirective, FDragExternalItemStartEventData, FDragHandleDirective, FDragHandlerResult, FDragNodeStartEventData, FDragStartedEvent, FDraggableBase, FDraggableDataContext, FDraggableDirective, FDropToGroupEvent, FExternalItem, FExternalItemBase, FExternalItemPlaceholder, FExternalItemPreview, FExternalItemService, FFlowBase, FFlowComponent, FFlowModule, FGroupDirective, FIdRegistryBase, FLayoutController, FLayoutEngine, FLineAlignmentComponent, FMagneticLines, FMagneticLinesBase, FMagneticRects, FMagneticRectsBase, FMinimapBase, FMinimapCanvasDirective, FMinimapComponent, FMinimapFlowDirective, FMinimapState, FMinimapViewDirective, FMoveNodesEvent, FNodeBase, FNodeConnectionsIntersectionEvent, FNodeDirective, FNodeInputBase, FNodeInputDirective, FNodeIntersectedWithConnections, FNodeOutletBase, FNodeOutletDirective, FNodeOutputBase, FNodeOutputDirective, FNodeRegistry, FReassignConnectionEvent, FRectPatternComponent, FReflowBaselineTracker, FReflowController, FReflowCycleGuard, FReflowIgnore, FReflowIgnoreRegistry, FReflowOrchestrator, FReflowPlanner, FResizeChannel, FResizeHandleDirective, FResizeNodeStartEventData, FRotateHandleDirective, FRotateNodeStartEventData, FSelectionArea, FSelectionAreaBase, FSelectionChangeEvent, FSingleRegistryBase, FSnapConnectionComponent, FSourceConnectorBase, FVirtualFor, FZoomBase, FZoomDirective, F_A11Y_CONFIG, F_AUTO_PAN_PROVIDERS, F_BACKGROUND, F_BACKGROUND_FEATURES, F_BACKGROUND_PATTERN, F_BACKGROUND_PROVIDERS, F_CACHE_FEATURES, F_CACHE_OPTIONS, F_CANVAS, F_CANVAS_CONFIG, F_CANVAS_FEATURES, F_CANVAS_PROVIDERS, F_CONNECTION_BUILDERS, F_CONNECTION_COMPONENTS_PARENT, F_CONNECTION_CONTENT, F_CONNECTION_DRAG_HANDLE_END, F_CONNECTION_DRAG_HANDLE_START, F_CONNECTION_FEATURES, F_CONNECTION_FLOW, F_CONNECTION_GRADIENT, F_CONNECTION_IMPORTS_EXPORTS, F_CONNECTION_MARKER, F_CONNECTION_PATH, F_CONNECTION_PROVIDERS, F_CONNECTION_SELECTION, F_CONNECTION_WAYPOINTS, F_CONNECTOR, F_CONNECTORS_FEATURES, F_CONNECTORS_PROVIDERS, F_CONTROL_SCHEME_CONFIG, F_CSS_CLASS, F_DEFAULT_A11Y_CONFIG, F_DEFAULT_A11Y_KEYS, F_DEFAULT_A11Y_MESSAGES, F_DEFAULT_CONTROL_SCHEME, F_DEFAULT_LAYER_ORDER, F_DRAGGABLE_FEATURES, F_DRAGGABLE_PROVIDERS, F_DRAG_SELECT_CONTROL_SCHEME, F_EXTERNAL_ITEM, F_EXTERNAL_ITEM_PROVIDERS, F_FLOW, F_FLOW_CONFIG, F_FLOW_FEATURES, F_FLOW_PROVIDERS, F_LAYOUT, F_LAYOUT_OPTIONS, F_LINE_ALIGNMENT_PROVIDERS, F_MAGNETIC_LINES, F_MAGNETIC_LINES_PROVIDERS, F_MAGNETIC_RECTS, F_MAGNETIC_RECTS_PROVIDERS, F_MINIMAP_BASE, F_MINIMAP_FEATURES, F_MINIMAP_PROVIDERS, F_NODE, F_NODE_FEATURES, F_NODE_INPUT, F_NODE_OUTLET, F_NODE_OUTPUT, F_NODE_PROVIDERS, F_REFLOW_CONFIG, F_REFLOW_PROVIDERS, F_SCROLL_PAN_CONTROL_SCHEME, F_SELECTED_CLASS, F_SELECTION_AREA_PROVIDERS, F_SELECTION_FEATURES, F_STORAGE_PROVIDERS, F_VIRTUAL_FOR_PROVIDERS, F_ZOOM, F_ZOOM_FEATURES, F_ZOOM_PROVIDERS, FindConnectableConnectorUsingPriorityAndPosition, FindConnectableConnectorUsingPriorityAndPositionRequest, FitToChildNodesAndGroups, FitToChildNodesAndGroupsRequest, FitToFlow, FitToFlowRequest, GET_FLOW_STATE_PROVIDERS, GetCachedFCacheRect, GetCachedFCacheRectRequest, GetChildNodeIds, GetChildNodeIdsRequest, GetConnectorRectReference, GetConnectorRectReferenceRequest, GetCurrentSelection, GetCurrentSelectionRequest, GetDeepChildrenNodesAndGroups, GetDeepChildrenNodesAndGroupsRequest, GetFlow, GetFlowRequest, GetNodePadding, GetNodePaddingRequest, GetNormalizedConnectorRect, GetNormalizedConnectorRectRequest, GetNormalizedElementRect, GetNormalizedElementRectRequest, GetNormalizedParentNodeRect, GetNormalizedParentNodeRectRequest, GetNormalizedPoint, GetNormalizedPointRequest, GetParentNodes, GetParentNodesRequest, GlobalScopeFilter, GridSnapper, GroupScopeFilter, HandleConnectionWorkerMessage, HandleConnectionWorkerMessageRequest, IMouseEvent, INSTANCES, IPointerEvent, IPointerUpEvent, ITouchDownEvent, ITouchMoveEvent, InitializeDragSequence, InitializeDragSequenceRequest, InputCanvasPosition, InputCanvasPositionRequest, InputCanvasScale, InputCanvasScaleRequest, InvalidateFCacheNode, InvalidateFCacheNodeRequest, IsArrayHasParentNode, IsArrayHasParentNodeRequest, IsConnectionRedrawCurrent, IsConnectionRedrawCurrentRequest, IsConnectionWorkerEnabled, IsConnectionWorkerEnabledRequest, IsDragStarted, IsDragStartedRequest, ListenConnectionsChanges, ListenConnectionsChangesRequest, ListenNodesChanges, ListenNodesChangesRequest, ListenTransformChanges, ListenTransformChangesRequest, LogExecutionTime, MOUSE_EVENT_IGNORE_TIME, MagneticLineElement, MagneticLineRenderer, MagneticLinesHandler, MagneticLinesPreparation, MagneticLinesPreparationRequest, MagneticRectElement, MagneticRectsHandler, MagneticRectsPreparation, MagneticRectsPreparationRequest, MagneticRectsRenderer, MarkConnectableConnectors, MarkConnectableConnectorsRequest, MarkConnectionConnectorsAsConnected, MarkConnectionConnectorsAsConnectedRequest, MinimapCalculateViewRect, MinimapCalculateViewRectRequest, MinimapCalculateViewport, MinimapCalculateViewportRequest, MinimapDrawNodes, MinimapDrawNodesRequest, MoveFrontElementsBeforeTargetElement, MoveFrontElementsBeforeTargetElementRequest, NODE_PROVIDERS, NODE_RESIZE_PROVIDERS, NODE_ROTATE_PROVIDERS, NotifyFullRendered, NotifyFullRenderedRequest, NotifyNodesRendered, NotifyNodesRenderedRequest, NotifyTransformChanged, NotifyTransformChangedRequest, OnPointerMove, OnPointerMoveRequest, PINCH_TO_ZOOM_PROVIDERS, PinchToZoomFinalize, PinchToZoomFinalizeRequest, PinchToZoomHandler, PinchToZoomPreparation, PinchToZoomPreparationRequest, Polyline, PolylineContentAlign, PolylineContentPlace, PolylineSampler, PrepareDragSequence, PrepareDragSequenceRequest, PreventDefaultIsExternalItem, PreventDefaultIsExternalItemRequest, QueueConnectionRedraw, QueueConnectionRedrawRequest, QueueConnectionRedrawState, RESIZE_DIRECTIONS, RESIZE_NODE_HANDLER_KIND, RESIZE_NODE_HANDLER_TYPE, ROTATE_NODE_HANDLER_KIND, ROTATE_NODE_HANDLER_TYPE, ReadNodeBoundsWithPaddings, ReadNodeBoundsWithPaddingsRequest, ReadNodeBoundsWithPaddingsResponse, ReassignConnectionFinalize, ReassignConnectionFinalizeRequest, ReassignConnectionHandler, ReassignConnectionPreparation, ReassignConnectionPreparationRequest, ReassignConnectionSourceHandler, ReassignConnectionTargetHandler, RedrawCanvasWithAnimation, RedrawCanvasWithAnimationRequest, RedrawConnections, RedrawConnectionsRequest, RegisterFCacheConnector, RegisterFCacheConnectorRequest, RegisterFCacheNode, RegisterFCacheNodeRequest, RegisterPluginInstance, RegisterPluginInstanceRequest, RemoveCanvasFromStore, RemoveCanvasFromStoreRequest, RemoveConnectionForCreateFromStore, RemoveConnectionForCreateFromStoreRequest, RemoveConnectionFromStore, RemoveConnectionFromStoreRequest, RemoveConnectionMarkerFromStore, RemoveConnectionMarkerFromStoreRequest, RemoveConnectionWaypoint, RemoveConnectionWaypointRequest, RemoveConnectorFromStore, RemoveConnectorFromStoreRequest, RemoveDndFromStore, RemoveDndFromStoreRequest, RemoveFlowFromStore, RemoveFlowFromStoreRequest, RemoveNodeFromStore, RemoveNodeFromStoreRequest, RemovePluginInstance, RemovePluginInstanceRequest, RemoveSnapConnectionFromStore, RemoveSnapConnectionFromStoreRequest, RenderConnection, RenderConnectionFromGeometry, RenderConnectionFromGeometryRequest, RenderConnectionRequest, RenderConnectionWithLine, RenderConnectionWithLineRequest, RenderLifecycleState, ResetConnectionWorkerRuntime, ResetConnectionWorkerRuntimeRequest, ResetRenderLifecycle, ResetRenderLifecycleRequest, ResetScale, ResetScaleAndCenter, ResetScaleAndCenterRequest, ResetScaleRequest, ResetZoom, ResetZoomRequest, ResizeNodeConnectionBothSidesHandler, ResizeNodeConnectionHandlerBase, ResizeNodeConnectionSourceHandler, ResizeNodeConnectionTargetHandler, ResizeNodeFinalize, ResizeNodeFinalizeRequest, ResizeNodeHandler, ResizeNodePreparation, ResizeNodePreparationRequest, ResolveConnectableOutputForOutlet, ResolveConnectableOutputForOutletRequest, ResolveConnectionEndpointRect, ResolveConnectionEndpointRectRequest, ResolveConnectionEndpointRotationContext, ResolveConnectionEndpointRotationContextRequest, ResolveConnectionEndpoints, ResolveConnectionEndpointsRequest, ResolveConnectionGeometry, ResolveConnectionGeometryRequest, RotateNodeFinalize, RotateNodeFinalizeRequest, RotateNodeHandler, RotateNodePreparation, RotateNodePreparationRequest, RunAutoPanFrame, RunAutoPanFrameRequest, RunConnectionRedrawSlice, RunConnectionRedrawSliceRequest, RunConnectionWorker, RunConnectionWorkerBatch, RunConnectionWorkerBatchRequest, RunConnectionWorkerRequest, RunDevDiagnostics, RunDevDiagnosticsRequest, ScheduleAutoPanFrame, ScheduleAutoPanFrameRequest, ScrollCanvas, ScrollCanvasRequest, Select, SelectAll, SelectAllRequest, SelectAndUpdateNodeLayer, SelectAndUpdateNodeLayerRequest, SelectByPointer, SelectByPointerRequest, SelectRequest, SelectionAreaFinalize, SelectionAreaFinalizeRequest, SelectionAreaHandler, SelectionAreaPreparation, SelectionAreaPreparationRequest, SetBackgroundTransform, SetBackgroundTransformRequest, SetFCacheConnectorRect, SetFCacheConnectorRectRequest, SetFCacheNodeRect, SetFCacheNodeRectRequest, SetZoom, SetZoomRequest, ShouldUseConnectionWorker, ShouldUseConnectionWorkerRequest, SortDropCandidatesByLayer, SortDropCandidatesByLayerRequest, SortItemLayers, SortItemLayersRequest, SortItemsByParent, SortItemsByParentRequest, SortNodeLayers, SortNodeLayersRequest, StartConnectionRedraw, StartConnectionRedrawRequest, StartConnectionWorkerRedraw, StartConnectionWorkerRedrawRequest, StopAutoPan, StopAutoPanRequest, StopCollisionResolver, UnmarkConnectableConnectors, UnmarkConnectableConnectorsRequest, UnregisterFCacheConnector, UnregisterFCacheConnectorRequest, UnregisterFCacheNode, UnregisterFCacheNodeRequest, UpdateFCacheRectByElement, UpdateFCacheRectByElementRequest, UpdateItemAndChildrenLayers, UpdateItemAndChildrenLayersRequest, UpdateNodeWhenStateOrSizeChanged, UpdateNodeWhenStateOrSizeChangedRequest, UpdateScale, UpdateScaleRequest, WaitForConnectionsRendered, WaitForConnectionsRenderedRequest, XRangeSelectionStrategy, afterNextPaint, buildConnectionAnchors, buildCornerMidPointsAndApplyOffsets, calculateAutoPanAxisDelta, calculateAutoPanDelta, calculateCenterBetweenPoints, calculateCurveCandidates, calculateDifferenceAfterRotation, calculateMagneticGuides, calculateMagneticRects, calculatePointerInFlow, calculatePolylineCandidates, calculatePositionAfterRotation, castToConnectorType, coerceMarkerType, computeEdgeDeltas, createConnectionDomIdentifier, createConnectionSelectionDomIdentifier, createConnectionWorkerUrl, createGradientDomIdentifier, createGradientDomUrl, createMultiCubicPath, createSVGElement, createSegmentLinePath, cubicBezierAtT, debounceAnimationFrame, debounceMicrotask, debounceTime, defaultEventTrigger, determineSide, expandRectByOverflow, fDiagnosticMessage, fInstanceKey, fProvideCache, fSuppressDevWarnings, fWarnOnce, filterConnectableTargets, findExistingWaypoint, findSourceConnector, findSpatialNeighbor, findTargetConnector, findWaypointCandidate, fixedCenterBehavior, fixedOutboundBehavior, floatingBehavior, getAllSourceConnectors, getAllTargetConnectors, getExternalItemHost, infinityMinMax, isCalculateMode, isConnectionWorkerRuntimeSupported, isConnector, isDragBlocker, isDragExternalItemHandler, isDragHandleEnd, isDragHandleStart, isDragMinimapHandler, isDragNodeHandler, isExternalItem, isFDevMode, isMobile, isNode, isNodeOutlet, isNodeOutput, isOnFlowBackground, isOutletConnector, isPointerInsidePoint, isPointerInsideStartOrEndDragHandles, isResizeNodeHandler, isRotateHandle, isRotateNodeHandler, isSourceConnector, isTargetConnector, isValidEventTrigger, mergeA11yConfig, mergeControlSchemeConfig, mergeFCanvasConfig, mergeLayoutNodes, mergePointChains, mergeReflowConfig, middleButtonEventTrigger, mixinChangeSelection, mixinChangeVisibility, normalizeFlowLayoutData, normalizePolyline, notifyOnStart, pickWaypoint, primaryButtonEventTrigger, provideFFlow, provideFLayout, rebaseAutoPanPointerDownPosition, rectFromPoint, requireSourceConnector, requireTargetConnector, resolveAutoPanMode, resolveConnectionWorkerRuntime, resolveLayerOrder, revokeConnectionWorkerUrl, sampleCubicBezierUniform, sampleMultiCubicUniform, stringAttribute, takeOne, transitionEnd, withA11y, withConnectionFlow, withControlScheme, withFCanvas, withReflowOnResize, withinSnapThreshold };
24313
+ export { AddCanvasToStore, AddCanvasToStoreRequest, AddConnectionForCreateToStore, AddConnectionForCreateToStoreRequest, AddConnectionMarkerToStore, AddConnectionMarkerToStoreRequest, AddConnectionToStore, AddConnectionToStoreRequest, AddConnectorToStore, AddConnectorToStoreRequest, AddDndToStore, AddDndToStoreRequest, AddFlowToStore, AddFlowToStoreRequest, AddNodeToStore, AddNodeToStoreRequest, AddPatternToBackground, AddPatternToBackgroundRequest, AddSnapConnectionToStore, AddSnapConnectionToStoreRequest, ApplyChildResizeConstraints, ApplyChildResizeConstraintsRequest, ApplyConnectionRender, ApplyConnectionRenderRequest, ApplyConnectionWorkerResult, ApplyConnectionWorkerResultRequest, ApplyParentResizeConstraints, ApplyParentResizeConstraintsRequest, AttachDragNodeHandlerFromSelection, AttachDragNodeHandlerFromSelectionRequest, AttachResizeConnectionDragHandlersToNode, AttachResizeConnectionDragHandlersToNodeRequest, AttachSoftParentConnectionDragHandlersToNode, AttachSoftParentConnectionDragHandlersToNodeRequest, AttachSourceConnectionDragHandlersToNode, AttachSourceConnectionDragHandlersToNodeRequest, AttachTargetConnectionDragHandlersToNode, AttachTargetConnectionDragHandlersToNodeRequest, BuildConnectionLine, BuildConnectionLineRequest, BuildConnectionWorkerBatch, BuildConnectionWorkerBatchRequest, BuildConnectionWorkerPayloadItem, BuildConnectionWorkerPayloadItemRequest, BuildDragNodeConstraints, BuildDragNodeConstraintsRequest, CALCULATABLE_SIDES, COMMON_PROVIDERS, CONNECTABLE_SIDE_EPSILON, CREATE_MOVE_NODE_DRAG_MODEL_FROM_SELECTION_PROVIDERS, CalculateAdaptiveCurveData, CalculateBezierCurveData, CalculateChangedRectFromDifference, CalculateChangedRectFromDifferenceRequest, CalculateClosestConnector, CalculateClosestConnectorRequest, CalculateConnectableSideByConnectedPositions, CalculateConnectableSideByConnectedPositionsRequest, CalculateConnectableSideByInternalPosition, CalculateConnectableSideByInternalPositionRequest, CalculateConnectionsState, CalculateConnectionsStateRequest, CalculateConnectorsConnectableSides, CalculateConnectorsConnectableSidesRequest, CalculateDirectChildrenUnionRect, CalculateDirectChildrenUnionRectRequest, CalculateFlowPointFromMinimapPoint, CalculateFlowPointFromMinimapPointRequest, CalculateFlowState, CalculateFlowStateRequest, CalculateInputConnections, CalculateInputConnectionsRequest, CalculateNodesBoundingBox, CalculateNodesBoundingBoxNormalizedPosition, CalculateNodesBoundingBoxNormalizedPositionRequest, CalculateNodesBoundingBoxRequest, CalculateNodesState, CalculateNodesStateRequest, CalculateOutputConnections, CalculateOutputConnectionsRequest, CalculateResizeLimits, CalculateResizeLimitsRequest, CalculateSegmentLineData, CalculateSelectableItems, CalculateSelectableItemsRequest, CalculateSourceConnectorsToConnect, CalculateSourceConnectorsToConnectRequest, CalculateStraightLineData, CalculateTargetConnectorsToConnect, CalculateTargetConnectorsToConnectRequest, CenterBasedDeltaCalculator, CenterGroupOrNode, CenterGroupOrNodeRequest, CenterOfMassSelectionStrategy, ChainPushCollisionResolver, ClearSelection, ClearSelectionRequest, CompleteConnectionRedraw, CompleteConnectionRedrawRequest, ConnectableSidesScheduler, ConnectedSubgraphScopeFilter, ConnectionBehaviourBuilder, ConnectionBehaviourBuilderRequest, ConnectionContentLayoutEngine, ConnectionLineBuilder, ConnectionLineBuilderRequest, ConnectionRedrawState, ConnectionWorkerState, CreateConnectionCreateDragHandler, CreateConnectionCreateDragHandlerRequest, CreateConnectionFinalize, CreateConnectionFinalizeRequest, CreateConnectionFromConnectorPreparation, CreateConnectionFromConnectorPreparationRequest, CreateConnectionFromOutletPreparation, CreateConnectionFromOutletPreparationRequest, CreateConnectionFromOutputPreparation, CreateConnectionFromOutputPreparationRequest, CreateConnectionHandler, CreateConnectionMarkers, CreateConnectionMarkersRequest, CreateConnectionPreparation, CreateConnectionPreparationRequest, CreateDragNodeHandler, CreateDragNodeHandlerRequest, CreateDragNodeHierarchy, CreateDragNodeHierarchyRequest, DRAG_AND_DROP_COMMON_PROVIDERS, DRAG_AUTO_PAN_PROVIDERS, DRAG_CANVAS_PROVIDERS, DRAG_CONNECTIONS_PROVIDERS, DRAG_DROP_TO_GROUP_PROVIDERS, DRAG_EXTERNAL_ITEM_HANDLER_KIND, DRAG_EXTERNAL_ITEM_HANDLER_TYPE, DRAG_EXTERNAL_ITEM_PROVIDERS, DRAG_MINIMAP_HANDLER_KIND, DRAG_MINIMAP_HANDLER_TYPE, DRAG_MINIMAP_PROVIDERS, DRAG_NODE_HANDLER_KIND, DRAG_NODE_HANDLER_TYPE, DRAG_SELECTION_AREA_PROVIDERS, DRAG_SELECT_BY_POINTER_PROVIDERS, DeltaClamp, Deprecated, DetectConnectionsUnderDragNode, DetectConnectionsUnderDragNodeRequest, DisableConnectionWorker, DisableConnectionWorkerRequest, DownstreamConnectionsSelectionStrategy, DragAndDropBase, DragCanvasFinalize, DragCanvasFinalizeRequest, DragCanvasHandler, DragCanvasPreparation, DragCanvasPreparationRequest, DragConnectionWaypointFinalize, DragConnectionWaypointFinalizeRequest, DragConnectionWaypointHandler, DragConnectionWaypointPreparation, DragConnectionWaypointPreparationRequest, DragExternalItemCreatePlaceholder, DragExternalItemCreatePlaceholderRequest, DragExternalItemCreatePreview, DragExternalItemCreatePreviewRequest, DragExternalItemFinalize, DragExternalItemFinalizeRequest, DragExternalItemHandler, DragExternalItemPreparation, DragExternalItemPreparationRequest, DragHandlerBase, DragHandlerInjector, DragMinimapFinalize, DragMinimapFinalizeRequest, DragMinimapHandler, DragMinimapPreparation, DragMinimapPreparationRequest, DragNodeConnectionBothSidesHandler, DragNodeConnectionHandlerBase, DragNodeConnectionSourceHandler, DragNodeConnectionTargetHandler, DragNodeDeltaConstraints, DragNodeFinalize, DragNodeFinalizeRequest, DragNodeHandler, DragNodeHierarchy, DragNodeItemHandler, DragNodePreparation, DragNodePreparationRequest, DropToGroupFinalize, DropToGroupFinalizeRequest, DropToGroupHandler, DropToGroupPreparation, DropToGroupPreparationRequest, ECanvasRedrawContext, EFCanvasLayer, EFConnectableSide, EFConnectionBehavior, EFConnectionConnectableSide, EFConnectionType, EFFlowFeatureKind, EFLayoutDirection, EFLayoutMode, EFMarkerType, EFReflowAxis, EFReflowCollision, EFReflowDeltaSource, EFReflowMode, EFReflowScope, EFResizeHandleType, EFZoomDirection, EMPTY_REFLOW_PLAN, EdgeBasedDeltaCalculator, EmitConnectionsChanges, EmitConnectionsChangesRequest, EmitEndDragSequenceEvent, EmitEndDragSequenceEventRequest, EmitSelectionChangeEvent, EmitSelectionChangeEventRequest, EmitStartDragSequenceEvent, EmitStartDragSequenceEventRequest, EnsureConnectionWorker, EnsureConnectionWorkerRequest, EventExtensions, ExternalRectConstraint, FA11yAnnouncer, FA11yController, FAutoPan, FAutoPanBase, FBackgroundBase, FBackgroundComponent, FCache, FCacheConnector, FCacheConnectorKeyFactory, FCacheNode, FCanvasBase, FCanvasChangeEvent, FCanvasComponent, FChannel, FChannelHub, FCirclePatternComponent, FClickConnectFlow, FComponentsStore, FConnectionBase, FConnectionComponent, FConnectionComponentsParent, FConnectionContent, FConnectionContentBase, FConnectionDragHandleBase, FConnectionDragHandleEnd, FConnectionDragHandleStart, FConnectionForCreateComponent, FConnectionGradient, FConnectionGradientBase, FConnectionGradientRenderer, FConnectionGradientRendererBase, FConnectionMarker, FConnectionMarkerArrow, FConnectionMarkerBase, FConnectionMarkerCircle, FConnectionMarkerRegistry, FConnectionPath, FConnectionPathBase, FConnectionRegistry, FConnectionSelection, FConnectionSelectionBase, FConnectionWaypoints, FConnectionWaypointsBase, FConnectionWaypointsChangedEvent, FConnectorBase, FConnectorDirective, FConnectorRegistry, FControlSchemeController, FCreateConnectionEvent, FCreateConnectionSession, FCreateNodeEvent, FDeleteSelectedEvent, FDragBlockerDirective, FDragExternalItemStartEventData, FDragHandleDirective, FDragHandlerResult, FDragNodeStartEventData, FDragStartedEvent, FDraggableBase, FDraggableDataContext, FDraggableDirective, FDropToGroupEvent, FExternalItem, FExternalItemBase, FExternalItemPlaceholder, FExternalItemPreview, FExternalItemService, FFlowBase, FFlowComponent, FFlowModule, FFlowState, FFlowStateController, FGroupDirective, FIdRegistryBase, FLayoutController, FLayoutEngine, FLineAlignmentComponent, FMagneticLines, FMagneticLinesBase, FMagneticRects, FMagneticRectsBase, FMinimapBase, FMinimapCanvasDirective, FMinimapComponent, FMinimapFlowDirective, FMinimapState, FMinimapViewDirective, FMoveNodesEvent, FNodeBase, FNodeConnectionsIntersectionEvent, FNodeDirective, FNodeInputBase, FNodeInputDirective, FNodeIntersectedWithConnections, FNodeOutletBase, FNodeOutletDirective, FNodeOutputBase, FNodeOutputDirective, FNodeRegistry, FReassignConnectionEvent, FRectPatternComponent, FReflowBaselineTracker, FReflowController, FReflowCycleGuard, FReflowIgnore, FReflowIgnoreRegistry, FReflowOrchestrator, FReflowPlanner, FResizeChannel, FResizeHandleDirective, FResizeNodeStartEventData, FRotateHandleDirective, FRotateNodeStartEventData, FSelectionArea, FSelectionAreaBase, FSelectionChangeEvent, FSingleRegistryBase, FSnapConnectionComponent, FSourceConnectorBase, FVirtualFor, FZoomBase, FZoomDirective, F_A11Y_CONFIG, F_AUTO_PAN_PROVIDERS, F_BACKGROUND, F_BACKGROUND_FEATURES, F_BACKGROUND_PATTERN, F_BACKGROUND_PROVIDERS, F_CACHE_FEATURES, F_CACHE_OPTIONS, F_CANVAS, F_CANVAS_CONFIG, F_CANVAS_FEATURES, F_CANVAS_PROVIDERS, F_CONNECTION_BUILDERS, F_CONNECTION_COMPONENTS_PARENT, F_CONNECTION_CONTENT, F_CONNECTION_DRAG_HANDLE_END, F_CONNECTION_DRAG_HANDLE_START, F_CONNECTION_FEATURES, F_CONNECTION_FLOW, F_CONNECTION_GRADIENT, F_CONNECTION_IMPORTS_EXPORTS, F_CONNECTION_MARKER, F_CONNECTION_PATH, F_CONNECTION_PROVIDERS, F_CONNECTION_SELECTION, F_CONNECTION_WAYPOINTS, F_CONNECTOR, F_CONNECTORS_FEATURES, F_CONNECTORS_PROVIDERS, F_CONTROL_SCHEME_CONFIG, F_CSS_CLASS, F_DEFAULT_A11Y_CONFIG, F_DEFAULT_A11Y_KEYS, F_DEFAULT_A11Y_MESSAGES, F_DEFAULT_CONTROL_SCHEME, F_DEFAULT_LAYER_ORDER, F_DRAGGABLE_FEATURES, F_DRAGGABLE_PROVIDERS, F_DRAG_SELECT_CONTROL_SCHEME, F_EXTERNAL_ITEM, F_EXTERNAL_ITEM_PROVIDERS, F_FLOW, F_FLOW_CONFIG, F_FLOW_FEATURES, F_FLOW_PROVIDERS, F_FLOW_STATE_CONFIG, F_LAYOUT, F_LAYOUT_OPTIONS, F_LINE_ALIGNMENT_PROVIDERS, F_MAGNETIC_LINES, F_MAGNETIC_LINES_PROVIDERS, F_MAGNETIC_RECTS, F_MAGNETIC_RECTS_PROVIDERS, F_MINIMAP_BASE, F_MINIMAP_FEATURES, F_MINIMAP_PROVIDERS, F_NODE, F_NODE_FEATURES, F_NODE_INPUT, F_NODE_OUTLET, F_NODE_OUTPUT, F_NODE_PROVIDERS, F_REFLOW_CONFIG, F_REFLOW_PROVIDERS, F_SCROLL_PAN_CONTROL_SCHEME, F_SELECTED_CLASS, F_SELECTION_AREA_PROVIDERS, F_SELECTION_FEATURES, F_STORAGE_PROVIDERS, F_VIRTUAL_FOR_PROVIDERS, F_ZOOM, F_ZOOM_FEATURES, F_ZOOM_PROVIDERS, FindConnectableConnectorUsingPriorityAndPosition, FindConnectableConnectorUsingPriorityAndPositionRequest, FitToChildNodesAndGroups, FitToChildNodesAndGroupsRequest, FitToFlow, FitToFlowRequest, GET_FLOW_STATE_PROVIDERS, GetCachedFCacheRect, GetCachedFCacheRectRequest, GetChildNodeIds, GetChildNodeIdsRequest, GetConnectorRectReference, GetConnectorRectReferenceRequest, GetCurrentSelection, GetCurrentSelectionRequest, GetDeepChildrenNodesAndGroups, GetDeepChildrenNodesAndGroupsRequest, GetFlow, GetFlowRequest, GetNodePadding, GetNodePaddingRequest, GetNormalizedConnectorRect, GetNormalizedConnectorRectRequest, GetNormalizedElementRect, GetNormalizedElementRectRequest, GetNormalizedParentNodeRect, GetNormalizedParentNodeRectRequest, GetNormalizedPoint, GetNormalizedPointRequest, GetParentNodes, GetParentNodesRequest, GlobalScopeFilter, GridSnapper, GroupScopeFilter, HandleConnectionWorkerMessage, HandleConnectionWorkerMessageRequest, IMouseEvent, INSTANCES, IPointerEvent, IPointerUpEvent, ITouchDownEvent, ITouchMoveEvent, InitializeDragSequence, InitializeDragSequenceRequest, InputCanvasPosition, InputCanvasPositionRequest, InputCanvasScale, InputCanvasScaleRequest, InvalidateFCacheNode, InvalidateFCacheNodeRequest, IsArrayHasParentNode, IsArrayHasParentNodeRequest, IsConnectionRedrawCurrent, IsConnectionRedrawCurrentRequest, IsConnectionWorkerEnabled, IsConnectionWorkerEnabledRequest, IsDragStarted, IsDragStartedRequest, ListenConnectionsChanges, ListenConnectionsChangesRequest, ListenNodesChanges, ListenNodesChangesRequest, ListenTransformChanges, ListenTransformChangesRequest, LogExecutionTime, MOUSE_EVENT_IGNORE_TIME, MagneticLineElement, MagneticLineRenderer, MagneticLinesHandler, MagneticLinesPreparation, MagneticLinesPreparationRequest, MagneticRectElement, MagneticRectsHandler, MagneticRectsPreparation, MagneticRectsPreparationRequest, MagneticRectsRenderer, MarkConnectableConnectors, MarkConnectableConnectorsRequest, MarkConnectionConnectorsAsConnected, MarkConnectionConnectorsAsConnectedRequest, MinimapCalculateViewRect, MinimapCalculateViewRectRequest, MinimapCalculateViewport, MinimapCalculateViewportRequest, MinimapDrawNodes, MinimapDrawNodesRequest, MinimapNodeRects, MoveFrontElementsBeforeTargetElement, MoveFrontElementsBeforeTargetElementRequest, NODE_PROVIDERS, NODE_RESIZE_PROVIDERS, NODE_ROTATE_PROVIDERS, NotifyFullRendered, NotifyFullRenderedRequest, NotifyNodesRendered, NotifyNodesRenderedRequest, NotifyTransformChanged, NotifyTransformChangedRequest, OnPointerMove, OnPointerMoveRequest, PINCH_TO_ZOOM_PROVIDERS, PinchToZoomFinalize, PinchToZoomFinalizeRequest, PinchToZoomHandler, PinchToZoomPreparation, PinchToZoomPreparationRequest, Polyline, PolylineContentAlign, PolylineContentPlace, PolylineSampler, PrepareDragSequence, PrepareDragSequenceRequest, PreventDefaultIsExternalItem, PreventDefaultIsExternalItemRequest, QueueConnectionRedraw, QueueConnectionRedrawRequest, QueueConnectionRedrawState, RESIZE_DIRECTIONS, RESIZE_NODE_HANDLER_KIND, RESIZE_NODE_HANDLER_TYPE, ROTATE_NODE_HANDLER_KIND, ROTATE_NODE_HANDLER_TYPE, ReadNodeBoundsWithPaddings, ReadNodeBoundsWithPaddingsRequest, ReadNodeBoundsWithPaddingsResponse, ReassignConnectionFinalize, ReassignConnectionFinalizeRequest, ReassignConnectionHandler, ReassignConnectionPreparation, ReassignConnectionPreparationRequest, ReassignConnectionSourceHandler, ReassignConnectionTargetHandler, RedrawCanvasWithAnimation, RedrawCanvasWithAnimationRequest, RedrawConnections, RedrawConnectionsRequest, RegisterFCacheConnector, RegisterFCacheConnectorRequest, RegisterFCacheNode, RegisterFCacheNodeRequest, RegisterPluginInstance, RegisterPluginInstanceRequest, RemoveCanvasFromStore, RemoveCanvasFromStoreRequest, RemoveConnectionForCreateFromStore, RemoveConnectionForCreateFromStoreRequest, RemoveConnectionFromStore, RemoveConnectionFromStoreRequest, RemoveConnectionMarkerFromStore, RemoveConnectionMarkerFromStoreRequest, RemoveConnectionWaypoint, RemoveConnectionWaypointRequest, RemoveConnectorFromStore, RemoveConnectorFromStoreRequest, RemoveDndFromStore, RemoveDndFromStoreRequest, RemoveFlowFromStore, RemoveFlowFromStoreRequest, RemoveNodeFromStore, RemoveNodeFromStoreRequest, RemovePluginInstance, RemovePluginInstanceRequest, RemoveSnapConnectionFromStore, RemoveSnapConnectionFromStoreRequest, RenderConnection, RenderConnectionFromGeometry, RenderConnectionFromGeometryRequest, RenderConnectionRequest, RenderConnectionWithLine, RenderConnectionWithLineRequest, RenderLifecycleState, ResetConnectionWorkerRuntime, ResetConnectionWorkerRuntimeRequest, ResetRenderLifecycle, ResetRenderLifecycleRequest, ResetScale, ResetScaleAndCenter, ResetScaleAndCenterRequest, ResetScaleRequest, ResetZoom, ResetZoomRequest, ResizeNodeConnectionBothSidesHandler, ResizeNodeConnectionHandlerBase, ResizeNodeConnectionSourceHandler, ResizeNodeConnectionTargetHandler, ResizeNodeFinalize, ResizeNodeFinalizeRequest, ResizeNodeHandler, ResizeNodePreparation, ResizeNodePreparationRequest, ResolveConnectableOutputForOutlet, ResolveConnectableOutputForOutletRequest, ResolveConnectionEndpointRect, ResolveConnectionEndpointRectRequest, ResolveConnectionEndpointRotationContext, ResolveConnectionEndpointRotationContextRequest, ResolveConnectionEndpoints, ResolveConnectionEndpointsRequest, ResolveConnectionGeometry, ResolveConnectionGeometryRequest, RotateNodeFinalize, RotateNodeFinalizeRequest, RotateNodeHandler, RotateNodePreparation, RotateNodePreparationRequest, RunAutoPanFrame, RunAutoPanFrameRequest, RunConnectionRedrawSlice, RunConnectionRedrawSliceRequest, RunConnectionWorker, RunConnectionWorkerBatch, RunConnectionWorkerBatchRequest, RunConnectionWorkerRequest, RunDevDiagnostics, RunDevDiagnosticsRequest, ScheduleAutoPanFrame, ScheduleAutoPanFrameRequest, ScrollCanvas, ScrollCanvasRequest, Select, SelectAll, SelectAllRequest, SelectAndUpdateNodeLayer, SelectAndUpdateNodeLayerRequest, SelectByPointer, SelectByPointerRequest, SelectRequest, SelectionAreaFinalize, SelectionAreaFinalizeRequest, SelectionAreaHandler, SelectionAreaPreparation, SelectionAreaPreparationRequest, SetBackgroundTransform, SetBackgroundTransformRequest, SetFCacheConnectorRect, SetFCacheConnectorRectRequest, SetFCacheNodeRect, SetFCacheNodeRectRequest, SetZoom, SetZoomRequest, ShouldUseConnectionWorker, ShouldUseConnectionWorkerRequest, SortDropCandidatesByLayer, SortDropCandidatesByLayerRequest, SortItemLayers, SortItemLayersRequest, SortItemsByParent, SortItemsByParentRequest, SortNodeLayers, SortNodeLayersRequest, StartConnectionRedraw, StartConnectionRedrawRequest, StartConnectionWorkerRedraw, StartConnectionWorkerRedrawRequest, StopAutoPan, StopAutoPanRequest, StopCollisionResolver, UnmarkConnectableConnectors, UnmarkConnectableConnectorsRequest, UnregisterFCacheConnector, UnregisterFCacheConnectorRequest, UnregisterFCacheNode, UnregisterFCacheNodeRequest, UpdateFCacheRectByElement, UpdateFCacheRectByElementRequest, UpdateItemAndChildrenLayers, UpdateItemAndChildrenLayersRequest, UpdateNodeWhenStateOrSizeChanged, UpdateNodeWhenStateOrSizeChangedRequest, UpdateScale, UpdateScaleRequest, WaitForConnectionsRendered, WaitForConnectionsRenderedRequest, XRangeSelectionStrategy, afterNextPaint, buildConnectionAnchors, buildCornerMidPointsAndApplyOffsets, calculateAutoPanAxisDelta, calculateAutoPanDelta, calculateCenterBetweenPoints, calculateCurveCandidates, calculateDifferenceAfterRotation, calculateMagneticGuides, calculateMagneticRects, calculatePointerInFlow, calculatePolylineCandidates, calculatePositionAfterRotation, castToConnectorType, coerceMarkerType, computeEdgeDeltas, createConnectionDomIdentifier, createConnectionSelectionDomIdentifier, createConnectionWorkerUrl, createGradientDomIdentifier, createGradientDomUrl, createMultiCubicPath, createSVGElement, createSegmentLinePath, cubicBezierAtT, debounceAnimationFrame, debounceMicrotask, debounceTime, defaultEventTrigger, determineSide, expandRectByOverflow, fDiagnosticMessage, fInstanceKey, fProvideCache, fSuppressDevWarnings, fWarnOnce, filterConnectableTargets, findExistingWaypoint, findNodeOrGroupContaining, findSourceConnector, findSpatialNeighbor, findTargetConnector, findWaypointCandidate, fixedCenterBehavior, fixedOutboundBehavior, floatingBehavior, getAllSourceConnectors, getAllTargetConnectors, getExternalItemHost, infinityMinMax, injectFlowState, isCalculateMode, isConnectionWorkerRuntimeSupported, isConnector, isDragBlocker, isDragExternalItemHandler, isDragHandleEnd, isDragHandleStart, isDragMinimapHandler, isDragNodeHandler, isExternalItem, isFDevMode, isMobile, isNode, isNodeOutlet, isNodeOutput, isOnFlowBackground, isOutletConnector, isPointerInsidePoint, isPointerInsideStartOrEndDragHandles, isResizeNodeHandler, isRotateHandle, isRotateNodeHandler, isSourceConnector, isTargetConnector, isValidEventTrigger, mergeA11yConfig, mergeControlSchemeConfig, mergeFCanvasConfig, mergeFlowStateConfig, mergeLayoutNodes, mergePointChains, mergeReflowConfig, middleButtonEventTrigger, mixinChangeSelection, mixinChangeVisibility, normalizeFlowLayoutData, normalizePolyline, notifyOnStart, pickWaypoint, primaryButtonEventTrigger, provideFFlow, provideFLayout, rebaseAutoPanPointerDownPosition, rectFromPoint, requireSourceConnector, requireTargetConnector, resolveAutoPanMode, resolveConnectionWorkerRuntime, resolveLayerOrder, revokeConnectionWorkerUrl, sampleCubicBezierUniform, sampleMultiCubicUniform, stringAttribute, takeOne, transitionEnd, withA11y, withConnectionFlow, withControlScheme, withFCanvas, withFlowState, withReflowOnResize, withinSnapThreshold };
22697
24314
  //# sourceMappingURL=foblex-flow.mjs.map