ngx-vflow 0.2.1 → 0.2.2

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.
@@ -2,13 +2,20 @@ import { Injectable, signal } from '@angular/core';
2
2
  import * as i0 from "@angular/core";
3
3
  export class HandleService {
4
4
  constructor() {
5
- this.handles = signal([]);
5
+ this.node = signal(null);
6
6
  }
7
7
  createHandle(newHandle) {
8
- this.handles.update(handles => [...handles, newHandle]);
8
+ const node = this.node();
9
+ if (node) {
10
+ node.rawHandles.update(handles => [...handles, newHandle]);
11
+ }
9
12
  }
10
13
  destroyHandle(handleToDestoy) {
11
- this.handles.update(handles => handles.filter(handle => handle !== handleToDestoy));
14
+ const node = this.node();
15
+ // TODO: microtask
16
+ if (node) {
17
+ queueMicrotask(() => node.rawHandles.update(handles => handles.filter(handle => handle !== handleToDestoy)));
18
+ }
12
19
  }
13
20
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
14
21
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleService }); }
@@ -16,4 +23,4 @@ export class HandleService {
16
23
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleService, decorators: [{
17
24
  type: Injectable
18
25
  }] });
19
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGFuZGxlLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtdmZsb3ctbGliL3NyYy9saWIvdmZsb3cvc2VydmljZXMvaGFuZGxlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBVSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7O0FBYzNELE1BQU0sT0FBTyxhQUFhO0lBRDFCO1FBRWtCLFlBQU8sR0FBRyxNQUFNLENBQWUsRUFBRSxDQUFDLENBQUE7S0FXbkQ7SUFUUSxZQUFZLENBQUMsU0FBcUI7UUFDdkMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsT0FBTyxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUE7SUFDekQsQ0FBQztJQUVNLGFBQWEsQ0FBQyxjQUEwQjtRQUM3QyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FDakIsT0FBTyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsTUFBTSxLQUFLLGNBQWMsQ0FBQyxDQUMvRCxDQUFBO0lBQ0gsQ0FBQzsrR0FYVSxhQUFhO21IQUFiLGFBQWE7OzRGQUFiLGFBQWE7a0JBRHpCLFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBTaWduYWwsIHNpZ25hbCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgUG9zaXRpb24gfSBmcm9tICcuLi90eXBlcy9wb3NpdGlvbi50eXBlJztcbmltcG9ydCB7IEhhbmRsZVR5cGUgfSBmcm9tICcuLi90eXBlcy9oYW5kbGUtdHlwZS50eXBlJztcbmltcG9ydCB7IFBvaW50IH0gZnJvbSAnLi4vaW50ZXJmYWNlcy9wb2ludC5pbnRlcmZhY2UnO1xuXG5leHBvcnQgaW50ZXJmYWNlIE5vZGVIYW5kbGUge1xuICBwb3NpdGlvbjogUG9zaXRpb25cbiAgdHlwZTogSGFuZGxlVHlwZVxuICBwYXJlbnRQb3NpdGlvbjogU2lnbmFsPFBvaW50PlxuICBwYXJlbnRTaXplOiBTaWduYWw8eyB3aWR0aDogbnVtYmVyLCBoZWlnaHQ6IG51bWJlciB9PlxuICBpZD86IHN0cmluZ1xufVxuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgSGFuZGxlU2VydmljZSB7XG4gIHB1YmxpYyByZWFkb25seSBoYW5kbGVzID0gc2lnbmFsPE5vZGVIYW5kbGVbXT4oW10pXG5cbiAgcHVibGljIGNyZWF0ZUhhbmRsZShuZXdIYW5kbGU6IE5vZGVIYW5kbGUpIHtcbiAgICB0aGlzLmhhbmRsZXMudXBkYXRlKGhhbmRsZXMgPT4gWy4uLmhhbmRsZXMsIG5ld0hhbmRsZV0pXG4gIH1cblxuICBwdWJsaWMgZGVzdHJveUhhbmRsZShoYW5kbGVUb0Rlc3RveTogTm9kZUhhbmRsZSkge1xuICAgIHRoaXMuaGFuZGxlcy51cGRhdGUoXG4gICAgICBoYW5kbGVzID0+IGhhbmRsZXMuZmlsdGVyKGhhbmRsZSA9PiBoYW5kbGUgIT09IGhhbmRsZVRvRGVzdG95KVxuICAgIClcbiAgfVxufVxuIl19
26
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGFuZGxlLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtdmZsb3ctbGliL3NyYy9saWIvdmZsb3cvc2VydmljZXMvaGFuZGxlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBVSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7O0FBZ0IzRCxNQUFNLE9BQU8sYUFBYTtJQUQxQjtRQUVrQixTQUFJLEdBQUcsTUFBTSxDQUFtQixJQUFJLENBQUMsQ0FBQTtLQWtCdEQ7SUFoQlEsWUFBWSxDQUFDLFNBQXNCO1FBQ3hDLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQTtRQUN4QixJQUFJLElBQUksRUFBRTtZQUNSLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLE9BQU8sRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFBO1NBQzNEO0lBQ0gsQ0FBQztJQUVNLGFBQWEsQ0FBQyxjQUEyQjtRQUM5QyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUE7UUFDeEIsa0JBQWtCO1FBQ2xCLElBQUksSUFBSSxFQUFFO1lBQ1IsY0FBYyxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUN6QyxPQUFPLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEtBQUssY0FBYyxDQUFDLENBQy9ELENBQUMsQ0FBQztTQUNKO0lBQ0gsQ0FBQzsrR0FsQlUsYUFBYTttSEFBYixhQUFhOzs0RkFBYixhQUFhO2tCQUR6QixVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgU2lnbmFsLCBzaWduYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFBvc2l0aW9uIH0gZnJvbSAnLi4vdHlwZXMvcG9zaXRpb24udHlwZSc7XG5pbXBvcnQgeyBIYW5kbGVUeXBlIH0gZnJvbSAnLi4vdHlwZXMvaGFuZGxlLXR5cGUudHlwZSc7XG5pbXBvcnQgeyBQb2ludCB9IGZyb20gJy4uL2ludGVyZmFjZXMvcG9pbnQuaW50ZXJmYWNlJztcbmltcG9ydCB7IE5vZGVNb2RlbCB9IGZyb20gJy4uL21vZGVscy9ub2RlLm1vZGVsJztcbmltcG9ydCB7IEhhbmRsZU1vZGVsIH0gZnJvbSAnLi4vbW9kZWxzL2hhbmRsZS5tb2RlbCc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgTm9kZUhhbmRsZSB7XG4gIHBvc2l0aW9uOiBQb3NpdGlvblxuICB0eXBlOiBIYW5kbGVUeXBlXG4gIHBhcmVudFBvc2l0aW9uOiBQb2ludFxuICBwYXJlbnRTaXplOiB7IHdpZHRoOiBudW1iZXIsIGhlaWdodDogbnVtYmVyIH1cbiAgaWQ/OiBzdHJpbmdcbn1cblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIEhhbmRsZVNlcnZpY2Uge1xuICBwdWJsaWMgcmVhZG9ubHkgbm9kZSA9IHNpZ25hbDxOb2RlTW9kZWwgfCBudWxsPihudWxsKVxuXG4gIHB1YmxpYyBjcmVhdGVIYW5kbGUobmV3SGFuZGxlOiBIYW5kbGVNb2RlbCkge1xuICAgIGNvbnN0IG5vZGUgPSB0aGlzLm5vZGUoKVxuICAgIGlmIChub2RlKSB7XG4gICAgICBub2RlLnJhd0hhbmRsZXMudXBkYXRlKGhhbmRsZXMgPT4gWy4uLmhhbmRsZXMsIG5ld0hhbmRsZV0pXG4gICAgfVxuICB9XG5cbiAgcHVibGljIGRlc3Ryb3lIYW5kbGUoaGFuZGxlVG9EZXN0b3k6IEhhbmRsZU1vZGVsKSB7XG4gICAgY29uc3Qgbm9kZSA9IHRoaXMubm9kZSgpXG4gICAgLy8gVE9ETzogbWljcm90YXNrXG4gICAgaWYgKG5vZGUpIHtcbiAgICAgIHF1ZXVlTWljcm90YXNrKCgpID0+IG5vZGUucmF3SGFuZGxlcy51cGRhdGUoXG4gICAgICAgIGhhbmRsZXMgPT4gaGFuZGxlcy5maWx0ZXIoaGFuZGxlID0+IGhhbmRsZSAhPT0gaGFuZGxlVG9EZXN0b3kpXG4gICAgICApKTtcbiAgICB9XG4gIH1cbn1cbiJdfQ==
@@ -1,7 +1,7 @@
1
1
  import { Injectable, inject } from '@angular/core';
