ngx-vflow 1.4.1 → 1.5.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.
Files changed (52) hide show
  1. package/esm2022/lib/vflow/components/connection/connection.component.mjs +3 -3
  2. package/esm2022/lib/vflow/components/edge/edge.component.mjs +30 -5
  3. package/esm2022/lib/vflow/components/node/node.component.mjs +4 -2
  4. package/esm2022/lib/vflow/components/vflow/vflow.component.mjs +15 -3
  5. package/esm2022/lib/vflow/directives/connection-controller.directive.mjs +55 -37
  6. package/esm2022/lib/vflow/directives/root-svg-context.directive.mjs +2 -2
  7. package/esm2022/lib/vflow/directives/selectable.directive.mjs +19 -11
  8. package/esm2022/lib/vflow/interfaces/connection.interface.mjs +1 -1
  9. package/esm2022/lib/vflow/interfaces/edge.interface.mjs +1 -1
  10. package/esm2022/lib/vflow/models/edge.model.mjs +25 -23
  11. package/esm2022/lib/vflow/public-components/handle/handle.component.mjs +18 -21
  12. package/esm2022/lib/vflow/public-components/node-toolbar/node-toolbar.component.mjs +1 -1
  13. package/esm2022/lib/vflow/services/edge-rendering.service.mjs +28 -0
  14. package/esm2022/lib/vflow/services/flow-settings.service.mjs +2 -1
  15. package/esm2022/lib/vflow/services/flow-status.service.mjs +13 -1
  16. package/esm2022/lib/vflow/testing-utils/component-mocks/handle-mock.component.mjs +3 -1
  17. package/esm2022/lib/vflow/testing-utils/component-mocks/minimap-mock.component.mjs +3 -1
  18. package/esm2022/lib/vflow/testing-utils/component-mocks/node-toolbar-mock.component.mjs +5 -1
  19. package/esm2022/lib/vflow/testing-utils/component-mocks/resizable-mock.component.mjs +5 -1
  20. package/esm2022/lib/vflow/testing-utils/component-mocks/vflow-mock.component.mjs +50 -22
  21. package/esm2022/lib/vflow/testing-utils/directive-mocks/connection-controller-mock.directive.mjs +14 -2
  22. package/esm2022/lib/vflow/testing-utils/directive-mocks/drag-handle-mock.directive.mjs +1 -1
  23. package/esm2022/lib/vflow/testing-utils/directive-mocks/selectable-mock.directive.mjs +1 -1
  24. package/esm2022/lib/vflow/testing-utils/directive-mocks/template-mock.directive.mjs +1 -1
  25. package/esm2022/lib/vflow/testing-utils/types.mjs +2 -0
  26. package/fesm2022/ngx-vflow.mjs +374 -243
  27. package/fesm2022/ngx-vflow.mjs.map +1 -1
  28. package/lib/vflow/components/edge/edge.component.d.ts +10 -2
  29. package/lib/vflow/components/vflow/vflow.component.d.ts +6 -1
  30. package/lib/vflow/directives/connection-controller.directive.d.ts +5 -2
  31. package/lib/vflow/directives/selectable.directive.d.ts +4 -1
  32. package/lib/vflow/interfaces/connection.interface.d.ts +5 -0
  33. package/lib/vflow/interfaces/edge.interface.d.ts +1 -0
  34. package/lib/vflow/models/edge.model.d.ts +4 -0
  35. package/lib/vflow/public-components/handle/handle.component.d.ts +3 -6
  36. package/lib/vflow/public-components/node-toolbar/node-toolbar.component.d.ts +1 -1
  37. package/lib/vflow/services/edge-rendering.service.d.ts +10 -0
  38. package/lib/vflow/services/flow-settings.service.d.ts +1 -0
  39. package/lib/vflow/services/flow-status.service.d.ts +24 -1
  40. package/lib/vflow/testing-utils/component-mocks/handle-mock.component.d.ts +5 -2
  41. package/lib/vflow/testing-utils/component-mocks/minimap-mock.component.d.ts +5 -2
  42. package/lib/vflow/testing-utils/component-mocks/node-toolbar-mock.component.d.ts +6 -1
  43. package/lib/vflow/testing-utils/component-mocks/resizable-mock.component.d.ts +6 -1
  44. package/lib/vflow/testing-utils/component-mocks/vflow-mock.component.d.ts +27 -13
  45. package/lib/vflow/testing-utils/directive-mocks/connection-controller-mock.directive.d.ts +12 -3
  46. package/lib/vflow/testing-utils/directive-mocks/drag-handle-mock.directive.d.ts +3 -1
  47. package/lib/vflow/testing-utils/directive-mocks/selectable-mock.directive.d.ts +3 -1
  48. package/lib/vflow/testing-utils/directive-mocks/template-mock.directive.d.ts +8 -6
  49. package/lib/vflow/testing-utils/types.d.ts +1 -0
  50. package/package.json +1 -1
  51. package/esm2022/lib/vflow/decorators/run-in-injection-context.decorator.mjs +0 -18
  52. package/lib/vflow/decorators/run-in-injection-context.decorator.d.ts +0 -5
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { signal, computed, Injectable, inject, ElementRef, Directive, effect, untracked, TemplateRef, DestroyRef, EventEmitter, OutputEmitterRef, input, NgZone, viewChild, Component, ChangeDetectionStrategy, Injector, output, HostListener, runInInjectionContext, contentChild, Input, forwardRef } from '@angular/core';
2
+ import { signal, computed, Injectable, inject, ElementRef, Directive, effect, untracked, TemplateRef, DestroyRef, EventEmitter, OutputEmitterRef, input, NgZone, viewChild, Component, ChangeDetectionStrategy, output, HostListener, Injector, runInInjectionContext, 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, skip, map, pairwise, filter, distinctUntilChanged, observeOn, asyncScheduler, zip, animationFrameScheduler, share, startWith, of } from 'rxjs';
@@ -151,6 +151,7 @@ class FlowSettingsService {
151
151
  constructor() {
152
152
  this.entitiesSelectable = signal(true);
153
153
  this.elevateNodesOnSelect = signal(true);
154
+ this.elevateEdgesOnSelect = signal(true);
154
155
  /**
155
156
  * @see {VflowComponent.view}
156
157
  */
@@ -677,12 +678,24 @@ class FlowStatusService {
677
678
  setConnectionStartStatus(source, sourceHandle) {
678
679
  this.status.set({ state: 'connection-start', payload: { source, sourceHandle } });
679
680
  }
681
+ setReconnectionStartStatus(source, sourceHandle, oldEdge) {
682
+ this.status.set({ state: 'reconnection-start', payload: { source, sourceHandle, oldEdge } });
683
+ }
680
684
  setConnectionValidationStatus(valid, source, target, sourceHandle, targetHandle) {
681
685
  this.status.set({ state: 'connection-validation', payload: { source, target, sourceHandle, targetHandle, valid } });
682
686
  }
687
+ setReconnectionValidationStatus(valid, source, target, sourceHandle, targetHandle, oldEdge) {
688
+ this.status.set({
689
+ state: 'reconnection-validation',
690
+ payload: { source, target, sourceHandle, targetHandle, valid, oldEdge },
691
+ });
692
+ }
683
693
  setConnectionEndStatus(source, target, sourceHandle, targetHandle) {
684
694
  this.status.set({ state: 'connection-end', payload: { source, target, sourceHandle, targetHandle } });
685
695
  }
696
+ setReconnectionEndStatus(source, target, sourceHandle, targetHandle, oldEdge) {
697
+ this.status.set({ state: 'reconnection-end', payload: { source, target, sourceHandle, targetHandle, oldEdge } });
698
+ }
686
699
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowStatusService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
687
700
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowStatusService }); }
688
701
  }
