@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.
- package/AI.md +39 -11
- package/README.md +48 -21
- package/STYLING.md +1 -0
- package/fesm2022/foblex-flow.mjs +1806 -189
- package/fesm2022/foblex-flow.mjs.map +1 -1
- package/index.d.ts +717 -35
- package/package.json +12 -2
- package/styles/domains/_node-group.scss +6 -2
package/fesm2022/foblex-flow.mjs
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
79
|
-
|
|
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
|
-
|
|
95
|
-
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
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',
|
|
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
|
-
|
|
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
|
|
4467
|
-
}
|
|
4468
|
-
_getRoundedRect(rect, element
|
|
4469
|
-
const
|
|
4470
|
-
|
|
4471
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
7629
|
+
_target;
|
|
7630
|
+
constructor(_event, target) {
|
|
7351
7631
|
this._event = _event;
|
|
7352
|
-
|
|
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
|
|
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
|
|
11167
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
14878
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
19389
|
-
|
|
19390
|
-
|
|
19391
|
-
|
|
19392
|
-
|
|
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
|
-
|
|
19396
|
-
|
|
19397
|
-
|
|
19398
|
-
|
|
19399
|
-
|
|
19400
|
-
|
|
19401
|
-
|
|
19402
|
-
|
|
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
|
-
|
|
19409
|
-
|
|
19410
|
-
|
|
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(
|
|
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
|
-
|
|
19452
|
-
|
|
19453
|
-
|
|
19454
|
-
|
|
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
|
-
|
|
21902
|
-
|
|
21903
|
-
|
|
21904
|
-
|
|
21905
|
-
|
|
21906
|
-
|
|
21907
|
-
|
|
21908
|
-
|
|
21909
|
-
|
|
21910
|
-
|
|
21911
|
-
|
|
21912
|
-
|
|
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.
|
|
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
|
-
|
|
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
|