2
2
  import { FlowEntitiesService } from './flow-entities.service';
3
3
  import { toObservable } from '@angular/core/rxjs-interop';
4
- import { filter, map, merge, pairwise, skip, switchMap } from 'rxjs';
4
+ import { asyncScheduler, filter, map, merge, observeOn, pairwise, skip, switchMap } from 'rxjs';
5
5
  import * as i0 from "@angular/core";
6
6
  export class NodesChangeService {
7
7
  constructor() {
@@ -21,7 +21,10 @@ export class NodesChangeService {
21
21
  .pipe(pairwise(), map(([oldList, newList]) => newList.filter(node => !oldList.includes(node))), filter((nodes) => !!nodes.length), map((nodes) => nodes.map(node => ({ type: 'add', id: node.node.id }))));
22
22
  this.nodeRemoveChange$ = toObservable(this.entitiesService.nodes)
23
23
  .pipe(pairwise(), map(([oldList, newList]) => oldList.filter(node => !newList.includes(node))), filter((nodes) => !!nodes.length), map((nodes) => nodes.map(node => ({ type: 'remove', id: node.node.id }))));
24
- this.changes$ = merge(this.nodesPositionChange$, this.nodeAddChange$, this.nodeRemoveChange$);
24
+ this.changes$ = merge(this.nodesPositionChange$, this.nodeAddChange$, this.nodeRemoveChange$).pipe(
25
+ // this fixes a bug when on fire node event change,
26
+ // you can't get valid list of detached edges
27
+ observeOn(asyncScheduler));
25
28
  }
26
29
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodesChangeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
27
30
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodesChangeService }); }
@@ -29,4 +32,4 @@ export class NodesChangeService {
29
32
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodesChangeService, decorators: [{
30
33
  type: Injectable
31
34
  }] });