@@ -1254,6 +1267,7 @@ class EdgeModel {
1254
1267
  this.target = signal(undefined);
1255
1268
  this.selected = signal(false);
1256
1269
  this.selected$ = toObservable(this.selected);
1270
+ this.renderOrder = signal(0);
1257
1271
  this.detached = computed(() => {
1258
1272
  const source = this.source();
1259
1273
  const target = this.target();
@@ -1278,28 +1292,8 @@ class EdgeModel {
1278
1292
  });
1279
1293
  this.detached$ = toObservable(this.detached);
1280
1294
  this.path = computed(() => {
1281
- let source;
1282
- if (this.edge.sourceHandle) {
1283
- source = this.source()
1284
- ?.handles()
1285
- .find((handle) => handle.rawHandle.id === this.edge.sourceHandle);
1286
- }
1287
- else {
1288
- source = this.source()
1289
- ?.handles()
1290
- .find((handle) => handle.rawHandle.type === 'source');
1291
- }
1292
- let target;
1293
- if (this.edge.targetHandle) {
1294
- target = this.target()
1295
- ?.handles()
1296
- .find((handle) => handle.rawHandle.id === this.edge.targetHandle);
1297
- }
1298
- else {
1299
- target = this.target()
1300
- ?.handles()
1301
- .find((handle) => handle.rawHandle.type === 'target');
1302
- }
1295
+ const source = this.sourceHandle();
1296
+ const target = this.targetHandle();
1303
1297
  // TODO: don't like this
1304
1298
  if (!source || !target) {
1305
1299
  return {
@@ -1322,9 +1316,30 @@ class EdgeModel {
1322
1316
  return smoothStepPath(source.pointAbsolute(), target.pointAbsolute(), source.rawHandle.position, target.rawHandle.position, 0);
1323
1317
  }
1324
1318
  });
1319
+ this.sourceHandle = computed(() => {
1320
+ if (this.edge.sourceHandle) {
1321
+ return (this.source()
1322
+ ?.handles()
1323
+ .find((handle) => handle.rawHandle.id === this.edge.sourceHandle) ?? null);
1324
+ }
1325
+ return (this.source()
1326
+ ?.handles()
1327
+ .find((handle) => handle.rawHandle.type === 'source') ?? null);
1328
+ });
1329
+ this.targetHandle = computed(() => {
1330
+ if (this.edge.targetHandle) {
1331
+ return (this.target()
1332
+ ?.handles()
1333
+ .find((handle) => handle.rawHandle.id === this.edge.targetHandle) ?? null);
1334
+ }
1335
+ return (this.target()
1336
+ ?.handles()
1337
+ .find((handle) => handle.rawHandle.type === 'target') ?? null);
1338
+ });
1325
1339
  this.edgeLabels = {};
1326
1340
  this.type = edge.type ?? 'default';
1327
1341
  this.curve = edge.curve ?? 'bezier';
1342
+ this.reconnectable = edge.reconnectable ?? false;
1328
1343
  if (edge.edgeLabels?.start)
1329
1344
  this.edgeLabels.start = new EdgeLabelModel(edge.edgeLabels.start);
1330
1345
  if (edge.edgeLabels?.center)
@@ -1845,76 +1860,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
1845
1860
  args: [{ standalone: true, selector: 'g[edgeLabel]', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgTemplateOutlet], template: "@if (model(); as model) {\n @if (model.edgeLabel.type === 'html-template' && htmlTemplate()) {\n @if (htmlTemplate(); as htmlTemplate) {\n <svg:foreignObject\n [attr.x]=\"edgeLabelPoint().x\"\n [attr.y]=\"edgeLabelPoint().y\"\n [attr.width]=\"model.size().width\"\n [attr.height]=\"model.size().height\">\n <div #edgeLabelWrapper class=\"edge-label-wrapper\">\n <ng-container *ngTemplateOutlet=\"htmlTemplate; context: getLabelContext()\" />\n </div>\n </svg:foreignObject>\n }\n }\n\n @if (model.edgeLabel.type === 'default') {\n <svg:foreignObject\n [attr.x]=\"edgeLabelPoint().x\"\n [attr.y]=\"edgeLabelPoint().y\"\n [attr.width]=\"model.size().width\"\n [attr.height]=\"model.size().height\">\n <div #edgeLabelWrapper class=\"edge-label-wrapper\" [style]=\"edgeLabelStyle()\">\n {{ model.edgeLabel.text }}\n </div>\n </svg:foreignObject>\n }\n}\n", styles: [".edge-label-wrapper{width:max-content;margin-top:1px;margin-left:1px}\n"] }]
1846
1861
  }] });
1847
1862
 
1848
- class EdgeComponent {
1849
- constructor() {
1850
- this.injector = inject(Injector);
1851
- this.selectionService = inject(SelectionService);
1852
- this.flowSettingsService = inject(FlowSettingsService);
1853
- this.model = input.required();
1854
- this.edgeTemplate = input();
1855
- this.edgeLabelHtmlTemplate = input();
1856
- this.markerStartUrl = computed(() => {
1857
- const marker = this.model().edge.markers?.start;
1858
- return marker ? `url(#${hashCode(JSON.stringify(marker))})` : '';
1859
- });
1860
- this.markerEndUrl = computed(() => {
1861
- const marker = this.model().edge.markers?.end;
1862
- return marker ? `url(#${hashCode(JSON.stringify(marker))})` : '';
1863
- });
1864
- }
1865
- ngOnInit() {
1866
- this.edgeContext = {
1867
- $implicit: {
1868
- // TODO: check if edge could change
1869
- edge: this.model().edge,
1870
- path: computed(() => this.model().path().path),
1871
- markerStart: this.markerStartUrl,
1872
- markerEnd: this.markerEndUrl,
1873
- selected: this.model().selected.asReadonly(),
1874
- },
1875
- };
1876
- }
1877
- onEdgeMouseDown() {
1878
- if (this.flowSettingsService.entitiesSelectable()) {
1879
- this.selectionService.select(this.model());
1880
- }
1881
- }
1882
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1883
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: EdgeComponent, isStandalone: true, selector: "g[edge]", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, edgeTemplate: { classPropertyName: "edgeTemplate", publicName: "edgeTemplate", isSignal: true, isRequired: false, transformFunction: null }, edgeLabelHtmlTemplate: { classPropertyName: "edgeLabelHtmlTemplate", publicName: "edgeLabelHtmlTemplate", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "selectable" }, ngImport: i0, template: "@if (model().type === 'default') {\n <svg:path\n class=\"edge\"\n [attr.d]=\"model().path().path\"\n [attr.marker-start]=\"markerStartUrl()\"\n [attr.marker-end]=\"markerEndUrl()\"\n [class.edge_selected]=\"model().selected()\"\n (mousedown)=\"onEdgeMouseDown()\" />\n}\n\n@if (model().type === 'template' && edgeTemplate()) {\n @if (edgeTemplate(); as edgeTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"edgeTemplate\"\n [ngTemplateOutletContext]=\"edgeContext\"\n [ngTemplateOutletInjector]=\"injector\" />\n }\n}\n\n@if (model().edgeLabels.start; as label) {\n <svg:g\n edgeLabel\n [model]=\"label\"\n [point]=\"model().path().points.start\"\n [edgeModel]=\"model()\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate()\" />\n}\n\n@if (model().edgeLabels.center; as label) {\n <svg:g\n edgeLabel\n [model]=\"label\"\n [point]=\"model().path().points.center\"\n [edgeModel]=\"model()\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate()\" />\n}\n\n@if (model().edgeLabels.end; as label) {\n <svg:g\n edgeLabel\n [model]=\"label\"\n [point]=\"model().path().points.end\"\n [edgeModel]=\"model()\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate()\" />\n}\n", styles: [".edge{fill:none;stroke-width:2;stroke:#b1b1b7}.edge_selected{stroke-width:2.5;stroke:#0f4c75}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: EdgeLabelComponent, selector: "g[edgeLabel]", inputs: ["model", "edgeModel", "point", "htmlTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1884
- }
1885
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeComponent, decorators: [{
1886
- type: Component,
1887
- args: [{ standalone: true, selector: 'g[edge]', changeDetection: ChangeDetectionStrategy.OnPush, host: {
1888
- class: 'selectable',
1889
- }, imports: [NgTemplateOutlet, EdgeLabelComponent], template: "@if (model().type === 'default') {\n <svg:path\n class=\"edge\"\n [attr.d]=\"model().path().path\"\n [attr.marker-start]=\"markerStartUrl()\"\n [attr.marker-end]=\"markerEndUrl()\"\n [class.edge_selected]=\"model().selected()\"\n (mousedown)=\"onEdgeMouseDown()\" />\n}\n\n@if (model().type === 'template' && edgeTemplate()) {\n @if (edgeTemplate(); as edgeTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"edgeTemplate\"\n [ngTemplateOutletContext]=\"edgeContext\"\n [ngTemplateOutletInjector]=\"injector\" />\n }\n}\n\n@if (model().edgeLabels.start; as label) {\n <svg:g\n edgeLabel\n [model]=\"label\"\n [point]=\"model().path().points.start\"\n [edgeModel]=\"model()\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate()\" />\n}\n\n@if (model().edgeLabels.center; as label) {\n <svg:g\n edgeLabel\n [model]=\"label\"\n [point]=\"model().path().points.center\"\n [edgeModel]=\"model()\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate()\" />\n}\n\n@if (model().edgeLabels.end; as label) {\n <svg:g\n edgeLabel\n [model]=\"label\"\n [point]=\"model().path().points.end\"\n [edgeModel]=\"model()\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate()\" />\n}\n", styles: [".edge{fill:none;stroke-width:2;stroke:#b1b1b7}.edge_selected{stroke-width:2.5;stroke:#0f4c75}\n"] }]
1890
- }] });
1891
-
1892
- class HandleService {
1893
- constructor() {
1894
- this.node = signal(null);
1895
- }
1896
- createHandle(newHandle) {
1897
- const node = this.node();
1898
- if (node) {
1899
- node.handles.update((handles) => [...handles, newHandle]);
1900
- }
1901
- }
1902
- destroyHandle(handleToDestoy) {
1903
- const node = this.node();
1904
- if (node) {
1905
- node.handles.update((handles) => handles.filter((handle) => handle !== handleToDestoy));
1906
- }
1907
- }
1908
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1909
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleService }); }
1910
- }
1911
- __decorate([
1912
- Microtask // TODO fixes rendering of handle for group node
1913
- ], HandleService.prototype, "createHandle", null);
1914
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleService, decorators: [{
1915
- type: Injectable
1916
- }], propDecorators: { createHandle: [] } });
1917
-
1918
1863
  /**
1919
1864
  * This function contains a hack-y behavior.
1920
1865
  * If the handles are of the same type (source-source or target-target),
@@ -1960,42 +1905,24 @@ class ConnectionControllerDirective {
1960
1905
  * @todo add connect event and deprecate onConnect
1961
1906
  */
