ngx-vflow 1.0.6 → 1.0.7
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/esm2022/lib/vflow/components/node/node.component.mjs +7 -6
- package/esm2022/lib/vflow/components/vflow/vflow.component.mjs +4 -10
- package/esm2022/lib/vflow/directives/connection-controller.directive.mjs +37 -47
- package/esm2022/lib/vflow/services/flow-status.service.mjs +1 -15
- package/esm2022/lib/vflow/vflow.mjs +3 -1
- package/fesm2022/ngx-vflow.mjs +151 -179
- package/fesm2022/ngx-vflow.mjs.map +1 -1
- package/lib/vflow/components/node/node.component.d.ts +1 -1
- package/lib/vflow/components/vflow/vflow.component.d.ts +4 -5
- package/lib/vflow/directives/connection-controller.directive.d.ts +4 -5
- package/lib/vflow/services/flow-status.service.d.ts +0 -6
- package/lib/vflow/vflow.d.ts +2 -1
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@ import { MiniMapComponent } from './public-components/minimap/minimap.component'
|
|
|
6
6
|
import { NodeToolbarComponent } from './public-components/node-toolbar/node-toolbar.component';
|
|
7
7
|
import { ResizableComponent } from './public-components/resizable/resizable.component';
|
|
8
8
|
import { HandleComponent } from './public-components/handle/handle.component';
|
|
9
|
+
import { ConnectionControllerDirective } from './directives/connection-controller.directive';
|
|
9
10
|
export const Vflow = [
|
|
10
11
|
VflowComponent,
|
|
11
12
|
HandleComponent,
|
|
@@ -14,6 +15,7 @@ export const Vflow = [
|
|
|
14
15
|
MiniMapComponent,
|
|
15
16
|
NodeToolbarComponent,
|
|
16
17
|
DragHandleDirective,
|
|
18
|
+
ConnectionControllerDirective,
|
|
17
19
|
NodeHtmlTemplateDirective,
|
|
18
20
|
GroupNodeTemplateDirective,
|
|
19
21
|
EdgeLabelHtmlTemplateDirective,
|
|
@@ -21,4 +23,4 @@ export const Vflow = [
|
|
|
21
23
|
ConnectionTemplateDirective,
|
|
22
24
|
HandleTemplateDirective,
|
|
23
25
|
];
|
|
24
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
26
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmZsb3cuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtdmZsb3ctbGliL3NyYy9saWIvdmZsb3cvdmZsb3cudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQ3BFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQ3pFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBQ3hFLE9BQU8sRUFDTCwyQkFBMkIsRUFDM0IsOEJBQThCLEVBQzlCLHFCQUFxQixFQUNyQiwwQkFBMEIsRUFDMUIsdUJBQXVCLEVBQ3ZCLHlCQUF5QixHQUMxQixNQUFNLGlDQUFpQyxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLCtDQUErQyxDQUFDO0FBQ2pGLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLHlEQUF5RCxDQUFDO0FBQy9GLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLG1EQUFtRCxDQUFDO0FBQ3ZGLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSw2Q0FBNkMsQ0FBQztBQUM5RSxPQUFPLEVBQUUsNkJBQTZCLEVBQUUsTUFBTSw4Q0FBOEMsQ0FBQztBQUU3RixNQUFNLENBQUMsTUFBTSxLQUFLLEdBQUc7SUFDbkIsY0FBYztJQUNkLGVBQWU7SUFDZixrQkFBa0I7SUFDbEIsbUJBQW1CO0lBQ25CLGdCQUFnQjtJQUNoQixvQkFBb0I7SUFDcEIsbUJBQW1CO0lBQ25CLDZCQUE2QjtJQUU3Qix5QkFBeUI7SUFDekIsMEJBQTBCO0lBQzFCLDhCQUE4QjtJQUM5QixxQkFBcUI7SUFDckIsMkJBQTJCO0lBQzNCLHVCQUF1QjtDQUNmLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBWZmxvd0NvbXBvbmVudCB9IGZyb20gJy4vY29tcG9uZW50cy92Zmxvdy92Zmxvdy5jb21wb25lbnQnO1xuaW1wb3J0IHsgRHJhZ0hhbmRsZURpcmVjdGl2ZSB9IGZyb20gJy4vZGlyZWN0aXZlcy9kcmFnLWhhbmRsZS5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgU2VsZWN0YWJsZURpcmVjdGl2ZSB9IGZyb20gJy4vZGlyZWN0aXZlcy9zZWxlY3RhYmxlLmRpcmVjdGl2ZSc7XG5pbXBvcnQge1xuICBDb25uZWN0aW9uVGVtcGxhdGVEaXJlY3RpdmUsXG4gIEVkZ2VMYWJlbEh0bWxUZW1wbGF0ZURpcmVjdGl2ZSxcbiAgRWRnZVRlbXBsYXRlRGlyZWN0aXZlLFxuICBHcm91cE5vZGVUZW1wbGF0ZURpcmVjdGl2ZSxcbiAgSGFuZGxlVGVtcGxhdGVEaXJlY3RpdmUsXG4gIE5vZGVIdG1sVGVtcGxhdGVEaXJlY3RpdmUsXG59IGZyb20gJy4vZGlyZWN0aXZlcy90ZW1wbGF0ZS5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgTWluaU1hcENvbXBvbmVudCB9IGZyb20gJy4vcHVibGljLWNvbXBvbmVudHMvbWluaW1hcC9taW5pbWFwLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBOb2RlVG9vbGJhckNvbXBvbmVudCB9IGZyb20gJy4vcHVibGljLWNvbXBvbmVudHMvbm9kZS10b29sYmFyL25vZGUtdG9vbGJhci5jb21wb25lbnQnO1xuaW1wb3J0IHsgUmVzaXphYmxlQ29tcG9uZW50IH0gZnJvbSAnLi9wdWJsaWMtY29tcG9uZW50cy9yZXNpemFibGUvcmVzaXphYmxlLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBIYW5kbGVDb21wb25lbnQgfSBmcm9tICcuL3B1YmxpYy1jb21wb25lbnRzL2hhbmRsZS9oYW5kbGUuY29tcG9uZW50JztcbmltcG9ydCB7IENvbm5lY3Rpb25Db250cm9sbGVyRGlyZWN0aXZlIH0gZnJvbSAnLi9kaXJlY3RpdmVzL2Nvbm5lY3Rpb24tY29udHJvbGxlci5kaXJlY3RpdmUnO1xuXG5leHBvcnQgY29uc3QgVmZsb3cgPSBbXG4gIFZmbG93Q29tcG9uZW50LFxuICBIYW5kbGVDb21wb25lbnQsXG4gIFJlc2l6YWJsZUNvbXBvbmVudCxcbiAgU2VsZWN0YWJsZURpcmVjdGl2ZSxcbiAgTWluaU1hcENvbXBvbmVudCxcbiAgTm9kZVRvb2xiYXJDb21wb25lbnQsXG4gIERyYWdIYW5kbGVEaXJlY3RpdmUsXG4gIENvbm5lY3Rpb25Db250cm9sbGVyRGlyZWN0aXZlLFxuXG4gIE5vZGVIdG1sVGVtcGxhdGVEaXJlY3RpdmUsXG4gIEdyb3VwTm9kZVRlbXBsYXRlRGlyZWN0aXZlLFxuICBFZGdlTGFiZWxIdG1sVGVtcGxhdGVEaXJlY3RpdmUsXG4gIEVkZ2VUZW1wbGF0ZURpcmVjdGl2ZSxcbiAgQ29ubmVjdGlvblRlbXBsYXRlRGlyZWN0aXZlLFxuICBIYW5kbGVUZW1wbGF0ZURpcmVjdGl2ZSxcbl0gYXMgY29uc3Q7XG4iXX0=
|
package/fesm2022/ngx-vflow.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { signal, computed, Injectable, inject, ElementRef, Directive, effect, untracked, TemplateRef,
|
|
2
|
+
import { signal, computed, Injectable, inject, ElementRef, Directive, effect, untracked, TemplateRef, DestroyRef, EventEmitter, OutputEmitterRef, input, viewChild, Component, ChangeDetectionStrategy, Injector, runInInjectionContext, output, HostListener, NgZone, contentChild, Input, forwardRef } from '@angular/core';
|
|
3
3
|
import { select } from 'd3-selection';
|
|
4
4
|
import { zoomIdentity, zoom } from 'd3-zoom';
|
|
5
5
|
import { switchMap, merge, fromEvent, tap, Subject, Observable, observeOn, animationFrameScheduler, skip, map, pairwise, filter, distinctUntilChanged, asyncScheduler, zip, share, startWith, of } from 'rxjs';
|
|
@@ -666,173 +666,6 @@ class FlowStatusService {
|
|
|
666
666
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowStatusService, decorators: [{
|
|
667
667
|
type: Injectable
|
|
668
668
|
}] });
|
|
669
|
-
/**
|
|
670
|
-
* Batch status changes together to call them one after another
|
|
671
|
-
*
|
|
672
|
-
* @param changes list of set[FlowStatus.state]Status() calls
|
|
673
|
-
*/
|
|
674
|
-
function batchStatusChanges(...changes) {
|
|
675
|
-
if (changes.length) {
|
|
676
|
-
const [firstChange, ...restChanges] = changes;
|
|
677
|
-
// first change is sync
|
|
678
|
-
firstChange();
|
|
679
|
-
// without timer, subscribed effects/comuted signals only get latest value
|
|
680
|
-
restChanges.forEach((change) => setTimeout(() => change()));
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
/**
|
|
685
|
-
* This function contains a hack-y behavior.
|
|
686
|
-
* If the handles are of the same type (source-source or target-target),
|
|
687
|
-
* it returns nodes where source === target and
|
|
688
|
-
* handles where sourceHandle === targetHandle
|
|
689
|
-
*
|
|
690
|
-
* This leads to that notSelfValidator returns false for these cases,
|
|
691
|
-
* exactly what we need for strict connection type
|
|
692
|
-
*/
|
|
693
|
-
function adjustDirection(connection) {
|
|
694
|
-
const result = {};
|
|
695
|
-
if (connection.sourceHandle.rawHandle.type === 'source') {
|
|
696
|
-
result.source = connection.source;
|
|
697
|
-
result.sourceHandle = connection.sourceHandle;
|
|
698
|
-
}
|
|
699
|
-
else {
|
|
700
|
-
result.source = connection.target;
|
|
701
|
-
result.sourceHandle = connection.targetHandle;
|
|
702
|
-
}
|
|
703
|
-
if (connection.targetHandle.rawHandle.type === 'target') {
|
|
704
|
-
result.target = connection.target;
|
|
705
|
-
result.targetHandle = connection.targetHandle;
|
|
706
|
-
}
|
|
707
|
-
else {
|
|
708
|
-
result.target = connection.source;
|
|
709
|
-
result.targetHandle = connection.sourceHandle;
|
|
710
|
-
}
|
|
711
|
-
return result;
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
class ConnectionControllerDirective {
|
|
715
|
-
constructor() {
|
|
716
|
-
/**
|
|
717
|
-
* This event fires when user tries to create new Edge.
|
|
718
|
-
*
|
|
719
|
-
* `Connection` is an entity that contains data about source and target nodes.
|
|
720
|
-
*
|
|
721
|
-
* Also it's important to note, that this event only fires when connection is valid by validator function in `ConnectionSettings`,
|
|
722
|
-
* by default without passing the validator every connection concidered valid.
|
|
723
|
-
*
|
|
724
|
-
* @todo add connect event and deprecate onConnect
|
|
725
|
-
*/
|
|
726
|
-
// eslint-disable-next-line @angular-eslint/no-output-on-prefix
|
|
727
|
-
this.onConnect = output();
|
|
728
|
-
this.statusService = inject(FlowStatusService);
|
|
729
|
-
this.flowEntitiesService = inject(FlowEntitiesService);
|
|
730
|
-
this.connectEffect = effect(() => {
|
|
731
|
-
const status = this.statusService.status();
|
|
732
|
-
if (status.state === 'connection-end') {
|
|
733
|
-
let source = status.payload.source;
|
|
734
|
-
let target = status.payload.target;
|
|
735
|
-
let sourceHandle = status.payload.sourceHandle;
|
|
736
|
-
let targetHandle = status.payload.targetHandle;
|
|
737
|
-
if (this.isStrictMode()) {
|
|
738
|
-
const adjusted = adjustDirection({
|
|
739
|
-
source: status.payload.source,
|
|
740
|
-
sourceHandle: status.payload.sourceHandle,
|
|
741
|
-
target: status.payload.target,
|
|
742
|
-
targetHandle: status.payload.targetHandle,
|
|
743
|
-
});
|
|
744
|
-
source = adjusted.source;
|
|
745
|
-
target = adjusted.target;
|
|
746
|
-
sourceHandle = adjusted.sourceHandle;
|
|
747
|
-
targetHandle = adjusted.targetHandle;
|
|
748
|
-
}
|
|
749
|
-
const sourceId = source.node.id;
|
|
750
|
-
const targetId = target.node.id;
|
|
751
|
-
const sourceHandleId = sourceHandle.rawHandle.id;
|
|
752
|
-
const targetHandleId = targetHandle.rawHandle.id;
|
|
753
|
-
const connectionModel = this.flowEntitiesService.connection();
|
|
754
|
-
const connection = {
|
|
755
|
-
source: sourceId,
|
|
756
|
-
target: targetId,
|
|
757
|
-
sourceHandle: sourceHandleId,
|
|
758
|
-
targetHandle: targetHandleId,
|
|
759
|
-
};
|
|
760
|
-
if (connectionModel.validator(connection)) {
|
|
761
|
-
this.onConnect.emit(connection);
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
}, { allowSignalWrites: true });
|
|
765
|
-
this.isStrictMode = computed(() => this.flowEntitiesService.connection().mode === 'strict');
|
|
766
|
-
}
|
|
767
|
-
startConnection(handle) {
|
|
768
|
-
this.statusService.setConnectionStartStatus(handle.parentNode, handle);
|
|
769
|
-
}
|
|
770
|
-
validateConnection(handle) {
|
|
771
|
-
const status = this.statusService.status();
|
|
772
|
-
if (status.state === 'connection-start') {
|
|
773
|
-
let source = status.payload.source;
|
|
774
|
-
let target = handle.parentNode;
|
|
775
|
-
let sourceHandle = status.payload.sourceHandle;
|
|
776
|
-
let targetHandle = handle;
|
|
777
|
-
if (this.isStrictMode()) {
|
|
778
|
-
// swap direction (if needed) according to actual source and target of strict mode
|
|
779
|
-
const adjusted = adjustDirection({
|
|
780
|
-
source: status.payload.source,
|
|
781
|
-
sourceHandle: status.payload.sourceHandle,
|
|
782
|
-
target: handle.parentNode,
|
|
783
|
-
targetHandle: handle,
|
|
784
|
-
});
|
|
785
|
-
source = adjusted.source;
|
|
786
|
-
target = adjusted.target;
|
|
787
|
-
sourceHandle = adjusted.sourceHandle;
|
|
788
|
-
targetHandle = adjusted.targetHandle;
|
|
789
|
-
}
|
|
790
|
-
const valid = this.flowEntitiesService.connection().validator({
|
|
791
|
-
source: source.node.id,
|
|
792
|
-
target: target.node.id,
|
|
793
|
-
sourceHandle: sourceHandle.rawHandle.id,
|
|
794
|
-
targetHandle: targetHandle.rawHandle.id,
|
|
795
|
-
});
|
|
796
|
-
// TODO: check how react flow handles highlight of handle
|
|
797
|
-
// if direction changes
|
|
798
|
-
handle.state.set(valid ? 'valid' : 'invalid');
|
|
799
|
-
// status is about how we draw connection, so we don't need
|
|
800
|
-
// swapped diretion here
|
|
801
|
-
this.statusService.setConnectionValidationStatus(valid, status.payload.source, handle.parentNode, status.payload.sourceHandle, handle);
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
resetValidateConnection(targetHandle) {
|
|
805
|
-
targetHandle.state.set('idle');
|
|
806
|
-
// drop back to start status
|
|
807
|
-
const status = this.statusService.status();
|
|
808
|
-
if (status.state === 'connection-validation') {
|
|
809
|
-
this.statusService.setConnectionStartStatus(status.payload.source, status.payload.sourceHandle);
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
endConnection() {
|
|
813
|
-
const status = this.statusService.status();
|
|
814
|
-
if (status.state === 'connection-validation') {
|
|
815
|
-
const source = status.payload.source;
|
|
816
|
-
const sourceHandle = status.payload.sourceHandle;
|
|
817
|
-
const target = status.payload.target;
|
|
818
|
-
const targetHandle = status.payload.targetHandle;
|
|
819
|
-
batchStatusChanges(
|
|
820
|
-
// call to create connection
|
|
821
|
-
() => this.statusService.setConnectionEndStatus(source, target, sourceHandle, targetHandle),
|
|
822
|
-
// when connection created, we need go back to idle status
|
|
823
|
-
() => this.statusService.setIdleStatus());
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConnectionControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
827
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: ConnectionControllerDirective, isStandalone: true, selector: "[connectionController]", outputs: { onConnect: "onConnect" }, ngImport: i0 }); }
|
|
828
|
-
}
|
|
829
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConnectionControllerDirective, decorators: [{
|
|
830
|
-
type: Directive,
|
|
831
|
-
args: [{
|
|
832
|
-
selector: '[connectionController]',
|
|
833
|
-
standalone: true,
|
|
834
|
-
}]
|
|
835
|
-
}] });
|
|
836
669
|
|
|
837
670
|
class ComponentEventBusService {
|
|
838
671
|
constructor() {
|
|
@@ -2032,6 +1865,147 @@ const implementsWithInjector = (instance) => {
|
|
|
2032
1865
|
return 'injector' in instance && 'get' in instance.injector;
|
|
2033
1866
|
};
|
|
2034
1867
|
|
|
1868
|
+
/**
|
|
1869
|
+
* This function contains a hack-y behavior.
|
|
1870
|
+
* If the handles are of the same type (source-source or target-target),
|
|
1871
|
+
* it returns nodes where source === target and
|
|
1872
|
+
* handles where sourceHandle === targetHandle
|
|
1873
|
+
*
|
|
1874
|
+
* This leads to that notSelfValidator returns false for these cases,
|
|
1875
|
+
* exactly what we need for strict connection type
|
|
1876
|
+
*/
|
|
1877
|
+
function adjustDirection(connection) {
|
|
1878
|
+
const result = {};
|
|
1879
|
+
if (connection.sourceHandle.rawHandle.type === 'source') {
|
|
1880
|
+
result.source = connection.source;
|
|
1881
|
+
result.sourceHandle = connection.sourceHandle;
|
|
1882
|
+
}
|
|
1883
|
+
else {
|
|
1884
|
+
result.source = connection.target;
|
|
1885
|
+
result.sourceHandle = connection.targetHandle;
|
|
1886
|
+
}
|
|
1887
|
+
if (connection.targetHandle.rawHandle.type === 'target') {
|
|
1888
|
+
result.target = connection.target;
|
|
1889
|
+
result.targetHandle = connection.targetHandle;
|
|
1890
|
+
}
|
|
1891
|
+
else {
|
|
1892
|
+
result.target = connection.source;
|
|
1893
|
+
result.targetHandle = connection.sourceHandle;
|
|
1894
|
+
}
|
|
1895
|
+
return result;
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
class ConnectionControllerDirective {
|
|
1899
|
+
constructor() {
|
|
1900
|
+
this.statusService = inject(FlowStatusService);
|
|
1901
|
+
this.flowEntitiesService = inject(FlowEntitiesService);
|
|
1902
|
+
/**
|
|
1903
|
+
* This event fires when user tries to create new Edge.
|
|
1904
|
+
*
|
|
1905
|
+
* `Connection` is an entity that contains data about source and target nodes.
|
|
1906
|
+
*
|
|
1907
|
+
* Also it's important to note, that this event only fires when connection is valid by validator function in `ConnectionSettings`,
|
|
1908
|
+
* by default without passing the validator every connection concidered valid.
|
|
1909
|
+
*
|
|
1910
|
+
* @todo add connect event and deprecate onConnect
|
|
1911
|
+
*/
|
|
1912
|
+
// eslint-disable-next-line @angular-eslint/no-output-on-prefix
|
|
1913
|
+
this.onConnect = outputFromObservable(toObservable(this.statusService.status).pipe(filter((status) => status.state === 'connection-end'), map((status) => {
|
|
1914
|
+
let source = status.payload.source;
|
|
1915
|
+
let target = status.payload.target;
|
|
1916
|
+
let sourceHandle = status.payload.sourceHandle;
|
|
1917
|
+
let targetHandle = status.payload.targetHandle;
|
|
1918
|
+
if (this.isStrictMode()) {
|
|
1919
|
+
const adjusted = adjustDirection({
|
|
1920
|
+
source: status.payload.source,
|
|
1921
|
+
sourceHandle: status.payload.sourceHandle,
|
|
1922
|
+
target: status.payload.target,
|
|
1923
|
+
targetHandle: status.payload.targetHandle,
|
|
1924
|
+
});
|
|
1925
|
+
source = adjusted.source;
|
|
1926
|
+
target = adjusted.target;
|
|
1927
|
+
sourceHandle = adjusted.sourceHandle;
|
|
1928
|
+
targetHandle = adjusted.targetHandle;
|
|
1929
|
+
}
|
|
1930
|
+
const sourceId = source.node.id;
|
|
1931
|
+
const targetId = target.node.id;
|
|
1932
|
+
const sourceHandleId = sourceHandle.rawHandle.id;
|
|
1933
|
+
const targetHandleId = targetHandle.rawHandle.id;
|
|
1934
|
+
return {
|
|
1935
|
+
source: sourceId,
|
|
1936
|
+
target: targetId,
|
|
1937
|
+
sourceHandle: sourceHandleId,
|
|
1938
|
+
targetHandle: targetHandleId,
|
|
1939
|
+
};
|
|
1940
|
+
}), tap(() => this.statusService.setIdleStatus()), filter((connection) => this.flowEntitiesService.connection().validator(connection))));
|
|
1941
|
+
this.isStrictMode = computed(() => this.flowEntitiesService.connection().mode === 'strict');
|
|
1942
|
+
}
|
|
1943
|
+
startConnection(handle) {
|
|
1944
|
+
this.statusService.setConnectionStartStatus(handle.parentNode, handle);
|
|
1945
|
+
}
|
|
1946
|
+
validateConnection(handle) {
|
|
1947
|
+
const status = this.statusService.status();
|
|
1948
|
+
if (status.state === 'connection-start') {
|
|
1949
|
+
let source = status.payload.source;
|
|
1950
|
+
let target = handle.parentNode;
|
|
1951
|
+
let sourceHandle = status.payload.sourceHandle;
|
|
1952
|
+
let targetHandle = handle;
|
|
1953
|
+
if (this.isStrictMode()) {
|
|
1954
|
+
// swap direction (if needed) according to actual source and target of strict mode
|
|
1955
|
+
const adjusted = adjustDirection({
|
|
1956
|
+
source: status.payload.source,
|
|
1957
|
+
sourceHandle: status.payload.sourceHandle,
|
|
1958
|
+
target: handle.parentNode,
|
|
1959
|
+
targetHandle: handle,
|
|
1960
|
+
});
|
|
1961
|
+
source = adjusted.source;
|
|
1962
|
+
target = adjusted.target;
|
|
1963
|
+
sourceHandle = adjusted.sourceHandle;
|
|
1964
|
+
targetHandle = adjusted.targetHandle;
|
|
1965
|
+
}
|
|
1966
|
+
const valid = this.flowEntitiesService.connection().validator({
|
|
1967
|
+
source: source.node.id,
|
|
1968
|
+
target: target.node.id,
|
|
1969
|
+
sourceHandle: sourceHandle.rawHandle.id,
|
|
1970
|
+
targetHandle: targetHandle.rawHandle.id,
|
|
1971
|
+
});
|
|
1972
|
+
// TODO: check how react flow handles highlight of handle
|
|
1973
|
+
// if direction changes
|
|
1974
|
+
handle.state.set(valid ? 'valid' : 'invalid');
|
|
1975
|
+
// status is about how we draw connection, so we don't need
|
|
1976
|
+
// swapped diretion here
|
|
1977
|
+
this.statusService.setConnectionValidationStatus(valid, status.payload.source, handle.parentNode, status.payload.sourceHandle, handle);
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
resetValidateConnection(targetHandle) {
|
|
1981
|
+
targetHandle.state.set('idle');
|
|
1982
|
+
// drop back to start status
|
|
1983
|
+
const status = this.statusService.status();
|
|
1984
|
+
if (status.state === 'connection-validation') {
|
|
1985
|
+
this.statusService.setConnectionStartStatus(status.payload.source, status.payload.sourceHandle);
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
endConnection() {
|
|
1989
|
+
const status = this.statusService.status();
|
|
1990
|
+
if (status.state === 'connection-validation') {
|
|
1991
|
+
const source = status.payload.source;
|
|
1992
|
+
const sourceHandle = status.payload.sourceHandle;
|
|
1993
|
+
const target = status.payload.target;
|
|
1994
|
+
const targetHandle = status.payload.targetHandle;
|
|
1995
|
+
this.statusService.setConnectionEndStatus(source, target, sourceHandle, targetHandle);
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConnectionControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1999
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: ConnectionControllerDirective, isStandalone: true, selector: "[onConnect]", outputs: { onConnect: "onConnect" }, ngImport: i0 }); }
|
|
2000
|
+
}
|
|
2001
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConnectionControllerDirective, decorators: [{
|
|
2002
|
+
type: Directive,
|
|
2003
|
+
args: [{
|
|
2004
|
+
selector: '[onConnect]',
|
|
2005
|
+
standalone: true,
|
|
2006
|
+
}]
|
|
2007
|
+
}] });
|
|
2008
|
+
|
|
2035
2009
|
class HandleSizeControllerDirective {
|
|
2036
2010
|
constructor() {
|
|
2037
2011
|
this.handleModel = input.required({
|
|
@@ -2517,10 +2491,11 @@ class NodeComponent {
|
|
|
2517
2491
|
this.flowSettingsService = inject(FlowSettingsService);
|
|
2518
2492
|
this.selectionService = inject(SelectionService);
|
|
2519
2493
|
this.hostRef = inject(ElementRef);
|
|
2520
|
-
this.connectionController = inject(ConnectionControllerDirective);
|
|
2521
2494
|
this.nodeAccessor = inject(NodeAccessorService);
|
|
2522
2495
|
this.overlaysService = inject(OverlaysService);
|
|
2523
2496
|
this.zone = inject(NgZone);
|
|
2497
|
+
// TODO remove dependency from this directive
|
|
2498
|
+
this.connectionController = inject(ConnectionControllerDirective, { optional: true });
|
|
2524
2499
|
this.nodeModel = input.required();
|
|
2525
2500
|
this.nodeTemplate = input();
|
|
2526
2501
|
this.groupNodeTemplate = input();
|
|
@@ -2569,16 +2544,16 @@ class NodeComponent {
|
|
|
2569
2544
|
startConnection(event, handle) {
|
|
2570
2545
|
// ignore drag by stopping propagation
|
|
2571
2546
|
event.stopPropagation();
|
|
2572
|
-
this.connectionController
|
|
2547
|
+
this.connectionController?.startConnection(handle);
|
|
2573
2548
|
}
|
|
2574
2549
|
validateConnection(handle) {
|
|
2575
|
-
this.connectionController
|
|
2550
|
+
this.connectionController?.validateConnection(handle);
|
|
2576
2551
|
}
|
|
2577
2552
|
resetValidateConnection(targetHandle) {
|
|
2578
|
-
this.connectionController
|
|
2553
|
+
this.connectionController?.resetValidateConnection(targetHandle);
|
|
2579
2554
|
}
|
|
2580
2555
|
endConnection() {
|
|
2581
|
-
this.connectionController
|
|
2556
|
+
this.connectionController?.endConnection();
|
|
2582
2557
|
}
|
|
2583
2558
|
pullNode() {
|
|
2584
2559
|
this.nodeRenderingService.pullNode(this.nodeModel());
|
|
@@ -2932,10 +2907,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
2932
2907
|
args: ['document:touchend']
|
|
2933
2908
|
}] } });
|
|
2934
2909
|
|
|
2935
|
-
const connectionControllerHostDirective = {
|
|
2936
|
-
directive: ConnectionControllerDirective,
|
|
2937
|
-
outputs: ['onConnect'],
|
|
2938
|
-
};
|
|
2939
2910
|
const changesControllerHostDirective = {
|
|
2940
2911
|
directive: ChangesControllerDirective,
|
|
2941
2912
|
outputs: [
|
|
@@ -3208,7 +3179,7 @@ class VflowComponent {
|
|
|
3208
3179
|
ComponentEventBusService,
|
|
3209
3180
|
KeyboardService,
|
|
3210
3181
|
OverlaysService,
|
|
3211
|
-
], queries: [{ propertyName: "nodeTemplateDirective", first: true, predicate: NodeHtmlTemplateDirective, descendants: true, isSignal: true }, { propertyName: "groupNodeTemplateDirective", first: true, predicate: GroupNodeTemplateDirective, descendants: true, isSignal: true }, { propertyName: "edgeTemplateDirective", first: true, predicate: EdgeTemplateDirective, descendants: true, isSignal: true }, { propertyName: "edgeLabelHtmlDirective", first: true, predicate: EdgeLabelHtmlTemplateDirective, descendants: true, isSignal: true }, { propertyName: "connectionTemplateDirective", first: true, predicate: ConnectionTemplateDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "mapContext", first: true, predicate: MapContextDirective, descendants: true, isSignal: true }, { propertyName: "spacePointContext", first: true, predicate: SpacePointContextDirective, descendants: true, isSignal: true }], hostDirectives: [{ directive:
|
|
3182
|
+
], queries: [{ propertyName: "nodeTemplateDirective", first: true, predicate: NodeHtmlTemplateDirective, descendants: true, isSignal: true }, { propertyName: "groupNodeTemplateDirective", first: true, predicate: GroupNodeTemplateDirective, descendants: true, isSignal: true }, { propertyName: "edgeTemplateDirective", first: true, predicate: EdgeTemplateDirective, descendants: true, isSignal: true }, { propertyName: "edgeLabelHtmlDirective", first: true, predicate: EdgeLabelHtmlTemplateDirective, descendants: true, isSignal: true }, { propertyName: "connectionTemplateDirective", first: true, predicate: ConnectionTemplateDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "mapContext", first: true, predicate: MapContextDirective, descendants: true, isSignal: true }, { propertyName: "spacePointContext", first: true, predicate: SpacePointContextDirective, descendants: true, isSignal: true }], hostDirectives: [{ directive: ChangesControllerDirective, outputs: ["onNodesChange", "onNodesChange", "onNodesChange.position", "onNodesChange.position", "onNodesChange.position.single", "onNodesChange.position.single", "onNodesChange.position.many", "onNodesChange.position.many", "onNodesChange.size", "onNodesChange.size", "onNodesChange.size.single", "onNodesChange.size.single", "onNodesChange.size.many", "onNodesChange.size.many", "onNodesChange.add", "onNodesChange.add", "onNodesChange.add.single", "onNodesChange.add.single", "onNodesChange.add.many", "onNodesChange.add.many", "onNodesChange.remove", "onNodesChange.remove", "onNodesChange.remove.single", "onNodesChange.remove.single", "onNodesChange.remove.many", "onNodesChange.remove.many", "onNodesChange.select", "onNodesChange.select", "onNodesChange.select.single", "onNodesChange.select.single", "onNodesChange.select.many", "onNodesChange.select.many", "onEdgesChange", "onEdgesChange", "onEdgesChange.detached", "onEdgesChange.detached", "onEdgesChange.detached.single", "onEdgesChange.detached.single", "onEdgesChange.detached.many", "onEdgesChange.detached.many", "onEdgesChange.add", "onEdgesChange.add", "onEdgesChange.add.single", "onEdgesChange.add.single", "onEdgesChange.add.many", "onEdgesChange.add.many", "onEdgesChange.remove", "onEdgesChange.remove", "onEdgesChange.remove.single", "onEdgesChange.remove.single", "onEdgesChange.remove.many", "onEdgesChange.remove.many", "onEdgesChange.select", "onEdgesChange.select", "onEdgesChange.select.single", "onEdgesChange.select.single", "onEdgesChange.select.many", "onEdgesChange.select.many"] }], ngImport: i0, template: "<svg:svg #flow rootSvgRef rootSvgContext rootPointer flowSizeController class=\"root-svg\">\n <defs flowDefs [markers]=\"markers()\" />\n\n <g background />\n\n <svg:g mapContext spacePointContext>\n <!-- Connection -->\n <svg:g connection [model]=\"connection\" [template]=\"connectionTemplateDirective()?.templateRef\" />\n\n @if (optimization().detachedGroupsLayer) {\n <!-- Groups -->\n @for (model of groups(); track trackNodes($index, model)) {\n <svg:g\n node\n [nodeModel]=\"model\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective()?.templateRef\"\n [attr.transform]=\"model.pointTransform()\" />\n }\n <!-- Edges -->\n @for (model of edgeModels(); track trackEdges($index, model)) {\n <svg:g\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective()?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective()?.templateRef\" />\n }\n <!-- Nodes -->\n @for (model of nonGroups(); track trackNodes($index, model)) {\n <svg:g\n node\n [nodeModel]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective()?.templateRef\"\n [attr.transform]=\"model.pointTransform()\" />\n }\n }\n\n @if (!optimization().detachedGroupsLayer) {\n <!-- Edges -->\n @for (model of edgeModels(); track trackEdges($index, model)) {\n <svg:g\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective()?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective()?.templateRef\" />\n }\n <!-- Nodes -->\n @for (model of nodeModels(); track trackNodes($index, model)) {\n <svg:g\n node\n [nodeModel]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective()?.templateRef\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective()?.templateRef\"\n [attr.transform]=\"model.pointTransform()\" />\n }\n }\n </svg:g>\n\n <!-- Minimap -->\n @if (minimap(); as minimap) {\n <ng-container [ngTemplateOutlet]=\"minimap.template()\" />\n }\n</svg:svg>\n", styles: [":host{display:block;width:100%;height:100%;-webkit-user-select:none;user-select:none}:host ::ng-deep *{box-sizing:border-box}\n"], dependencies: [{ kind: "directive", type: RootSvgReferenceDirective, selector: "svg[rootSvgRef]" }, { kind: "directive", type: RootSvgContextDirective, selector: "svg[rootSvgContext]" }, { kind: "directive", type: RootPointerDirective, selector: "svg[rootPointer]" }, { kind: "directive", type: FlowSizeControllerDirective, selector: "svg[flowSizeController]" }, { kind: "component", type: DefsComponent, selector: "defs[flowDefs]", inputs: ["markers"] }, { kind: "component", type: BackgroundComponent, selector: "g[background]" }, { kind: "directive", type: MapContextDirective, selector: "g[mapContext]" }, { kind: "directive", type: SpacePointContextDirective, selector: "g[spacePointContext]" }, { kind: "component", type: ConnectionComponent, selector: "g[connection]", inputs: ["model", "template"] }, { kind: "component", type: NodeComponent, selector: "g[node]", inputs: ["nodeModel", "nodeTemplate", "groupNodeTemplate"] }, { kind: "component", type: EdgeComponent, selector: "g[edge]", inputs: ["model", "edgeTemplate", "edgeLabelHtmlTemplate"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3212
3183
|
}
|
|
3213
3184
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: VflowComponent, decorators: [{
|
|
3214
3185
|
type: Component,
|
|
@@ -3225,7 +3196,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
3225
3196
|
ComponentEventBusService,
|
|
3226
3197
|
KeyboardService,
|
|
3227
3198
|
OverlaysService,
|
|
3228
|
-
], hostDirectives: [
|
|
3199
|
+
], hostDirectives: [changesControllerHostDirective], imports: [
|
|
3229
3200
|
RootSvgReferenceDirective,
|
|
3230
3201
|
RootSvgContextDirective,
|
|
3231
3202
|
RootPointerDirective,
|
|
@@ -3532,6 +3503,7 @@ const Vflow = [
|
|
|
3532
3503
|
MiniMapComponent,
|
|
3533
3504
|
NodeToolbarComponent,
|
|
3534
3505
|
DragHandleDirective,
|
|
3506
|
+
ConnectionControllerDirective,
|
|
3535
3507
|
NodeHtmlTemplateDirective,
|
|
3536
3508
|
GroupNodeTemplateDirective,
|
|
3537
3509
|
EdgeLabelHtmlTemplateDirective,
|