32
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZS1jaGFuZ2VzLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtdmZsb3ctbGliL3NyYy9saWIvdmZsb3cvc2VydmljZXMvbm9kZS1jaGFuZ2VzLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBVSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0QsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDOUQsT0FBTyxFQUFFLFlBQVksRUFBWSxNQUFNLDRCQUE0QixDQUFDO0FBQ3BFLE9BQU8sRUFBYyxNQUFNLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBTSxRQUFRLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxNQUFNLE1BQU0sQ0FBQzs7QUFJckYsTUFBTSxPQUFPLGtCQUFrQjtJQUQvQjtRQUVZLG9CQUFlLEdBQUcsTUFBTSxDQUFDLG1CQUFtQixDQUFDLENBQUE7UUFFN0MseUJBQW9CLEdBQUcsWUFBWSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDO2FBQ3RFLElBQUk7UUFDSCw2RkFBNkY7UUFDN0YsU0FBUyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FDbEIsS0FBSyxDQUNILEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUNsQixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUk7UUFDZCxvQ0FBb0M7UUFDcEMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUNQLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FDaEIsQ0FDRixDQUNGLENBQ0Y7UUFDRCxrRUFBa0U7UUFDbEUsbUNBQW1DO1FBQ25DLEdBQUcsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO1lBQ2pCLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUUsV0FBVyxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLFdBQVcsQ0FBQyxLQUFLLEVBQUUsRUFBRTtTQUMxRSxDQUFDLENBQ2dDLENBQUE7UUFFNUIsbUJBQWMsR0FBRyxZQUFZLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUM7YUFDaEUsSUFBSSxDQUNILFFBQVEsRUFBRSxFQUNWLEdBQUcsQ0FBQyxDQUFDLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxFQUFFLEVBQUUsQ0FDekIsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUNoRCxFQUNELE1BQU0sQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsRUFDakMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FDWixLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUN2RCxDQUNpQyxDQUFBO1FBRTVCLHNCQUFpQixHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQzthQUNuRSxJQUFJLENBQ0gsUUFBUSxFQUFFLEVBQ1YsR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLEVBQUUsRUFBRSxDQUN6QixPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQ2hELEVBQ0QsTUFBTSxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxFQUNqQyxHQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUNaLEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQzFELENBQ2lDLENBQUE7UUFFdEIsYUFBUSxHQUE2QixLQUFLLENBQ3hELElBQUksQ0FBQyxvQkFBb0IsRUFDekIsSUFBSSxDQUFDLGNBQWMsRUFDbkIsSUFBSSxDQUFDLGlCQUFpQixDQUN2QixDQUFBO0tBQ0Y7K0dBckRZLGtCQUFrQjttSEFBbEIsa0JBQWtCOzs0RkFBbEIsa0JBQWtCO2tCQUQ5QixVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgU2lnbmFsLCBpbmplY3QgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEZsb3dFbnRpdGllc1NlcnZpY2UgfSBmcm9tICcuL2Zsb3ctZW50aXRpZXMuc2VydmljZSc7XG5pbXBvcnQgeyB0b09ic2VydmFibGUsIHRvU2lnbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZS9yeGpzLWludGVyb3AnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgZmlsdGVyLCBtYXAsIG1lcmdlLCBvZiwgcGFpcndpc2UsIHNraXAsIHN3aXRjaE1hcCB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgTm9kZUNoYW5nZSB9IGZyb20gJy4uL3R5cGVzL25vZGUtY2hhbmdlLnR5cGUnO1xuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgTm9kZXNDaGFuZ2VTZXJ2aWNlIHtcbiAgcHJvdGVjdGVkIGVudGl0aWVzU2VydmljZSA9IGluamVjdChGbG93RW50aXRpZXNTZXJ2aWNlKVxuXG4gIHByb3RlY3RlZCBub2Rlc1Bvc2l0aW9uQ2hhbmdlJCA9IHRvT2JzZXJ2YWJsZSh0aGlzLmVudGl0aWVzU2VydmljZS5ub2RlcylcbiAgICAucGlwZShcbiAgICAgIC8vIENoZWNrIGZvciBub2RlcyBsaXN0IGNoYW5nZSBhbmQgd2F0Y2ggZm9yIHNwZWNpZmljIG5vZGUgZnJvbSB0aGlzIGxpc3QgY2hhbmdlIGl0cyBwb3NpdGlvblxuICAgICAgc3dpdGNoTWFwKChub2RlcykgPT5cbiAgICAgICAgbWVyZ2UoXG4gICAgICAgICAgLi4ubm9kZXMubWFwKG5vZGUgPT5cbiAgICAgICAgICAgIG5vZGUucG9pbnQkLnBpcGUoXG4gICAgICAgICAgICAgIC8vIHNraXAgaW5pdGlhbCBwb3NpdGlvbiBmcm9tIHNpZ25hbFxuICAgICAgICAgICAgICBza2lwKDEpLFxuICAgICAgICAgICAgICBtYXAoKCkgPT4gbm9kZSlcbiAgICAgICAgICAgIClcbiAgICAgICAgICApXG4gICAgICAgIClcbiAgICAgICksXG4gICAgICAvLyBGb3Igbm93IGl0J3MgYSBzaW5nbGUgbm9kZSwgbGF0ZXIgdGhpcyBsaXN0IHdpbGwgYWxzbyBiZSBmaWxsZWRcbiAgICAgIC8vIHdpdGggY2hpbGQgbm9kZSBwb3NpdGlvbiBjaGFuZ2VzXG4gICAgICBtYXAoY2hhbmdlZE5vZGUgPT4gW1xuICAgICAgICB7IHR5cGU6ICdwb3NpdGlvbicsIGlkOiBjaGFuZ2VkTm9kZS5ub2RlLmlkLCBwb2ludDogY2hhbmdlZE5vZGUucG9pbnQoKSB9XG4gICAgICBdKVxuICAgICkgc2F0aXNmaWVzIE9ic2VydmFibGU8Tm9kZUNoYW5nZVtdPlxuXG4gIHByb3RlY3RlZCBub2RlQWRkQ2hhbmdlJCA9IHRvT2JzZXJ2YWJsZSh0aGlzLmVudGl0aWVzU2VydmljZS5ub2RlcylcbiAgICAucGlwZShcbiAgICAgIHBhaXJ3aXNlKCksXG4gICAgICBtYXAoKFtvbGRMaXN0LCBuZXdMaXN0XSkgPT5cbiAgICAgICAgbmV3TGlzdC5maWx0ZXIobm9kZSA9PiAhb2xkTGlzdC5pbmNsdWRlcyhub2RlKSlcbiAgICAgICksXG4gICAgICBmaWx0ZXIoKG5vZGVzKSA9PiAhIW5vZGVzLmxlbmd0aCksXG4gICAgICBtYXAoKG5vZGVzKSA9PlxuICAgICAgICBub2Rlcy5tYXAobm9kZSA9PiAoeyB0eXBlOiAnYWRkJywgaWQ6IG5vZGUubm9kZS5pZCB9KSlcbiAgICAgIClcbiAgICApIHNhdGlzZmllcyBPYnNlcnZhYmxlPE5vZGVDaGFuZ2VbXT5cblxuICBwcm90ZWN0ZWQgbm9kZVJlbW92ZUNoYW5nZSQgPSB0b09ic2VydmFibGUodGhpcy5lbnRpdGllc1NlcnZpY2Uubm9kZXMpXG4gICAgLnBpcGUoXG4gICAgICBwYWlyd2lzZSgpLFxuICAgICAgbWFwKChbb2xkTGlzdCwgbmV3TGlzdF0pID0+XG4gICAgICAgIG9sZExpc3QuZmlsdGVyKG5vZGUgPT4gIW5ld0xpc3QuaW5jbHVkZXMobm9kZSkpXG4gICAgICApLFxuICAgICAgZmlsdGVyKChub2RlcykgPT4gISFub2Rlcy5sZW5ndGgpLFxuICAgICAgbWFwKChub2RlcykgPT5cbiAgICAgICAgbm9kZXMubWFwKG5vZGUgPT4gKHsgdHlwZTogJ3JlbW92ZScsIGlkOiBub2RlLm5vZGUuaWQgfSkpXG4gICAgICApXG4gICAgKSBzYXRpc2ZpZXMgT2JzZXJ2YWJsZTxOb2RlQ2hhbmdlW10+XG5cbiAgcHVibGljIHJlYWRvbmx5IGNoYW5nZXMkOiBPYnNlcnZhYmxlPE5vZGVDaGFuZ2VbXT4gPSBtZXJnZShcbiAgICB0aGlzLm5vZGVzUG9zaXRpb25DaGFuZ2UkLFxuICAgIHRoaXMubm9kZUFkZENoYW5nZSQsXG4gICAgdGhpcy5ub2RlUmVtb3ZlQ2hhbmdlJFxuICApXG59XG4iXX0=
35
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZS1jaGFuZ2VzLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtdmZsb3ctbGliL3NyYy9saWIvdmZsb3cvc2VydmljZXMvbm9kZS1jaGFuZ2VzLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBVSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0QsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDOUQsT0FBTyxFQUFFLFlBQVksRUFBWSxNQUFNLDRCQUE0QixDQUFDO0FBQ3BFLE9BQU8sRUFBYyxjQUFjLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFNLFFBQVEsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLE1BQU0sTUFBTSxDQUFDOztBQUloSCxNQUFNLE9BQU8sa0JBQWtCO0lBRC9CO1FBRVksb0JBQWUsR0FBRyxNQUFNLENBQUMsbUJBQW1CLENBQUMsQ0FBQTtRQUU3Qyx5QkFBb0IsR0FBRyxZQUFZLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUM7YUFDdEUsSUFBSTtRQUNILDZGQUE2RjtRQUM3RixTQUFTLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUNsQixLQUFLLENBQ0gsR0FBRyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQ2xCLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSTtRQUNkLG9DQUFvQztRQUNwQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQ1AsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUNoQixDQUNGLENBQ0YsQ0FDRjtRQUNELGtFQUFrRTtRQUNsRSxtQ0FBbUM7UUFDbkMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUM7WUFDakIsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBRSxXQUFXLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsV0FBVyxDQUFDLEtBQUssRUFBRSxFQUFFO1NBQzFFLENBQUMsQ0FDZ0MsQ0FBQTtRQUU1QixtQkFBYyxHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQzthQUNoRSxJQUFJLENBQ0gsUUFBUSxFQUFFLEVBQ1YsR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLEVBQUUsRUFBRSxDQUN6QixPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQ2hELEVBQ0QsTUFBTSxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxFQUNqQyxHQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUNaLEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQ3ZELENBQ2lDLENBQUE7UUFFNUIsc0JBQWlCLEdBQUcsWUFBWSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDO2FBQ25FLElBQUksQ0FDSCxRQUFRLEVBQUUsRUFDVixHQUFHLENBQUMsQ0FBQyxDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsRUFBRSxFQUFFLENBQ3pCLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FDaEQsRUFDRCxNQUFNLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLEVBQ2pDLEdBQUcsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQ1osS0FBSyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLEVBQUUsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FDMUQsQ0FDaUMsQ0FBQTtRQUV0QixhQUFRLEdBQTZCLEtBQUssQ0FDeEQsSUFBSSxDQUFDLG9CQUFvQixFQUN6QixJQUFJLENBQUMsY0FBYyxFQUNuQixJQUFJLENBQUMsaUJBQWlCLENBQ3ZCLENBQUMsSUFBSTtRQUNKLG1EQUFtRDtRQUNuRCw2Q0FBNkM7UUFDN0MsU0FBUyxDQUFDLGNBQWMsQ0FBQyxDQUMxQixDQUFBO0tBQ0Y7K0dBekRZLGtCQUFrQjttSEFBbEIsa0JBQWtCOzs0RkFBbEIsa0JBQWtCO2tCQUQ5QixVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgU2lnbmFsLCBpbmplY3QgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEZsb3dFbnRpdGllc1NlcnZpY2UgfSBmcm9tICcuL2Zsb3ctZW50aXRpZXMuc2VydmljZSc7XG5pbXBvcnQgeyB0b09ic2VydmFibGUsIHRvU2lnbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZS9yeGpzLWludGVyb3AnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgYXN5bmNTY2hlZHVsZXIsIGZpbHRlciwgbWFwLCBtZXJnZSwgb2JzZXJ2ZU9uLCBvZiwgcGFpcndpc2UsIHNraXAsIHN3aXRjaE1hcCB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgTm9kZUNoYW5nZSB9IGZyb20gJy4uL3R5cGVzL25vZGUtY2hhbmdlLnR5cGUnO1xuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgTm9kZXNDaGFuZ2VTZXJ2aWNlIHtcbiAgcHJvdGVjdGVkIGVudGl0aWVzU2VydmljZSA9IGluamVjdChGbG93RW50aXRpZXNTZXJ2aWNlKVxuXG4gIHByb3RlY3RlZCBub2Rlc1Bvc2l0aW9uQ2hhbmdlJCA9IHRvT2JzZXJ2YWJsZSh0aGlzLmVudGl0aWVzU2VydmljZS5ub2RlcylcbiAgICAucGlwZShcbiAgICAgIC8vIENoZWNrIGZvciBub2RlcyBsaXN0IGNoYW5nZSBhbmQgd2F0Y2ggZm9yIHNwZWNpZmljIG5vZGUgZnJvbSB0aGlzIGxpc3QgY2hhbmdlIGl0cyBwb3NpdGlvblxuICAgICAgc3dpdGNoTWFwKChub2RlcykgPT5cbiAgICAgICAgbWVyZ2UoXG4gICAgICAgICAgLi4ubm9kZXMubWFwKG5vZGUgPT5cbiAgICAgICAgICAgIG5vZGUucG9pbnQkLnBpcGUoXG4gICAgICAgICAgICAgIC8vIHNraXAgaW5pdGlhbCBwb3NpdGlvbiBmcm9tIHNpZ25hbFxuICAgICAgICAgICAgICBza2lwKDEpLFxuICAgICAgICAgICAgICBtYXAoKCkgPT4gbm9kZSlcbiAgICAgICAgICAgIClcbiAgICAgICAgICApXG4gICAgICAgIClcbiAgICAgICksXG4gICAgICAvLyBGb3Igbm93IGl0J3MgYSBzaW5nbGUgbm9kZSwgbGF0ZXIgdGhpcyBsaXN0IHdpbGwgYWxzbyBiZSBmaWxsZWRcbiAgICAgIC8vIHdpdGggY2hpbGQgbm9kZSBwb3NpdGlvbiBjaGFuZ2VzXG4gICAgICBtYXAoY2hhbmdlZE5vZGUgPT4gW1xuICAgICAgICB7IHR5cGU6ICdwb3NpdGlvbicsIGlkOiBjaGFuZ2VkTm9kZS5ub2RlLmlkLCBwb2ludDogY2hhbmdlZE5vZGUucG9pbnQoKSB9XG4gICAgICBdKVxuICAgICkgc2F0aXNmaWVzIE9ic2VydmFibGU8Tm9kZUNoYW5nZVtdPlxuXG4gIHByb3RlY3RlZCBub2RlQWRkQ2hhbmdlJCA9IHRvT2JzZXJ2YWJsZSh0aGlzLmVudGl0aWVzU2VydmljZS5ub2RlcylcbiAgICAucGlwZShcbiAgICAgIHBhaXJ3aXNlKCksXG4gICAgICBtYXAoKFtvbGRMaXN0LCBuZXdMaXN0XSkgPT5cbiAgICAgICAgbmV3TGlzdC5maWx0ZXIobm9kZSA9PiAhb2xkTGlzdC5pbmNsdWRlcyhub2RlKSlcbiAgICAgICksXG4gICAgICBmaWx0ZXIoKG5vZGVzKSA9PiAhIW5vZGVzLmxlbmd0aCksXG4gICAgICBtYXAoKG5vZGVzKSA9PlxuICAgICAgICBub2Rlcy5tYXAobm9kZSA9PiAoeyB0eXBlOiAnYWRkJywgaWQ6IG5vZGUubm9kZS5pZCB9KSlcbiAgICAgIClcbiAgICApIHNhdGlzZmllcyBPYnNlcnZhYmxlPE5vZGVDaGFuZ2VbXT5cblxuICBwcm90ZWN0ZWQgbm9kZVJlbW92ZUNoYW5nZSQgPSB0b09ic2VydmFibGUodGhpcy5lbnRpdGllc1NlcnZpY2Uubm9kZXMpXG4gICAgLnBpcGUoXG4gICAgICBwYWlyd2lzZSgpLFxuICAgICAgbWFwKChbb2xkTGlzdCwgbmV3TGlzdF0pID0+XG4gICAgICAgIG9sZExpc3QuZmlsdGVyKG5vZGUgPT4gIW5ld0xpc3QuaW5jbHVkZXMobm9kZSkpXG4gICAgICApLFxuICAgICAgZmlsdGVyKChub2RlcykgPT4gISFub2Rlcy5sZW5ndGgpLFxuICAgICAgbWFwKChub2RlcykgPT5cbiAgICAgICAgbm9kZXMubWFwKG5vZGUgPT4gKHsgdHlwZTogJ3JlbW92ZScsIGlkOiBub2RlLm5vZGUuaWQgfSkpXG4gICAgICApXG4gICAgKSBzYXRpc2ZpZXMgT2JzZXJ2YWJsZTxOb2RlQ2hhbmdlW10+XG5cbiAgcHVibGljIHJlYWRvbmx5IGNoYW5nZXMkOiBPYnNlcnZhYmxlPE5vZGVDaGFuZ2VbXT4gPSBtZXJnZShcbiAgICB0aGlzLm5vZGVzUG9zaXRpb25DaGFuZ2UkLFxuICAgIHRoaXMubm9kZUFkZENoYW5nZSQsXG4gICAgdGhpcy5ub2RlUmVtb3ZlQ2hhbmdlJFxuICApLnBpcGUoXG4gICAgLy8gdGhpcyBmaXhlcyBhIGJ1ZyB3aGVuIG9uIGZpcmUgbm9kZSBldmVudCBjaGFuZ2UsXG4gICAgLy8geW91IGNhbid0IGdldCB2YWxpZCBsaXN0IG9mIGRldGFjaGVkIGVkZ2VzXG4gICAgb2JzZXJ2ZU9uKGFzeW5jU2NoZWR1bGVyKSxcbiAgKVxufVxuIl19
@@ -1,2 +1,2 @@
1
1
  export {};