1962
1907
  // eslint-disable-next-line @angular-eslint/no-output-on-prefix
1963
- this.onConnect = outputFromObservable(toObservable(this.statusService.status).pipe(filter((status) => status.state === 'connection-end'), map((status) => {
1964
- let source = status.payload.source;
1965
- let target = status.payload.target;
1966
- let sourceHandle = status.payload.sourceHandle;
1967
- let targetHandle = status.payload.targetHandle;
1968
- if (this.isStrictMode()) {
1969
- const adjusted = adjustDirection({
1970
- source: status.payload.source,
1971
- sourceHandle: status.payload.sourceHandle,
1972
- target: status.payload.target,
1973
- targetHandle: status.payload.targetHandle,
1974
- });
1975
- source = adjusted.source;
1976
- target = adjusted.target;
1977
- sourceHandle = adjusted.sourceHandle;
1978
- targetHandle = adjusted.targetHandle;
1979
- }
1980
- const sourceId = source.node.id;
1981
- const targetId = target.node.id;
1982
- const sourceHandleId = sourceHandle.rawHandle.id;
1983
- const targetHandleId = targetHandle.rawHandle.id;
1984
- return {
1985
- source: sourceId,
1986
- target: targetId,
1987
- sourceHandle: sourceHandleId,
1988
- targetHandle: targetHandleId,
1989
- };
1990
- }), tap(() => this.statusService.setIdleStatus()), filter((connection) => this.flowEntitiesService.connection().validator(connection))));
1908
+ this.onConnect = outputFromObservable(toObservable(this.statusService.status).pipe(filter((status) => status.state === 'connection-end'), map((status) => statusToConnection(status, this.isStrictMode())), tap(() => this.statusService.setIdleStatus()), filter((connection) => this.flowEntitiesService.connection().validator(connection))));
1909
+ this.onReconnect = outputFromObservable(toObservable(this.statusService.status).pipe(filter((status) => status.state === 'reconnection-end'), map((status) => {
1910
+ const connection = statusToConnection(status, this.isStrictMode());
1911
+ const oldEdge = status.payload.oldEdge.edge;
1912
+ return { connection, oldEdge };
1913
+ }), tap(() => this.statusService.setIdleStatus()), filter(({ connection }) => this.flowEntitiesService.connection().validator(connection))));
1991
1914
  this.isStrictMode = computed(() => this.flowEntitiesService.connection().mode === 'strict');
1992
1915
  }
1993
1916
  startConnection(handle) {
1994
1917
  this.statusService.setConnectionStartStatus(handle.parentNode, handle);
1995
1918
  }
1919
+ startReconnection(handle, oldEdge) {
1920
+ this.statusService.setReconnectionStartStatus(handle.parentNode, handle, oldEdge);
1921
+ }
1996
1922
  validateConnection(handle) {
1997
1923
  const status = this.statusService.status();
1998
- if (status.state === 'connection-start') {
1924
+ if (status.state === 'connection-start' || status.state === 'reconnection-start') {
1925
+ const isReconnection = status.state === 'reconnection-start';
1999
1926
  let source = status.payload.source;
2000
1927
  let target = handle.parentNode;
2001
1928
  let sourceHandle = status.payload.sourceHandle;
@@ -2024,89 +1951,97 @@ class ConnectionControllerDirective {
2024
1951
  handle.state.set(valid ? 'valid' : 'invalid');
2025
1952
  // status is about how we draw connection, so we don't need
2026
1953
  // swapped diretion here
2027
- this.statusService.setConnectionValidationStatus(valid, status.payload.source, handle.parentNode, status.payload.sourceHandle, handle);
1954
+ isReconnection
1955
+ ? this.statusService.setReconnectionValidationStatus(valid, status.payload.source, handle.parentNode, status.payload.sourceHandle, handle, status.payload.oldEdge)
1956
+ : this.statusService.setConnectionValidationStatus(valid, status.payload.source, handle.parentNode, status.payload.sourceHandle, handle);
2028
1957
  }
2029
1958
  }
2030
1959
  resetValidateConnection(targetHandle) {
2031
1960
  targetHandle.state.set('idle');
2032
1961
  // drop back to start status
2033
1962
  const status = this.statusService.status();
2034
- if (status.state === 'connection-validation') {
2035
- this.statusService.setConnectionStartStatus(status.payload.source, status.payload.sourceHandle);
1963
+ if (status.state === 'connection-validation' || status.state === 'reconnection-validation') {
1964
+ const isReconnection = status.state === 'reconnection-validation';
1965
+ isReconnection
1966
+ ? this.statusService.setReconnectionStartStatus(status.payload.source, status.payload.sourceHandle, status.payload.oldEdge)
1967
+ : this.statusService.setConnectionStartStatus(status.payload.source, status.payload.sourceHandle);
2036
1968
  }
2037
1969
  }
2038
1970
  endConnection() {
2039
1971
  const status = this.statusService.status();
2040
- if (status.state === 'connection-validation') {
1972
+ if (status.state === 'connection-validation' || status.state === 'reconnection-validation') {
1973
+ const isReconnection = status.state === 'reconnection-validation';
2041
1974
  const source = status.payload.source;
2042
1975
  const sourceHandle = status.payload.sourceHandle;
2043
1976
  const target = status.payload.target;
2044
1977
  const targetHandle = status.payload.targetHandle;
2045
- this.statusService.setConnectionEndStatus(source, target, sourceHandle, targetHandle);
1978
+ isReconnection
1979
+ ? this.statusService.setReconnectionEndStatus(source, target, sourceHandle, targetHandle, status.payload.oldEdge)
1980
+ : this.statusService.setConnectionEndStatus(source, target, sourceHandle, targetHandle);
2046
1981
  }
2047
1982
  }
2048
1983
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConnectionControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2049
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: ConnectionControllerDirective, isStandalone: true, selector: "[onConnect]", outputs: { onConnect: "onConnect" }, ngImport: i0 }); }
1984
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: ConnectionControllerDirective, isStandalone: true, selector: "[onConnect], [onReconnect]", outputs: { onConnect: "onConnect", onReconnect: "onReconnect" }, ngImport: i0 }); }
2050
1985
  }
2051
1986
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConnectionControllerDirective, decorators: [{
2052
1987
  type: Directive,
2053
1988
  args: [{
2054
- selector: '[onConnect]',
1989
+ selector: '[onConnect], [onReconnect]',
2055
1990
  standalone: true,
2056
1991
  }]
2057
1992
  }] });
1993
+ function statusToConnection(status, isStrictMode) {
1994
+ let source = status.payload.source;
1995
+ let target = status.payload.target;
1996
+ let sourceHandle = status.payload.sourceHandle;
1997
+ let targetHandle = status.payload.targetHandle;
1998
+ if (isStrictMode) {
1999
+ const adjusted = adjustDirection({
2000
+ source: status.payload.source,
2001
+ sourceHandle: status.payload.sourceHandle,
2002
+ target: status.payload.target,
2003
+ targetHandle: status.payload.targetHandle,
2004
+ });
2005
+ source = adjusted.source;
2006
+ target = adjusted.target;
2007
+ sourceHandle = adjusted.sourceHandle;
2008
+ targetHandle = adjusted.targetHandle;
2009
+ }
2010
+ const sourceId = source.node.id;
2011
+ const targetId = target.node.id;
2012
+ const sourceHandleId = sourceHandle.rawHandle.id;
2013
+ const targetHandleId = targetHandle.rawHandle.id;
2014
+ return {
2015
+ source: sourceId,
2016
+ target: targetId,
2017
+ sourceHandle: sourceHandleId,
2018
+ targetHandle: targetHandleId,
2019
+ };
2020
+ }
2058
2021
 