2
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWRnZS1jaGFuZ2UudHlwZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC12Zmxvdy1saWIvc3JjL2xpYi92Zmxvdy90eXBlcy9lZGdlLWNoYW5nZS50eXBlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgdHlwZSBFZGdlQ2hhbmdlID0gRWRnZURldGFjaGVkQ2hhbmdlIHwgRWRnZUFkZENoYW5nZSB8IEVkZ2VSZW1vdmVDaGFuZ2VcblxuZXhwb3J0IGludGVyZmFjZSBFZGdlRGV0YWNoZWRDaGFuZ2UgZXh0ZW5kcyBFZGdlQ2hhbmdlU2hhcmVkIHtcbiAgdHlwZTogJ2RldGFjaGVkJ1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEVkZ2VBZGRDaGFuZ2UgZXh0ZW5kcyBFZGdlQ2hhbmdlU2hhcmVkIHtcbiAgdHlwZTogJ2FkZCdcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFZGdlUmVtb3ZlQ2hhbmdlIGV4dGVuZHMgRWRnZUNoYW5nZVNoYXJlZCB7XG4gIHR5cGU6ICdyZW1vdmUnXG59XG5cbmludGVyZmFjZSBFZGdlQ2hhbmdlU2hhcmVkIHtcbiAgaWQ6IHN0cmluZ1xufVxuIl19
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWRnZS1jaGFuZ2UudHlwZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC12Zmxvdy1saWIvc3JjL2xpYi92Zmxvdy90eXBlcy9lZGdlLWNoYW5nZS50eXBlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgdHlwZSBFZGdlQ2hhbmdlID0gRWRnZURldGFjaGVkQ2hhbmdlIHwgRWRnZUFkZENoYW5nZSB8IEVkZ2VSZW1vdmVDaGFuZ2VcblxuLyoqXG4gKiBAZXhwZXJpbWVudGFsXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRWRnZURldGFjaGVkQ2hhbmdlIGV4dGVuZHMgRWRnZUNoYW5nZVNoYXJlZCB7XG4gIHR5cGU6ICdkZXRhY2hlZCdcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFZGdlQWRkQ2hhbmdlIGV4dGVuZHMgRWRnZUNoYW5nZVNoYXJlZCB7XG4gIHR5cGU6ICdhZGQnXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRWRnZVJlbW92ZUNoYW5nZSBleHRlbmRzIEVkZ2VDaGFuZ2VTaGFyZWQge1xuICB0eXBlOiAncmVtb3ZlJ1xufVxuXG5pbnRlcmZhY2UgRWRnZUNoYW5nZVNoYXJlZCB7XG4gIGlkOiBzdHJpbmdcbn1cbiJdfQ==
@@ -1,12 +1,12 @@
1
1
  import * as i1 from '@angular/common';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { signal, Injectable, inject, ElementRef, Directive, effect, Input, TemplateRef, computed, EventEmitter, Output, untracked, Injector, runInInjectionContext, Component, ChangeDetectionStrategy, ViewChild, HostListener, ContentChild, NgModule } from '@angular/core';
4
+ import { signal, Injectable, inject, ElementRef, Directive, effect, Input, TemplateRef, computed, EventEmitter, Output, untracked, Injector, Component, ChangeDetectionStrategy, ViewChild, HostListener, runInInjectionContext, ContentChild, NgModule } from '@angular/core';
5
5
  import { select } from 'd3-selection';
6
6
  import { zoomIdentity, zoom } from 'd3-zoom';
7
7
  import { drag } from 'd3-drag';
8
8
  import { toObservable, takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
9
- import { switchMap, merge, skip, map, pairwise, filter, observeOn, asyncScheduler, tap, fromEvent } from 'rxjs';
9
+ import { switchMap, merge, skip, map, pairwise, filter, observeOn, asyncScheduler, zip, distinctUntilChanged, tap, fromEvent } from 'rxjs';
10
10
  import { path } from 'd3-path';
11
11
 
12
12
  class ViewportService {
@@ -350,6 +350,9 @@ class FlowEntitiesService {
350
350
  getNode(id) {
351
351
  return this.nodes().find(({ node }) => node.id === id);
352
352
  }
353
+ getDetachedEdges() {
354
+ return this.edges().filter(e => e.detached());
355
+ }
353
356
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowEntitiesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
354
357
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowEntitiesService }); }
355
358
  }