2059
- class HandleSizeControllerDirective {
2022
+ class EdgeRenderingService {
2060
2023
  constructor() {
2061
- this.handleModel = input.required({
2062
- alias: 'handleSizeController',
2024
+ this.flowEntitiesService = inject(FlowEntitiesService);
2025
+ this.edges = computed(() => {
2026
+ return this.flowEntitiesService.validEdges().sort((aNode, bNode) => aNode.renderOrder() - bNode.renderOrder());
2063
2027
  });
2064
- this.handleWrapper = inject(ElementRef);
2065
- }
2066
- ngAfterViewInit() {
2067
- const element = this.handleWrapper.nativeElement;
2068
- const rect = element.getBBox();
2069
- const stroke = getChildStrokeWidth(element);
2070
- this.handleModel().size.set({
2071
- width: rect.width + stroke,
2072
- height: rect.height + stroke,
2028
+ this.maxOrder = computed(() => {
2029
+ return Math.max(...this.flowEntitiesService.validEdges().map((n) => n.renderOrder()));
2073
2030
  });
2074
2031
  }
2075
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleSizeControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2076
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "17.3.12", type: HandleSizeControllerDirective, isStandalone: true, selector: "[handleSizeController]", inputs: { handleModel: { classPropertyName: "handleModel", publicName: "handleSizeController", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
2077
- }
2078
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleSizeControllerDirective, decorators: [{
2079
- type: Directive,
2080
- args: [{
2081
- standalone: true,
2082
- selector: '[handleSizeController]',
2083
- }]
2084
- }] });
2085
- function getChildStrokeWidth(element) {
2086
- const child = element.firstElementChild;
2087
- if (child) {
2088
- const stroke = getComputedStyle(child).strokeWidth;
2089
- const strokeAsNumber = Number(stroke.replace('px', ''));
2090
- if (isNaN(strokeAsNumber)) {
2091
- return 0;
2032
+ pull(edge) {
2033
+ const isAlreadyOnTop = edge.renderOrder() !== 0 && this.maxOrder() === edge.renderOrder();
2034
+ if (isAlreadyOnTop) {
2035
+ return;
2092
2036
  }
2093
- return strokeAsNumber;
2094
- }
2095
- return 0;
2096
- }
2097
-
2098
- class DefaultNodeComponent {
2099
- constructor() {
2100
- this.selected = input(false);
2037
+ // pull node
2038
+ edge.renderOrder.set(this.maxOrder() + 1);
2101
2039
  }
2102
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DefaultNodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2103
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: DefaultNodeComponent, isStandalone: true, selector: "default-node", inputs: { selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.selected": "selected()" } }, ngImport: i0, template: "<ng-content />\n", styles: [":host{border:1.5px solid #1b262c;border-radius:5px;display:flex;align-items:center;justify-content:center;color:#000;background-color:#fff}:host(.selected){border-width:2px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2040
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeRenderingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2041
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeRenderingService }); }
2104
2042
  }
2105
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DefaultNodeComponent, decorators: [{
2106
- type: Component,
2107
- args: [{ standalone: true, selector: 'default-node', host: {
2108
- '[class.selected]': 'selected()',
2109
- }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content />\n", styles: [":host{border:1.5px solid #1b262c;border-radius:5px;display:flex;align-items:center;justify-content:center;color:#000;background-color:#fff}:host(.selected){border-width:2px}\n"] }]
2043
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeRenderingService, decorators: [{
2044
+ type: Injectable
2110
2045
  }] });
2111
2046
 
2112
2047
  function isTouchEvent(event) {
@@ -2191,6 +2126,150 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
2191
2126
  args: ['mouseout', ['$event']]
2192
2127
  }] } });
2193
2128
 
2129
+ class EdgeComponent {
2130
+ constructor() {
2131
+ this.injector = inject(Injector);
2132
+ this.selectionService = inject(SelectionService);
2133
+ this.flowSettingsService = inject(FlowSettingsService);
2134
+ this.flowStatusService = inject(FlowStatusService);
2135
+ this.edgeRenderingService = inject(EdgeRenderingService);
2136
+ // TODO remove dependency from this directive
2137
+ this.connectionController = inject(ConnectionControllerDirective, { optional: true });
2138
+ this.model = input.required();
2139
+ this.edgeTemplate = input();
2140
+ this.edgeLabelHtmlTemplate = input();
2141
+ this.interactiveEdgeRef = viewChild.required('interactiveEdge');
2142
+ this.markerStartUrl = computed(() => {
2143
+ const marker = this.model().edge.markers?.start;
2144
+ return marker ? `url(#${hashCode(JSON.stringify(marker))})` : '';
2145
+ });
2146
+ this.markerEndUrl = computed(() => {
2147
+ const marker = this.model().edge.markers?.end;
2148
+ return marker ? `url(#${hashCode(JSON.stringify(marker))})` : '';
2149
+ });
2150
+ this.isReconnecting = computed(() => {
2151
+ const status = this.flowStatusService.status();
2152
+ const isReconnecting = status.state === 'reconnection-start' || status.state === 'reconnection-validation';
2153
+ return isReconnecting && status.payload.oldEdge === this.model();
2154
+ });
2155
+ }
2156
+ ngOnInit() {
2157
+ this.edgeContext = {
2158
+ $implicit: {
2159
+ // TODO: check if edge could change
2160
+ edge: this.model().edge,
2161
+ path: computed(() => this.model().path().path),
2162
+ markerStart: this.markerStartUrl,
2163
+ markerEnd: this.markerEndUrl,
2164
+ selected: this.model().selected.asReadonly(),
2165
+ },
2166
+ };
2167
+ }
2168
+ select() {
2169
+ if (this.flowSettingsService.entitiesSelectable()) {
2170
+ this.selectionService.select(this.model());
2171
+ }
2172
+ }
2173
+ pull() {
2174
+ if (this.flowSettingsService.elevateEdgesOnSelect()) {
2175
+ this.edgeRenderingService.pull(this.model());
2176
+ }
2177
+ }
2178
+ startReconnection(event, handle) {
2179
+ // ignore drag by stopping propagation
2180
+ event.stopPropagation();
2181
+ this.connectionController?.startReconnection(handle, this.model());
2182
+ }
2183
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2184
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: EdgeComponent, isStandalone: true, selector: "g[edge]", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, edgeTemplate: { classPropertyName: "edgeTemplate", publicName: "edgeTemplate", isSignal: true, isRequired: false, transformFunction: null }, edgeLabelHtmlTemplate: { classPropertyName: "edgeLabelHtmlTemplate", publicName: "edgeLabelHtmlTemplate", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.visibility": "isReconnecting() ? \"hidden\" : \"visible\"" }, classAttribute: "selectable" }, viewQueries: [{ propertyName: "interactiveEdgeRef", first: true, predicate: ["interactiveEdge"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (model().type === 'default') {\n <svg:path\n class=\"edge\"\n [attr.d]=\"model().path().path\"\n [attr.marker-start]=\"markerStartUrl()\"\n [attr.marker-end]=\"markerEndUrl()\"\n [class.edge_selected]=\"model().selected()\" />\n\n <svg:path\n #interactiveEdge\n class=\"interactive-edge\"\n [attr.d]=\"model().path().path\"\n (pointerStart)=\"select(); pull()\" />\n}\n\n@if (model().type === 'template' && edgeTemplate()) {\n @if (edgeTemplate(); as edgeTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"edgeTemplate\"\n [ngTemplateOutletContext]=\"edgeContext\"\n [ngTemplateOutletInjector]=\"injector\" />\n\n <svg:path #interactiveEdge class=\"interactive-edge\" [attr.d]=\"model().path().path\" (pointerStart)=\"pull()\" />\n }\n}\n\n@if (model().edgeLabels.start; as label) {\n <svg:g\n edgeLabel\n [model]=\"label\"\n [point]=\"model().path().points.start\"\n [edgeModel]=\"model()\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate()\" />\n}\n\n@if (model().edgeLabels.center; as label) {\n <svg:g\n edgeLabel\n [model]=\"label\"\n [point]=\"model().path().points.center\"\n [edgeModel]=\"model()\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate()\" />\n}\n\n@if (model().edgeLabels.end; as label) {\n <svg:g\n edgeLabel\n [model]=\"label\"\n [point]=\"model().path().points.end\"\n [edgeModel]=\"model()\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate()\" />\n}\n\n@if (model().sourceHandle() && model().targetHandle()) {\n @if (model().reconnectable === true || model().reconnectable === 'source') {\n <svg:circle\n class=\"reconnect-handle\"\n r=\"10\"\n [attr.cx]=\"model().sourceHandle()!.pointAbsolute().x\"\n [attr.cy]=\"model().sourceHandle()!.pointAbsolute().y\"\n (pointerStart)=\"startReconnection($event, model().targetHandle()!)\" />\n }\n\n @if (model().reconnectable === true || model().reconnectable === 'target') {\n <svg:circle\n class=\"reconnect-handle\"\n r=\"10\"\n [attr.cx]=\"model().targetHandle()!.pointAbsolute().x\"\n [attr.cy]=\"model().targetHandle()!.pointAbsolute().y\"\n (pointerStart)=\"startReconnection($event, model().sourceHandle()!)\" />\n }\n}\n", styles: [".edge{fill:none;stroke-width:2;stroke:#b1b1b7}.edge_selected{stroke-width:2.5;stroke:#0f4c75}.interactive-edge{fill:none;stroke-width:20;stroke:transparent}.reconnect-handle{fill:transparent;cursor:move}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: EdgeLabelComponent, selector: "g[edgeLabel]", inputs: ["model", "edgeModel", "point", "htmlTemplate"] }, { kind: "directive", type: PointerDirective, selector: "[pointerStart], [pointerEnd], [pointerOver], [pointerOut]", outputs: ["pointerOver", "pointerOut", "pointerStart", "pointerEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2185
+ }
2186
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeComponent, decorators: [{
2187
+ type: Component,
2188
+ args: [{ standalone: true, selector: 'g[edge]', changeDetection: ChangeDetectionStrategy.OnPush, host: {
2189
+ class: 'selectable',
2190
+ '[style.visibility]': 'isReconnecting() ? "hidden" : "visible"',
2191
+ }, imports: [NgTemplateOutlet, EdgeLabelComponent, PointerDirective], template: "@if (model().type === 'default') {\n <svg:path\n class=\"edge\"\n [attr.d]=\"model().path().path\"\n [attr.marker-start]=\"markerStartUrl()\"\n [attr.marker-end]=\"markerEndUrl()\"\n [class.edge_selected]=\"model().selected()\" />\n\n <svg:path\n #interactiveEdge\n class=\"interactive-edge\"\n [attr.d]=\"model().path().path\"\n (pointerStart)=\"select(); pull()\" />\n}\n\n@if (model().type === 'template' && edgeTemplate()) {\n @if (edgeTemplate(); as edgeTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"edgeTemplate\"\n [ngTemplateOutletContext]=\"edgeContext\"\n [ngTemplateOutletInjector]=\"injector\" />\n\n <svg:path #interactiveEdge class=\"interactive-edge\" [attr.d]=\"model().path().path\" (pointerStart)=\"pull()\" />\n }\n}\n\n@if (model().edgeLabels.start; as label) {\n <svg:g\n edgeLabel\n [model]=\"label\"\n [point]=\"model().path().points.start\"\n [edgeModel]=\"model()\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate()\" />\n}\n\n@if (model().edgeLabels.center; as label) {\n <svg:g\n edgeLabel\n [model]=\"label\"\n [point]=\"model().path().points.center\"\n [edgeModel]=\"model()\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate()\" />\n}\n\n@if (model().edgeLabels.end; as label) {\n <svg:g\n edgeLabel\n [model]=\"label\"\n [point]=\"model().path().points.end\"\n [edgeModel]=\"model()\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate()\" />\n}\n\n@if (model().sourceHandle() && model().targetHandle()) {\n @if (model().reconnectable === true || model().reconnectable === 'source') {\n <svg:circle\n class=\"reconnect-handle\"\n r=\"10\"\n [attr.cx]=\"model().sourceHandle()!.pointAbsolute().x\"\n [attr.cy]=\"model().sourceHandle()!.pointAbsolute().y\"\n (pointerStart)=\"startReconnection($event, model().targetHandle()!)\" />\n }\n\n @if (model().reconnectable === true || model().reconnectable === 'target') {\n <svg:circle\n class=\"reconnect-handle\"\n r=\"10\"\n [attr.cx]=\"model().targetHandle()!.pointAbsolute().x\"\n [attr.cy]=\"model().targetHandle()!.pointAbsolute().y\"\n (pointerStart)=\"startReconnection($event, model().sourceHandle()!)\" />\n }\n}\n", styles: [".edge{fill:none;stroke-width:2;stroke:#b1b1b7}.edge_selected{stroke-width:2.5;stroke:#0f4c75}.interactive-edge{fill:none;stroke-width:20;stroke:transparent}.reconnect-handle{fill:transparent;cursor:move}\n"] }]
2192
+ }] });
2193
+
2194
+ class HandleService {
2195
+ constructor() {
2196
+ this.node = signal(null);
2197
+ }
2198
+ createHandle(newHandle) {
2199
+ const node = this.node();
2200
+ if (node) {
2201
+ node.handles.update((handles) => [...handles, newHandle]);
2202
+ }
2203
+ }
2204
+ destroyHandle(handleToDestoy) {
2205
+ const node = this.node();
2206
+ if (node) {
2207
+ node.handles.update((handles) => handles.filter((handle) => handle !== handleToDestoy));
2208
+ }
2209
+ }
2210
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2211
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleService }); }
2212
+ }
2213
+ __decorate([
2214
+ Microtask // TODO fixes rendering of handle for group node
2215
+ ], HandleService.prototype, "createHandle", null);
2216
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleService, decorators: [{
2217
+ type: Injectable
2218
+ }], propDecorators: { createHandle: [] } });
2219
+
2220
+ class HandleSizeControllerDirective {
2221
+ constructor() {
2222
+ this.handleModel = input.required({
2223
+ alias: 'handleSizeController',
2224
+ });
2225
+ this.handleWrapper = inject(ElementRef);
2226
+ }
2227
+ ngAfterViewInit() {
2228
+ const element = this.handleWrapper.nativeElement;
2229
+ const rect = element.getBBox();
2230
+ const stroke = getChildStrokeWidth(element);
2231
+ this.handleModel().size.set({
2232
+ width: rect.width + stroke,
2233
+ height: rect.height + stroke,
2234
+ });
2235
+ }
2236
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleSizeControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2237
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "17.3.12", type: HandleSizeControllerDirective, isStandalone: true, selector: "[handleSizeController]", inputs: { handleModel: { classPropertyName: "handleModel", publicName: "handleSizeController", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
2238
+ }
2239
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleSizeControllerDirective, decorators: [{
2240
+ type: Directive,
2241
+ args: [{
2242
+ standalone: true,
2243
+ selector: '[handleSizeController]',
2244
+ }]
2245
+ }] });
2246
+ function getChildStrokeWidth(element) {
2247
+ const child = element.firstElementChild;
2248
+ if (child) {
2249
+ const stroke = getComputedStyle(child).strokeWidth;
2250
+ const strokeAsNumber = Number(stroke.replace('px', ''));
2251
+ if (isNaN(strokeAsNumber)) {
2252
+ return 0;
2253
+ }
2254
+ return strokeAsNumber;
2255
+ }
2256
+ return 0;
2257
+ }
2258
+
2259
+ class DefaultNodeComponent {
2260
+ constructor() {
2261
+ this.selected = input(false);
2262
+ }
2263
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DefaultNodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2264
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: DefaultNodeComponent, isStandalone: true, selector: "default-node", inputs: { selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.selected": "selected()" } }, ngImport: i0, template: "<ng-content />\n", styles: [":host{border:1.5px solid #1b262c;border-radius:5px;display:flex;align-items:center;justify-content:center;color:#000;background-color:#fff}:host(.selected){border-width:2px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2265
+ }
2266
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DefaultNodeComponent, decorators: [{
2267
+ type: Component,
2268
+ args: [{ standalone: true, selector: 'default-node', host: {
2269
+ '[class.selected]': 'selected()',
2270
+ }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content />\n", styles: [":host{border:1.5px solid #1b262c;border-radius:5px;display:flex;align-items:center;justify-content:center;color:#000;background-color:#fff}:host(.selected){border-width:2px}\n"] }]
2271
+ }] });
2272
+
2194
2273
  class ResizableComponent {
2195
2274
  get model() {
2196
2275
  return this.nodeAccessor.model();
@@ -2470,23 +2549,6 @@ class HandleModel {
2470
2549
  }
2471
2550
  }
2472
2551
 
2473
- function InjectionContext(target, key, descriptor) {
2474
- const originalMethod = descriptor.value;
2475
- descriptor.value = function (...args) {
2476
- if (implementsWithInjector(this)) {
2477
- return runInInjectionContext(this.injector, () => originalMethod.apply(this, args));
2478
- }
2479
- else {
2480
- throw new Error('Class that contains decorated method must extends WithInjectorDirective class');
2481
- }
2482
- };
2483
- // Return the modified descriptor
2484
- return descriptor;
2485
- }
2486
- const implementsWithInjector = (instance) => {
2487
- return 'injector' in instance && 'get' in instance.injector;
2488
- };
2489
-
2490
2552
  class HandleComponent {
2491
2553
  constructor() {
2492
2554
  this.injector = inject(Injector);
@@ -2508,30 +2570,29 @@ class HandleComponent {
2508
2570
  this.template = input();
2509
2571
  }
2510
2572
  ngOnInit() {
2511
- const node = this.handleService.node();
2512
- if (node) {
2513
- this.model = new HandleModel({
2514
- position: this.position(),
2515
- type: this.type(),
2516
- id: this.id(),
2517
- hostReference: this.element.parentElement,
2518
- template: this.template(),
2519
- }, node);
2520
- this.handleService.createHandle(this.model);
2521
- requestAnimationFrame(() => this.model.updateHost());
2522
- this.destroyRef.onDestroy(() => this.handleService.destroyHandle(this.model));
2523
- }
2573
+ runInInjectionContext(this.injector, () => {
2574
+ const node = this.handleService.node();
2575
+ if (node) {
2576
+ const model = new HandleModel({
2577
+ position: this.position(),
2578
+ type: this.type(),
2579
+ id: this.id(),
2580
+ hostReference: this.element.parentElement,
2581
+ template: this.template(),
2582
+ }, node);
2583
+ this.handleService.createHandle(model);
2584
+ requestAnimationFrame(() => model.updateHost());
2585
+ this.destroyRef.onDestroy(() => this.handleService.destroyHandle(model));
2586
+ }
2587
+ });
2524
2588
  }
2525
2589
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2526
2590
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: HandleComponent, isStandalone: true, selector: "handle", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: true, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: true, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, template: { classPropertyName: "template", publicName: "template", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2527
2591
  }
2528
- __decorate([
2529
- InjectionContext
2530
- ], HandleComponent.prototype, "ngOnInit", null);
2531
2592
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleComponent, decorators: [{
2532
2593
  type: Component,
2533
2594
  args: [{ standalone: true, selector: 'handle', changeDetection: ChangeDetectionStrategy.OnPush, template: "" }]
2534
- }], propDecorators: { ngOnInit: [] } });
2595
+ }] });
2535
2596
 
2536
2597
  class NodeHandlesControllerDirective {
2537
2598
  constructor() {
@@ -2607,7 +2668,9 @@ class NodeComponent {
2607
2668
  this.nodeTemplate = input();
2608
2669
  this.groupNodeTemplate = input();
2609
2670
  this.showMagnet = computed(() => this.flowStatusService.status().state === 'connection-start' ||
2610
- this.flowStatusService.status().state === 'connection-validation');
2671
+ this.flowStatusService.status().state === 'connection-validation' ||
2672
+ this.flowStatusService.status().state === 'reconnection-start' ||
2673
+ this.flowStatusService.status().state === 'reconnection-validation');
2611
2674
  this.toolbar = computed(() => this.overlaysService.nodeToolbars().get(this.model()));
2612
2675
  }
2613
2676
  ngOnInit() {
@@ -2677,7 +2740,7 @@ class ConnectionComponent {
2677
2740
  this.spacePointContext = inject(SpacePointContextDirective);
2678
2741
  this.path = computed(() => {
2679
2742
  const status = this.flowStatusService.status();
2680
- if (status.state === 'connection-start') {
2743
+ if (status.state === 'connection-start' || status.state === 'reconnection-start') {
2681
2744
  const sourceHandle = status.payload.sourceHandle;
2682
2745
  const sourcePoint = sourceHandle.pointAbsolute();
2683
2746
  const sourcePosition = sourceHandle.rawHandle.position;
@@ -2694,7 +2757,7 @@ class ConnectionComponent {
2694
2757
  return smoothStepPath(sourcePoint, targetPoint, sourcePosition, targetPosition, 0).path;
2695
2758
  }
2696
2759
  }
2697
- if (status.state === 'connection-validation') {
2760
+ if (status.state === 'connection-validation' || status.state === 'reconnection-validation') {
2698
2761
  const sourceHandle = status.payload.sourceHandle;
2699
2762
  const sourcePoint = sourceHandle.pointAbsolute();
2700
2763
  const sourcePosition = sourceHandle.rawHandle.position;
@@ -2968,7 +3031,7 @@ class RootSvgContextDirective {
2968
3031
  // TODO: check for multiple instances on page
2969
3032
  resetConnection() {
2970
3033
  const status = this.flowStatusService.status();
2971
- if (status.state === 'connection-start') {
3034
+ if (status.state === 'connection-start' || status.state === 'reconnection-start') {
2972
3035
  this.flowStatusService.setIdleStatus();
2973
3036
  }
2974
3037
  }
@@ -3034,6 +3097,7 @@ class VflowComponent {
3034
3097
  this.nodesChangeService = inject(NodesChangeService);
3035
3098
  this.edgesChangeService = inject(EdgeChangesService);
3036
3099
  this.nodeRenderingService = inject(NodeRenderingService);
3100
+ this.edgeRenderingService = inject(EdgeRenderingService);
3037
3101
  this.flowSettingsService = inject(FlowSettingsService);
3038
3102
  this.componentEventBusService = inject(ComponentEventBusService);
3039
3103
  this.keyboardService = inject(KeyboardService);
@@ -3044,7 +3108,7 @@ class VflowComponent {
3044
3108
  this.nodeModels = computed(() => this.nodeRenderingService.nodes());
3045
3109
  this.groups = computed(() => this.nodeRenderingService.groups());
3046
3110
  this.nonGroups = computed(() => this.nodeRenderingService.nonGroups());
3047
- this.edgeModels = computed(() => this.flowEntitiesService.validEdges());
3111
+ this.edgeModels = computed(() => this.edgeRenderingService.edges());
3048
3112
  // #endregion
3049
3113
  // #region OUTPUTS
3050
3114
  /**
@@ -3162,6 +3226,12 @@ class VflowComponent {
3162
3226
  set elevateNodesOnSelect(value) {
3163
3227
  this.flowSettingsService.elevateNodesOnSelect.set(value);
3164
3228
  }
3229
+ /**
3230
+ * Raizing z-index for selected edge
3231
+ */
3232
+ set elevateEdgesOnSelect(value) {
3233
+ this.flowSettingsService.elevateEdgesOnSelect.set(value);
3234
+ }
3165
3235
  // #endregion
3166
3236
  // #region MAIN_INPUTS
3167
3237
  /**
@@ -3263,7 +3333,7 @@ class VflowComponent {
3263
3333
  });
3264
3334
  }
3265
3335
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: VflowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3266
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: VflowComponent, isStandalone: true, selector: "vflow", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: false, isRequired: false, transformFunction: null }, minZoom: { classPropertyName: "minZoom", publicName: "minZoom", isSignal: false, isRequired: false, transformFunction: null }, maxZoom: { classPropertyName: "maxZoom", publicName: "maxZoom", isSignal: false, isRequired: false, transformFunction: null }, background: { classPropertyName: "background", publicName: "background", isSignal: false, isRequired: false, transformFunction: null }, optimization: { classPropertyName: "optimization", publicName: "optimization", isSignal: true, isRequired: false, transformFunction: null }, entitiesSelectable: { classPropertyName: "entitiesSelectable", publicName: "entitiesSelectable", isSignal: false, isRequired: false, transformFunction: null }, keyboardShortcuts: { classPropertyName: "keyboardShortcuts", publicName: "keyboardShortcuts", isSignal: false, isRequired: false, transformFunction: null }, connection: { classPropertyName: "connection", publicName: "connection", isSignal: false, isRequired: false, transformFunction: (settings) => new ConnectionModel(settings) }, snapGrid: { classPropertyName: "snapGrid", publicName: "snapGrid", isSignal: false, isRequired: false, transformFunction: null }, elevateNodesOnSelect: { classPropertyName: "elevateNodesOnSelect", publicName: "elevateNodesOnSelect", isSignal: false, isRequired: false, transformFunction: null }, nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: false, isRequired: true, transformFunction: null }, edges: { classPropertyName: "edges", publicName: "edges", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { onComponentNodeEvent: "onComponentNodeEvent" }, providers: [
3336
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: VflowComponent, isStandalone: true, selector: "vflow", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: false, isRequired: false, transformFunction: null }, minZoom: { classPropertyName: "minZoom", publicName: "minZoom", isSignal: false, isRequired: false, transformFunction: null }, maxZoom: { classPropertyName: "maxZoom", publicName: "maxZoom", isSignal: false, isRequired: false, transformFunction: null }, background: { classPropertyName: "background", publicName: "background", isSignal: false, isRequired: false, transformFunction: null }, optimization: { classPropertyName: "optimization", publicName: "optimization", isSignal: true, isRequired: false, transformFunction: null }, entitiesSelectable: { classPropertyName: "entitiesSelectable", publicName: "entitiesSelectable", isSignal: false, isRequired: false, transformFunction: null }, keyboardShortcuts: { classPropertyName: "keyboardShortcuts", publicName: "keyboardShortcuts", isSignal: false, isRequired: false, transformFunction: null }, connection: { classPropertyName: "connection", publicName: "connection", isSignal: false, isRequired: false, transformFunction: (settings) => new ConnectionModel(settings) }, snapGrid: { classPropertyName: "snapGrid", publicName: "snapGrid", isSignal: false, isRequired: false, transformFunction: null }, elevateNodesOnSelect: { classPropertyName: "elevateNodesOnSelect", publicName: "elevateNodesOnSelect", isSignal: false, isRequired: false, transformFunction: null }, elevateEdgesOnSelect: { classPropertyName: "elevateEdgesOnSelect", publicName: "elevateEdgesOnSelect", isSignal: false, isRequired: false, transformFunction: null }, nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: false, isRequired: true, transformFunction: null }, edges: { classPropertyName: "edges", publicName: "edges", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { onComponentNodeEvent: "onComponentNodeEvent" }, providers: [
3267
3337
  DraggableService,
3268
3338
  ViewportService,
3269
3339
  FlowStatusService,
@@ -3271,6 +3341,7 @@ class VflowComponent {
3271
3341
  NodesChangeService,
3272
3342
  EdgeChangesService,
3273
3343
  NodeRenderingService,
3344
+ EdgeRenderingService,
3274
3345
  SelectionService,
3275
3346
  FlowSettingsService,
3276
3347
  ComponentEventBusService,
@@ -3288,6 +3359,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3288
3359
  NodesChangeService,
3289
3360
  EdgeChangesService,
3290
3361
  NodeRenderingService,
3362
+ EdgeRenderingService,
3291
3363
  SelectionService,
3292
3364
  FlowSettingsService,
3293
3365
  ComponentEventBusService,
@@ -3328,6 +3400,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3328
3400
  type: Input
3329
3401
  }], elevateNodesOnSelect: [{
3330
3402
  type: Input
3403
+ }], elevateEdgesOnSelect: [{
3404
+ type: Input
3331
3405
  }], nodes: [{
3332
3406
  type: Input,
3333
3407
  args: [{ required: true }]
@@ -3366,8 +3440,12 @@ class SelectableDirective {
3366
3440
  this.selectionService = inject(SelectionService);
3367
3441
  this.parentEdge = inject(EdgeComponent, { optional: true });
3368
3442
  this.parentNode = inject(NodeComponent, { optional: true });
3443
+ this.host = inject(ElementRef);
3444
+ this.selectOnEvent = this.getEvent$()
3445
+ .pipe(tap(() => this.select()), takeUntilDestroyed())
3446
+ .subscribe();
3369
3447
  }
3370
- onMousedown() {
3448
+ select() {
3371
3449
  const entity = this.entity();
3372
3450
  if (entity && this.flowSettingsService.entitiesSelectable()) {
3373
3451
  this.selectionService.select(entity);
@@ -3382,8 +3460,16 @@ class SelectableDirective {
3382
3460
  }
3383
3461
  return null;
3384
3462
  }
3463
+ getEvent$() {
3464
+ if (this.parentEdge) {
3465
+ // get not the edge itself, but the interactive edge (which is more UX friendly)
3466
+ const interactiveEdge = this.parentEdge.interactiveEdgeRef().nativeElement;
3467
+ return merge(fromEvent(interactiveEdge, 'mousedown'), fromEvent(interactiveEdge, 'touchstart'));
3468
+ }
3469
+ return merge(fromEvent(this.host.nativeElement, 'mousedown'), fromEvent(this.host.nativeElement, 'touchstart'));
3470
+ }
3385
3471
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3386
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: SelectableDirective, isStandalone: true, selector: "[selectable]", host: { listeners: { "mousedown": "onMousedown()", "touchstart": "onMousedown()" } }, ngImport: i0 }); }
3472
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: SelectableDirective, isStandalone: true, selector: "[selectable]", ngImport: i0 }); }
3387
3473
  }
3388
3474
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectableDirective, decorators: [{
3389
3475
  type: Directive,
@@ -3391,13 +3477,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3391
3477
  standalone: true,
3392
3478
  selector: '[selectable]',
3393
3479
  }]
3394
- }], propDecorators: { onMousedown: [{
3395
- type: HostListener,
3396
- args: ['mousedown']
3397
- }, {
3398
- type: HostListener,
3399
- args: ['touchstart']
3400
- }] } });
3480
+ }] });
3401
3481
 
3402
3482
  class MinimapModel {
3403
3483
  constructor() {
@@ -3756,20 +3836,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3756
3836
 
3757
3837
  class VflowMockComponent {
3758
3838
  constructor() {
3759
- this.nodes = input.required();
3760
- this.edges = input.required();
3761
- this.view = input([400, 400]);
3762
- this.minZoom = input(0.5);
3763
- this.maxZoom = input(3);
3764
- this.background = input('#fff');
3839
+ this.view = [400, 400];
3840
+ this.minZoom = 0.5;
3841
+ this.maxZoom = 3;
3842
+ this.background = '#fff';
3765
3843
  this.optimization = input({
3766
3844
  detachedGroupsLayer: false,
3767
3845
  });
3768
- this.entitiesSelectable = input(true);
3769
- this.keyboardShortcuts = input({
3846
+ this.entitiesSelectable = true;
3847
+ this.keyboardShortcuts = {
3770
3848
  multiSelection: null,
3771
- });
3772
- this.connection = input();
3849
+ };
3850
+ this.connection = new ConnectionModel({});
3773
3851
  // eslint-disable-next-line @angular-eslint/no-output-on-prefix
3774
3852
  this.onComponentNodeEvent = output();
3775
3853
  this.nodeTemplateDirective = contentChild(NodeHtmlTemplateMockDirective);
@@ -3788,6 +3866,8 @@ class VflowMockComponent {
3788
3866
  this.nodesChange$ = toObservable(this.nodesChange);
3789
3867
  this.edgesChange$ = toObservable(this.edgesChange);
3790
3868
  }
3869
+ // eslint-disable-next-line @angular-eslint/no-empty-lifecycle-method
3870
+ ngOnInit() { }
3791
3871
  viewportTo(viewport) {
3792
3872
  this.viewport.set(viewport);
3793
3873
  }
@@ -3802,9 +3882,8 @@ class VflowMockComponent {
3802
3882
  documentPointToFlowPoint(point) {
3803
3883
  return point;
3804
3884
  }
3805
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3806
3885
  getNode(id) {
3807
- return this.nodes().find((node) => node.id === id);
3886
+ return this.nodes.find((node) => node.id === id);
3808
3887
  }
3809
3888
  getDetachedEdges() {
3810
3889
  return [];
@@ -3813,10 +3892,10 @@ class VflowMockComponent {
3813
3892
  return signal(value);
3814
3893
  }
3815
3894
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: VflowMockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3816
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: VflowMockComponent, isStandalone: true, selector: "vflow", inputs: { nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: true, transformFunction: null }, edges: { classPropertyName: "edges", publicName: "edges", isSignal: true, isRequired: true, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null }, minZoom: { classPropertyName: "minZoom", publicName: "minZoom", isSignal: true, isRequired: false, transformFunction: null }, maxZoom: { classPropertyName: "maxZoom", publicName: "maxZoom", isSignal: true, isRequired: false, transformFunction: null }, background: { classPropertyName: "background", publicName: "background", isSignal: true, isRequired: false, transformFunction: null }, optimization: { classPropertyName: "optimization", publicName: "optimization", isSignal: true, isRequired: false, transformFunction: null }, entitiesSelectable: { classPropertyName: "entitiesSelectable", publicName: "entitiesSelectable", isSignal: true, isRequired: false, transformFunction: null }, keyboardShortcuts: { classPropertyName: "keyboardShortcuts", publicName: "keyboardShortcuts", isSignal: true, isRequired: false, transformFunction: null }, connection: { classPropertyName: "connection", publicName: "connection", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onComponentNodeEvent: "onComponentNodeEvent" }, queries: [{ propertyName: "nodeTemplateDirective", first: true, predicate: NodeHtmlTemplateMockDirective, descendants: true, isSignal: true }, { propertyName: "groupNodeTemplateDirective", first: true, predicate: GroupNodeTemplateMockDirective, descendants: true, isSignal: true }, { propertyName: "edgeTemplateDirective", first: true, predicate: EdgeTemplateMockDirective, descendants: true, isSignal: true }, { propertyName: "edgeLabelHtmlDirective", first: true, predicate: EdgeLabelHtmlTemplateMockDirective, descendants: true, isSignal: true }, { propertyName: "connectionTemplateDirective", first: true, predicate: ConnectionTemplateMockDirective, descendants: true, isSignal: true }], ngImport: i0, template: `
3895
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: VflowMockComponent, isStandalone: true, selector: "vflow", inputs: { nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: false, isRequired: true, transformFunction: null }, edges: { classPropertyName: "edges", publicName: "edges", isSignal: false, isRequired: false, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: false, isRequired: false, transformFunction: null }, minZoom: { classPropertyName: "minZoom", publicName: "minZoom", isSignal: false, isRequired: false, transformFunction: null }, maxZoom: { classPropertyName: "maxZoom", publicName: "maxZoom", isSignal: false, isRequired: false, transformFunction: null }, background: { classPropertyName: "background", publicName: "background", isSignal: false, isRequired: false, transformFunction: null }, optimization: { classPropertyName: "optimization", publicName: "optimization", isSignal: true, isRequired: false, transformFunction: null }, entitiesSelectable: { classPropertyName: "entitiesSelectable", publicName: "entitiesSelectable", isSignal: false, isRequired: false, transformFunction: null }, keyboardShortcuts: { classPropertyName: "keyboardShortcuts", publicName: "keyboardShortcuts", isSignal: false, isRequired: false, transformFunction: null }, connection: { classPropertyName: "connection", publicName: "connection", isSignal: false, isRequired: false, transformFunction: (settings) => new ConnectionModel(settings) }, snapGrid: { classPropertyName: "snapGrid", publicName: "snapGrid", isSignal: false, isRequired: false, transformFunction: null }, elevateNodesOnSelect: { classPropertyName: "elevateNodesOnSelect", publicName: "elevateNodesOnSelect", isSignal: false, isRequired: false, transformFunction: null }, elevateEdgesOnSelect: { classPropertyName: "elevateEdgesOnSelect", publicName: "elevateEdgesOnSelect", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { onComponentNodeEvent: "onComponentNodeEvent" }, queries: [{ propertyName: "nodeTemplateDirective", first: true, predicate: NodeHtmlTemplateMockDirective, descendants: true, isSignal: true }, { propertyName: "groupNodeTemplateDirective", first: true, predicate: GroupNodeTemplateMockDirective, descendants: true, isSignal: true }, { propertyName: "edgeTemplateDirective", first: true, predicate: EdgeTemplateMockDirective, descendants: true, isSignal: true }, { propertyName: "edgeLabelHtmlDirective", first: true, predicate: EdgeLabelHtmlTemplateMockDirective, descendants: true, isSignal: true }, { propertyName: "connectionTemplateDirective", first: true, predicate: ConnectionTemplateMockDirective, descendants: true, isSignal: true }], ngImport: i0, template: `
3817
3896
  <ng-content />
3818
3897
 
3819
- @for (node of nodes(); track $index) {
3898
+ @for (node of nodes; track $index) {
3820
3899
  @if (node.type === 'html-template') {
3821
3900
  <ng-component
3822
3901
  [ngTemplateOutlet]="nodeTemplateDirective()?.templateRef ?? null"
@@ -3842,7 +3921,7 @@ class VflowMockComponent {
3842
3921
  }
3843
3922
  }
3844
3923
 
3845
- @for (edge of edges(); track $index) {
3924
+ @for (edge of edges; track $index) {
3846
3925
  @if (edge.type === 'template') {
3847
3926
  <ng-component
3848
3927
  [ngTemplateOutlet]="edgeTemplateDirective()?.templateRef ?? null"
@@ -3890,7 +3969,7 @@ class VflowMockComponent {
3890
3969
  }
3891
3970
  }
3892
3971
 
3893
- @if (connection()?.type === 'template') {
3972
+ @if (connection.type === 'template') {
3894
3973
  <ng-component
3895
3974
  [ngTemplateOutlet]="connectionTemplateDirective()?.templateRef ?? null"
3896
3975
  [ngTemplateOutletContext]="{
@@ -3909,7 +3988,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3909
3988
  template: `
3910
3989
  <ng-content />
3911
3990
 
3912
- @for (node of nodes(); track $index) {
3991
+ @for (node of nodes; track $index) {
3913
3992
  @if (node.type === 'html-template') {
3914
3993
  <ng-component
3915
3994
  [ngTemplateOutlet]="nodeTemplateDirective()?.templateRef ?? null"
@@ -3935,7 +4014,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3935
4014
  }
3936
4015
  }
3937
4016
 
3938
- @for (edge of edges(); track $index) {
4017
+ @for (edge of edges; track $index) {
3939
4018
  @if (edge.type === 'template') {
3940
4019
  <ng-component
3941
4020
  [ngTemplateOutlet]="edgeTemplateDirective()?.templateRef ?? null"
@@ -3983,7 +4062,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3983
4062
  }
3984
4063
  }
3985
4064
 
3986
- @if (connection()?.type === 'template') {
4065
+ @if (connection.type === 'template') {
3987
4066
  <ng-component
3988
4067
  [ngTemplateOutlet]="connectionTemplateDirective()?.templateRef ?? null"
3989
4068
  [ngTemplateOutletContext]="{
@@ -3998,7 +4077,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3998
4077
  standalone: true,
3999
4078
  imports: [NgTemplateOutlet],
4000
4079
  }]
4001
- }] });
4080
+ }], propDecorators: { nodes: [{
4081
+ type: Input,
4082
+ args: [{ required: true }]
4083
+ }], edges: [{
4084
+ type: Input
4085
+ }], view: [{
4086
+ type: Input
4087
+ }], minZoom: [{
4088
+ type: Input
4089
+ }], maxZoom: [{
4090
+ type: Input
4091
+ }], background: [{
4092
+ type: Input
4093
+ }], entitiesSelectable: [{
4094
+ type: Input
4095
+ }], keyboardShortcuts: [{
4096
+ type: Input
4097
+ }], connection: [{
4098
+ type: Input,
4099
+ args: [{
4100
+ transform: (settings) => new ConnectionModel(settings),
4101
+ }]
4102
+ }], snapGrid: [{
4103
+ type: Input
4104
+ }], elevateNodesOnSelect: [{
4105
+ type: Input
4106
+ }], elevateEdgesOnSelect: [{
4107
+ type: Input
4108
+ }] } });
4002
4109
 
4003
4110
  class HandleMockComponent {
4004
4111
  constructor() {
@@ -4007,6 +4114,8 @@ class HandleMockComponent {
4007
4114
  this.id = input();
4008
4115
  this.template = input();
4009
4116
  }
4117
+ // eslint-disable-next-line @angular-eslint/no-empty-lifecycle-method
4118
+ ngOnInit() { }
4010
4119
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleMockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4011
4120
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: HandleMockComponent, isStandalone: true, selector: "handle", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: true, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: true, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, template: { classPropertyName: "template", publicName: "template", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4012
4121
  }
@@ -4026,6 +4135,10 @@ class ResizableMockComponent {
4026
4135
  this.resizerColor = input('#2e414c');
4027
4136
  this.gap = input(1.5);
4028
4137
  }
4138
+ // eslint-disable-next-line @angular-eslint/no-empty-lifecycle-method
4139
+ ngOnInit() { }
4140
+ // eslint-disable-next-line @angular-eslint/no-empty-lifecycle-method
4141
+ ngAfterViewInit() { }
4029
4142
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ResizableMockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4030
4143
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: ResizableMockComponent, isStandalone: true, selector: "[resizable]", inputs: { resizable: { classPropertyName: "resizable", publicName: "resizable", isSignal: true, isRequired: false, transformFunction: null }, resizerColor: { classPropertyName: "resizerColor", publicName: "resizerColor", isSignal: true, isRequired: false, transformFunction: null }, gap: { classPropertyName: "gap", publicName: "gap", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '<ng-content />', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4031
4144
  }
@@ -4046,6 +4159,8 @@ class MiniMapMockComponent {
4046
4159
  this.position = input('bottom-right');
4047
4160
  this.scaleOnHover = input(false);
4048
4161
  }
4162
+ // eslint-disable-next-line @angular-eslint/no-empty-lifecycle-method
4163
+ ngOnInit() { }
4049
4164
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MiniMapMockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4050
4165
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: MiniMapMockComponent, isStandalone: true, selector: "mini-map", inputs: { maskColor: { classPropertyName: "maskColor", publicName: "maskColor", isSignal: true, isRequired: false, transformFunction: null }, strokeColor: { classPropertyName: "strokeColor", publicName: "strokeColor", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, scaleOnHover: { classPropertyName: "scaleOnHover", publicName: "scaleOnHover", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4051
4166
  }
@@ -4063,6 +4178,10 @@ class NodeToolbarMockComponent {
4063
4178
  constructor() {
4064
4179
  this.position = input('top');
4065
4180
  }
4181
+ // eslint-disable-next-line @angular-eslint/no-empty-lifecycle-method
4182
+ ngOnInit() { }
4183
+ // eslint-disable-next-line @angular-eslint/no-empty-lifecycle-method
4184
+ ngOnDestroy() { }
4066
4185
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeToolbarMockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4067
4186
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: NodeToolbarMockComponent, isStandalone: true, selector: "node-toolbar", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '<ng-content />', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4068
4187
  }
@@ -4080,9 +4199,21 @@ class ConnectionControllerMockDirective {
4080
4199
  constructor() {
4081
4200
  // eslint-disable-next-line @angular-eslint/no-output-on-prefix
4082
4201
  this.onConnect = output();
4202
+ // eslint-disable-next-line @angular-eslint/no-output-on-prefix
4203
+ this.onReconnect = output();
4083
4204
  }
4205
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
4206
+ startConnection(handle) { }
4207
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
4208
+ startReconnection(handle) { }
4209
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
4210
+ validateConnection(handle) { }
4211
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
4212
+ resetValidateConnection(targetHandle) { }
4213
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
4214
+ endConnection() { }
4084
4215
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConnectionControllerMockDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4085
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: ConnectionControllerMockDirective, isStandalone: true, selector: "[onConnect]", outputs: { onConnect: "onConnect" }, ngImport: i0 }); }
4216
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: ConnectionControllerMockDirective, isStandalone: true, selector: "[onConnect]", outputs: { onConnect: "onConnect", onReconnect: "onReconnect" }, ngImport: i0 }); }
4086
4217
  }
4087
4218
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConnectionControllerMockDirective, decorators: [{
4088
4219
  type: Directive,