@@ -412,18 +415,18 @@ class HandleModel {
412
415
  switch (this.rawHandle.position) {
413
416
  case 'left': return {
414
417
  x: 0,
415
- y: this.rawHandle.parentPosition().y + (this.rawHandle.parentSize().height / 2)
418
+ y: this.parentPosition().y + (this.parentSize().height / 2)
416
419
  };
417
420
  case 'right': return {
418
421
  x: this.parentNode.size().width,
419
- y: this.rawHandle.parentPosition().y + (this.rawHandle.parentSize().height / 2)
422
+ y: this.parentPosition().y + (this.parentSize().height / 2)
420
423
  };
421
424
  case 'top': return {
422
- x: this.rawHandle.parentPosition().x + (this.rawHandle.parentSize().width / 2),
425
+ x: this.parentPosition().x + (this.parentSize().width / 2),
423
426
  y: 0
424
427
  };
425
428
  case 'bottom': return {
426
- x: this.rawHandle.parentPosition().x + this.rawHandle.parentSize().width / 2,
429
+ x: this.parentPosition().x + this.parentSize().width / 2,
427
430
  y: this.parentNode.size().height
428
431
  };
429
432
  }
@@ -442,6 +445,8 @@ class HandleModel {
442
445
  y: this.parentNode.point().y + this.offset().y + this.sizeOffset().y,
443
446
  };
444
447
  });
448
+ this.parentSize = signal(this.rawHandle.parentSize);
449
+ this.parentPosition = signal(this.rawHandle.parentPosition);
445
450
  }
446
451
  }
447
452
 
@@ -457,20 +462,20 @@ class NodeModel {
457
462
  this.targetPosition = computed(() => this.flow.handlePositions().target);
458
463
  this.handles = computed(() => {
459
464
  if (this.node.type === 'html-template') {
460
- return this.rawHandles().map((handle => new HandleModel(handle, this)));
465
+ return this.rawHandles();
461
466
  }
462
467
  return [
463
468
  new HandleModel({
464
469
  position: this.sourcePosition(),
465
470
  type: 'source',
466
- parentPosition: signal({ x: 0, y: 0 }),
467
- parentSize: signal(this.size())
471
+ parentPosition: { x: 0, y: 0 },
472
+ parentSize: this.size()
468
473
  }, this),
469
474
  new HandleModel({
470
475
  position: this.targetPosition(),
471
476
  type: 'target',
472
- parentPosition: signal({ x: 0, y: 0 }),
473
- parentSize: signal(this.size())
477
+ parentPosition: { x: 0, y: 0 },
478
+ parentSize: this.size()
474
479
  }, this),
475
480
  ];
476
481
  });
@@ -605,6 +610,31 @@ function getPointOnBezier(sourcePoint, targetPoint, controlPoint1, controlPoint2
605
610
  class EdgeModel {
606
611
  constructor(edge) {
607
612
  this.edge = edge;
613
+ this.detached = computed(() => {
614
+ if (!this.source || !this.target) {
615
+ return true;
616
+ }
617
+ let existsSourceHandle = false;
618
+ let existsTargetHandle = false;
619
+ if (this.edge.sourceHandle) {
620
+ existsSourceHandle = !!this.source.handles()
621
+ .find(handle => handle.rawHandle.id === this.edge.sourceHandle);
622
+ }
623
+ else {
624
+ existsSourceHandle = !!this.source.handles()
625
+ .find(handle => handle.rawHandle.type === 'source');
626
+ }
627
+ if (this.edge.targetHandle) {
628
+ existsTargetHandle = !!this.target.handles()
629
+ .find(handle => handle.rawHandle.id === this.edge.targetHandle);
630
+ }
631
+ else {
632
+ existsTargetHandle = !!this.target.handles()
633
+ .find(handle => handle.rawHandle.type === 'target');
634
+ }
635
+ return !existsSourceHandle || !existsTargetHandle;
636
+ });
637
+ this.detached$ = toObservable(this.detached);
608
638
  this.path = computed(() => {
609
639
  let source;
610
640
  if (this.edge.sourceHandle) {
@@ -702,7 +732,10 @@ class NodesChangeService {
702
732
  .pipe(pairwise(), map(([oldList, newList]) => newList.filter(node => !oldList.includes(node))), filter((nodes) => !!nodes.length), map((nodes) => nodes.map(node => ({ type: 'add', id: node.node.id }))));
703
733
  this.nodeRemoveChange$ = toObservable(this.entitiesService.nodes)
704
734
  .pipe(pairwise(), map(([oldList, newList]) => oldList.filter(node => !newList.includes(node))), filter((nodes) => !!nodes.length), map((nodes) => nodes.map(node => ({ type: 'remove', id: node.node.id }))));
705
- this.changes$ = merge(this.nodesPositionChange$, this.nodeAddChange$, this.nodeRemoveChange$);
735
+ this.changes$ = merge(this.nodesPositionChange$, this.nodeAddChange$, this.nodeRemoveChange$).pipe(
736
+ // this fixes a bug when on fire node event change,
737
+ // you can't get valid list of detached edges
738
+ observeOn(asyncScheduler));
706
739
  }
707
740
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodesChangeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
708
741
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodesChangeService }); }
@@ -711,16 +744,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
711
744
  type: Injectable
712
745
  }] });
713
746
 
747
+ const haveSameContents = (a, b) => a.length === b.length &&
748
+ [...new Set([...a, ...b])].every(v => a.filter(e => e === v).length === b.filter(e => e === v).length);
714
749
  class EdgeChangesService {
715
750
  constructor() {
716
751
  this.entitiesService = inject(FlowEntitiesService);
717
- this.edgeDetachedChange$ = toObservable(computed(() => {
752
+ this.edgeDetachedChange$ = merge(toObservable(computed(() => {
718
753
  const nodes = this.entitiesService.nodes();
719
754
  const edges = untracked(this.entitiesService.edges);
720
755
  return edges.filter(({ source, target }) => !nodes.includes(source) || !nodes.includes(target));
721
- })).pipe(
722
- // TODO check why there are 2 emits from single call inside computed
723
- filter(edges => !!edges.length), map((edges) => edges.map(({ edge }) => ({ type: 'detached', id: edge.id }))));
756
+ })), toObservable(this.entitiesService.edges).pipe(switchMap((edges) => {
757
+ return zip(...edges.map(e => e.detached$.pipe(map(() => e))));
758
+ }), map((edges) => edges.filter(e => e.detached())),
759
+ // TODO check why there are 2 emits
760
+ skip(2))).pipe(
761
+ // here we check if 2 approaches to detect detached edges emits same
762
+ // and same values (this may happen on node delete)
763
+ distinctUntilChanged(haveSameContents), filter(edges => !!edges.length), map((edges) => edges.map(({ edge }) => ({ type: 'detached', id: edge.id }))));
724
764
  this.edgeAddChange$ = toObservable(this.entitiesService.edges)
725
765
  .pipe(pairwise(), map(([oldList, newList]) => {
726
766
  return newList.filter(edge => !oldList.includes(edge));
@@ -780,13 +820,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
780
820
 
781
821
  class HandleService {
782
822
  constructor() {
783
- this.handles = signal([]);
823
+ this.node = signal(null);
784
824
  }
785
825
  createHandle(newHandle) {
786
- this.handles.update(handles => [...handles, newHandle]);
826
+ const node = this.node();
827
+ if (node) {
828
+ node.rawHandles.update(handles => [...handles, newHandle]);
829
+ }
787
830
  }
788
831
  destroyHandle(handleToDestoy) {
789
- this.handles.update(handles => handles.filter(handle => handle !== handleToDestoy));
832
+ const node = this.node();
833
+ // TODO: microtask
834
+ if (node) {
835
+ queueMicrotask(() => node.rawHandles.update(handles => handles.filter(handle => handle !== handleToDestoy)));
836
+ }
790
837
  }
791
838
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
792
839
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleService }); }
@@ -809,9 +856,7 @@ class NodeComponent {
809
856
  this.targetHandleState = signal('idle');
810
857
  }
811
858
  ngOnInit() {
812
- runInInjectionContext(this.injector, () => {
813
- effect(() => this.nodeModel.rawHandles.set(this.handleService.handles()), { allowSignalWrites: true });
814
- });
859
+ this.handleService.node.set(this.nodeModel);
815
860
  this.draggableService.toggleDraggable(this.hostRef.nativeElement, this.nodeModel);
816
861
  }
817
862
  ngAfterViewInit() {
@@ -1277,7 +1322,7 @@ class VflowComponent {
1277
1322
  * Edges to render
1278
1323
  */
1279
1324
  set edges(newEdges) {
1280
- const newModels = ReferenceKeeper.edges(newEdges, this.flowEntitiesService.edges());
1325
+ const newModels = runInInjectionContext(this.injector, () => ReferenceKeeper.edges(newEdges, this.flowEntitiesService.edges()));
1281
1326
  // quick and dirty binding nodes to edges
1282
1327
  addNodesToEdges(this.nodeModels, newModels);
1283
1328
  this.flowEntitiesService.edges.set(newModels);
@@ -1316,6 +1361,12 @@ class VflowComponent {
1316
1361
  getNode(id) {
1317
1362
  return this.flowEntitiesService.getNode(id)?.node;
1318
1363
  }
1364
+ /**
1365
+ * Sync method to get detached edges
1366
+ */
1367
+ getDetachedEdges() {
1368
+ return this.flowEntitiesService.getDetachedEdges().map(e => e.edge);
1369
+ }
1319
1370
  // #endregion
1320
1371
  trackNodes(idx, { node }) {
1321
1372
  return node.id;
@@ -1391,27 +1442,27 @@ class HandleComponent {
1391
1442
  }
1392
1443
  ngOnInit() {
1393
1444
  queueMicrotask(() => {
1394
- const rect = this.parentRect();
1395
- this.handleService.createHandle({
1445
+ const { width, height, x, y } = this.parentRect();
1446
+ this.model = new HandleModel({
1396
1447
  position: this.position,
1397
1448
  type: this.type,
1398
1449
  id: this.id,
1399
- parentPosition: signal({ x: rect.x, y: rect.y }),
1400
- parentSize: signal({ width: rect.width, height: rect.height })
1401
- });
1450
+ parentPosition: { x, y },
1451
+ parentSize: { width, height }
1452
+ }, this.handleService.node());
1453
+ this.handleService.createHandle(this.model);
1402
1454
  });
1403
1455
  }
1456
+ ngOnDestroy() {
1457
+ this.handleService.destroyHandle(this.model);
1458
+ }
1404
1459
  parentRect() {
1405
- // we assume there is only one foreignObject that wraps node
1406
- const fo = this.element.closest('foreignObject');
1407
1460
  const parent = this.element.parentElement;
1408
- const foRect = fo.getBoundingClientRect();
1409
- const parentRect = parent.getBoundingClientRect();
1410
1461
  return {
1411
- x: parentRect.left - foRect.left,
1412
- y: parentRect.top - foRect.top,
1413
- width: parentRect.width,
1414
- height: parentRect.height
1462
+ x: parent.offsetLeft,
1463
+ y: parent.offsetTop,
1464
+ width: parent.clientWidth,
1465
+ height: parent.clientHeight
1415
1466
  };
1416
1467
  }
1417
1468
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }