ngx-vflow 0.11.0 → 0.12.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 (33) hide show
  1. package/esm2022/lib/vflow/components/node/node.component.mjs +16 -13
  2. package/esm2022/lib/vflow/components/vflow/vflow.component.mjs +5 -2
  3. package/esm2022/lib/vflow/directives/changes-controller.directive.mjs +14 -2
  4. package/esm2022/lib/vflow/directives/flow-size-controller.directive.mjs +3 -3
  5. package/esm2022/lib/vflow/directives/root-pointer.directive.mjs +21 -4
  6. package/esm2022/lib/vflow/interfaces/node.interface.mjs +1 -1
  7. package/esm2022/lib/vflow/models/node.model.mjs +44 -5
  8. package/esm2022/lib/vflow/public-components/resizable/resizable.component.mjs +265 -0
  9. package/esm2022/lib/vflow/services/draggable.service.mjs +2 -2
  10. package/esm2022/lib/vflow/services/node-accessor.service.mjs +16 -0
  11. package/esm2022/lib/vflow/services/node-changes.service.mjs +6 -2
  12. package/esm2022/lib/vflow/types/node-change.type.mjs +1 -1
  13. package/esm2022/lib/vflow/utils/resizable.mjs +3 -3
  14. package/esm2022/lib/vflow/vflow.module.mjs +9 -4
  15. package/esm2022/public-api.mjs +2 -1
  16. package/fesm2022/ngx-vflow.mjs +409 -61
  17. package/fesm2022/ngx-vflow.mjs.map +1 -1
  18. package/lib/vflow/components/node/node.component.d.ts +2 -0
  19. package/lib/vflow/components/vflow/vflow.component.d.ts +1 -1
  20. package/lib/vflow/directives/changes-controller.directive.d.ts +5 -2
  21. package/lib/vflow/directives/root-pointer.directive.d.ts +24 -6
  22. package/lib/vflow/directives/space-point-context.directive.d.ts +5 -0
  23. package/lib/vflow/interfaces/node.interface.d.ts +10 -0
  24. package/lib/vflow/models/edge.model.d.ts +1 -17
  25. package/lib/vflow/models/node.model.d.ts +13 -2
  26. package/lib/vflow/public-components/resizable/resizable.component.d.ts +39 -0
  27. package/lib/vflow/services/node-accessor.service.d.ts +10 -0
  28. package/lib/vflow/services/node-changes.service.d.ts +8 -0
  29. package/lib/vflow/types/node-change.type.d.ts +8 -1
  30. package/lib/vflow/utils/resizable.d.ts +2 -1
  31. package/lib/vflow/vflow.module.d.ts +13 -12
  32. package/package.json +1 -1
  33. package/public-api.d.ts +1 -0
@@ -1,7 +1,7 @@
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, computed, Injectable, inject, ElementRef, Directive, effect, untracked, TemplateRef, EventEmitter, Output, DestroyRef, Input, runInInjectionContext, Injector, Component, ChangeDetectionStrategy, HostListener, ViewChild, HostBinding, ContentChild, NgModule } from '@angular/core';
4
+ import { signal, computed, Injectable, inject, ElementRef, Directive, effect, untracked, TemplateRef, EventEmitter, Output, DestroyRef, Input, runInInjectionContext, Injector, Component, ChangeDetectionStrategy, HostListener, ViewChild, NgZone, HostBinding, ContentChild, NgModule } from '@angular/core';
5
5
  import { select } from 'd3-selection';
6
6
  import { zoomIdentity, zoom } from 'd3-zoom';
7
7
  import { Subject, tap, merge, observeOn, animationFrameScheduler, switchMap, skip, map, pairwise, filter, distinctUntilChanged, asyncScheduler, zip, fromEvent, share, Observable, startWith } from 'rxjs';
@@ -432,7 +432,7 @@ class DraggableService {
432
432
  point.y = Math.min(parent.size().height - model.size().height, point.y);
433
433
  point.y = Math.max(0, point.y);
434
434
  }
435
- model.setPoint(point);
435
+ model.setPoint(point, true);
436
436
  });
437
437
  }
438
438
  /**
@@ -844,6 +844,7 @@ function isTemplateDynamicGroupNode(node) {
844
844
  return node.type === 'template-group';
845
845
  }
846
846
 
847
+ // TODO bad naming around points
847
848
  class NodeModel {
848
849
  static { this.defaultWidth = 100; }
849
850
  static { this.defaultHeight = 50; }
@@ -854,11 +855,15 @@ class NodeModel {
854
855
  this.entitiesService = inject(FlowEntitiesService);
855
856
  this.internalPoint = this.createInternalPointSignal();
856
857
  this.throttledPoint$ = toObservable(this.internalPoint).pipe(observeOn(animationFrameScheduler));
857
- this.point = toSignal(this.throttledPoint$, {
858
+ this.notThrottledPoint$ = new Subject();
859
+ this.point = toSignal(merge(this.throttledPoint$, this.notThrottledPoint$), {
858
860
  initialValue: this.internalPoint()
859
861
  });
860
862
  this.point$ = this.throttledPoint$;
861
863
  this.size = signal({ width: 0, height: 0 });
864
+ this.size$ = toObservable(this.size);
865
+ this.width = computed(() => this.size().width);
866
+ this.height = computed(() => this.size().height);
862
867
  this.renderOrder = signal(0);
863
868
  this.selected = signal(false);
864
869
  this.selected$ = toObservable(this.selected);
@@ -895,7 +900,11 @@ class NodeModel {
895
900
  };
896
901
  });
897
902
  this.parent = computed(() => this.entitiesService.nodes().find(n => n.node.id === this.parentId()) ?? null);
903
+ this.children = computed(() => this.entitiesService.nodes().filter(n => n.parentId() === this.node.id));
898
904
  this.color = signal(NodeModel.defaultColor);
905
+ this.resizable = signal(false);
906
+ this.resizing = signal(false);
907
+ this.resizerTemplate = signal(null);
899
908
  this.parentId = signal(null);
900
909
  if (isDefined(node.draggable)) {
901
910
  if (isDynamicNode(node)) {
@@ -921,9 +930,22 @@ class NodeModel {
921
930
  this.color.set(node.color);
922
931
  }
923
932
  }
933
+ if (node.type === 'default-group' && node.resizable) {
934
+ if (isDynamicNode(node)) {
935
+ this.resizable = node.resizable;
936
+ }
937
+ else {
938
+ this.resizable.set(node.resizable);
939
+ }
940
+ }
924
941
  }
925
- setPoint(point) {
926
- this.internalPoint.set(point);
942
+ setPoint(point, throttle) {
943
+ if (throttle) {
944
+ this.internalPoint.set(point);
945
+ }
946
+ else {
947
+ this.notThrottledPoint$.next(point);
948
+ }
927
949
  }
928
950
  /**
929
951
  * TODO find the way to implement this better
@@ -950,6 +972,23 @@ class NodeModel {
950
972
  }
951
973
  }
952
974
  }
975
+ if (node.type === 'html-template' || this.isComponentType) {
976
+ if (isDynamicNode(node)) {
977
+ effect(() => {
978
+ if (node.width && node.height) {
979
+ this.size.set({
980
+ width: node.width(),
981
+ height: node.height(),
982
+ });
983
+ }
984
+ }, { allowSignalWrites: true });
985
+ }
986
+ else {
987
+ if (node.width && node.height) {
988
+ this.size.set({ width: node.width, height: node.height });
989
+ }
990
+ }
991
+ }
953
992
  }
954
993
  createTextSignal() {
955
994
  const node = this.node;
@@ -1210,6 +1249,10 @@ class NodesChangeService {
1210
1249
  map(changedNode => [
1211
1250
  { type: 'position', id: changedNode.node.id, point: changedNode.point() }
1212
1251
  ]));
1252
+ this.nodeSizeChange$ = toObservable(this.entitiesService.nodes)
1253
+ .pipe(switchMap((nodes) => merge(...nodes.map(node => node.size$.pipe(skip(1), map(() => node))))), map(changedNode => [
1254
+ { type: 'size', id: changedNode.node.id, size: changedNode.size() }
1255
+ ]));
1213
1256
  this.nodeAddChange$ = toObservable(this.entitiesService.nodes)
1214
1257
  .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 }))));
1215
1258
  this.nodeRemoveChange$ = toObservable(this.entitiesService.nodes)
@@ -1218,7 +1261,7 @@ class NodesChangeService {
1218
1261
  .pipe(switchMap((nodes) => merge(...nodes.map(node => node.selected$.pipe(distinctUntilChanged(), skip(1), map(() => node))))), map((changedNode) => [
1219
1262
  { type: 'select', id: changedNode.node.id, selected: changedNode.selected() }
1220
1263
  ]));
1221
- this.changes$ = merge(this.nodesPositionChange$, this.nodeAddChange$, this.nodeRemoveChange$, this.nodeSelectedChange$).pipe(
1264
+ this.changes$ = merge(this.nodesPositionChange$, this.nodeSizeChange$, this.nodeAddChange$, this.nodeRemoveChange$, this.nodeSelectedChange$).pipe(
1222
1265
  // this fixes a bug when on fire node event change,
1223
1266
  // you can't get valid list of detached edges
1224
1267
  observeOn(asyncScheduler, DELAY_FOR_SCHEDULER));
@@ -1285,6 +1328,9 @@ class ChangesControllerDirective {
1285
1328
  this.onNodesChangePosition = this.nodeChangesOfType('position');
1286
1329
  this.onNodesChangePositionSignle = this.singleChange(this.nodeChangesOfType('position'));
1287
1330
  this.onNodesChangePositionMany = this.manyChanges(this.nodeChangesOfType('position'));
1331
+ this.onNodesChangeSize = this.nodeChangesOfType('size');
1332
+ this.onNodesChangeSizeSingle = this.singleChange(this.nodeChangesOfType('size'));
1333
+ this.onNodesChangeSizeMany = this.manyChanges(this.nodeChangesOfType('size'));
1288
1334
  this.onNodesChangeAdd = this.nodeChangesOfType('add');
1289
1335
  this.onNodesChangeAddSingle = this.singleChange(this.nodeChangesOfType('add'));
1290
1336
  this.onNodesChangeAddMany = this.manyChanges(this.nodeChangesOfType('add'));
@@ -1324,7 +1370,7 @@ class ChangesControllerDirective {
1324
1370
  return changes$.pipe(filter(changes => changes.length > 1));
1325
1371
  }
1326
1372
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ChangesControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1327
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ChangesControllerDirective, isStandalone: true, selector: "[changesController]", outputs: { onNodesChange: "onNodesChange", onNodesChangePosition: "onNodesChange.position", onNodesChangePositionSignle: "onNodesChange.position.single", onNodesChangePositionMany: "onNodesChange.position.many", onNodesChangeAdd: "onNodesChange.add", onNodesChangeAddSingle: "onNodesChange.add.single", onNodesChangeAddMany: "onNodesChange.add.many", onNodesChangeRemove: "onNodesChange.remove", onNodesChangeRemoveSingle: "onNodesChange.remove.single", onNodesChangeRemoveMany: "onNodesChange.remove.many", onNodesChangeSelect: "onNodesChange.select", onNodesChangeSelectSingle: "onNodesChange.select.single", onNodesChangeSelectMany: "onNodesChange.select.many", onEdgesChange: "onEdgesChange", onNodesChangeDetached: "onEdgesChange.detached", onNodesChangeDetachedSingle: "onEdgesChange.detached.single", onNodesChangeDetachedMany: "onEdgesChange.detached.many", onEdgesChangeAdd: "onEdgesChange.add", onEdgeChangeAddSingle: "onEdgesChange.add.single", onEdgeChangeAddMany: "onEdgesChange.add.many", onEdgeChangeRemove: "onEdgesChange.remove", onEdgeChangeRemoveSingle: "onEdgesChange.remove.single", onEdgeChangeRemoveMany: "onEdgesChange.remove.many", onEdgeChangeSelect: "onEdgesChange.select", onEdgeChangeSelectSingle: "onEdgesChange.select.single", onEdgeChangeSelectMany: "onEdgesChange.select.many" }, ngImport: i0 }); }
1373
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ChangesControllerDirective, isStandalone: true, selector: "[changesController]", outputs: { onNodesChange: "onNodesChange", onNodesChangePosition: "onNodesChange.position", onNodesChangePositionSignle: "onNodesChange.position.single", onNodesChangePositionMany: "onNodesChange.position.many", onNodesChangeSize: "onNodesChange.size", onNodesChangeSizeSingle: "onNodesChange.size.single", onNodesChangeSizeMany: "onNodesChange.size.many", onNodesChangeAdd: "onNodesChange.add", onNodesChangeAddSingle: "onNodesChange.add.single", onNodesChangeAddMany: "onNodesChange.add.many", onNodesChangeRemove: "onNodesChange.remove", onNodesChangeRemoveSingle: "onNodesChange.remove.single", onNodesChangeRemoveMany: "onNodesChange.remove.many", onNodesChangeSelect: "onNodesChange.select", onNodesChangeSelectSingle: "onNodesChange.select.single", onNodesChangeSelectMany: "onNodesChange.select.many", onEdgesChange: "onEdgesChange", onNodesChangeDetached: "onEdgesChange.detached", onNodesChangeDetachedSingle: "onEdgesChange.detached.single", onNodesChangeDetachedMany: "onEdgesChange.detached.many", onEdgesChangeAdd: "onEdgesChange.add", onEdgeChangeAddSingle: "onEdgesChange.add.single", onEdgeChangeAddMany: "onEdgesChange.add.many", onEdgeChangeRemove: "onEdgesChange.remove", onEdgeChangeRemoveSingle: "onEdgesChange.remove.single", onEdgeChangeRemoveMany: "onEdgesChange.remove.many", onEdgeChangeSelect: "onEdgesChange.select", onEdgeChangeSelectSingle: "onEdgesChange.select.single", onEdgeChangeSelectMany: "onEdgesChange.select.many" }, ngImport: i0 }); }
1328
1374
  }
1329
1375
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ChangesControllerDirective, decorators: [{
1330
1376
  type: Directive,
@@ -1343,6 +1389,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1343
1389
  }], onNodesChangePositionMany: [{
1344
1390
  type: Output,
1345
1391
  args: ['onNodesChange.position.many']
1392
+ }], onNodesChangeSize: [{
1393
+ type: Output,
1394
+ args: ['onNodesChange.size']
1395
+ }], onNodesChangeSizeSingle: [{
1396
+ type: Output,
1397
+ args: ['onNodesChange.size.single']
1398
+ }], onNodesChangeSizeMany: [{
1399
+ type: Output,
1400
+ args: ['onNodesChange.size.many']
1346
1401
  }], onNodesChangeAdd: [{
1347
1402
  type: Output,
1348
1403
  args: ['onNodesChange.add']
@@ -1442,25 +1497,42 @@ class RootPointerDirective {
1442
1497
  constructor() {
1443
1498
  this.host = inject(ElementRef).nativeElement;
1444
1499
  this.initialTouch$ = new Subject();
1500
+ this.prevTouchEvent = null;
1445
1501
  // TODO: do not emit if mouse not down
1446
1502
  this.mouseMovement$ = fromEvent(this.host, 'mousemove').pipe(map(event => ({
1447
1503
  x: event.clientX,
1448
1504
  y: event.clientY,
1505
+ movementX: event.movementX,
1506
+ movementY: event.movementY,
1507
+ target: event.target,
1449
1508
  originalEvent: event
1450
1509
  })), observeOn(animationFrameScheduler), share());
1451
1510
  this.touchMovement$ = merge(this.initialTouch$, fromEvent(this.host, 'touchmove')).pipe(tap((event) => event.preventDefault()), map((originalEvent) => {
1452
1511
  const x = originalEvent.touches[0]?.clientX ?? 0;
1453
1512
  const y = originalEvent.touches[0]?.clientY ?? 0;
1513
+ const movementX = this.prevTouchEvent
1514
+ ? originalEvent.touches[0].pageX - this.prevTouchEvent.touches[0].pageX
1515
+ : 0;
1516
+ const movementY = this.prevTouchEvent
1517
+ ? originalEvent.touches[0].pageY - this.prevTouchEvent.touches[0].pageY
1518
+ : 0;
1454
1519
  const target = document.elementFromPoint(x, y);
1455
- return { x, y, target, originalEvent };
1456
- }), observeOn(animationFrameScheduler), share());
1520
+ return { x, y, movementX, movementY, target, originalEvent };
1521
+ }), tap((event) => this.prevTouchEvent = event.originalEvent), observeOn(animationFrameScheduler), share());
1522
+ this.pointerMovement$ = merge(this.mouseMovement$, this.touchMovement$);
1457
1523
  this.touchEnd$ = fromEvent(this.host, 'touchend').pipe(map((originalEvent) => {
1458
1524
  const x = originalEvent.changedTouches[0]?.clientX ?? 0;
1459
1525
  const y = originalEvent.changedTouches[0]?.clientY ?? 0;
1460
1526
  const target = document.elementFromPoint(x, y);
1461
1527
  return { x, y, target, originalEvent };
1528
+ }), tap(() => this.prevTouchEvent = null), share());
1529
+ this.mouseUp$ = fromEvent(this.host, 'mouseup').pipe(map((originalEvent) => {
1530
+ const x = originalEvent.clientX;
1531
+ const y = originalEvent.clientY;
1532
+ const target = originalEvent.target;
1533
+ return { x, y, target, originalEvent };
1462
1534
  }), share());
1463
- this.pointerMovement$ = merge(this.mouseMovement$, this.touchMovement$);
1535
+ this.documentPointerEnd$ = merge(fromEvent(document, 'mouseup'), fromEvent(document, 'touchend')).pipe(share());
1464
1536
  }
1465
1537
  /**
1466
1538
  * We should know when user started a touch in order to not
@@ -1548,10 +1620,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1548
1620
  type: Injectable
1549
1621
  }], propDecorators: { createHandle: [] } });
1550
1622
 
1551
- function resizable(elems) {
1623
+ function resizable(elems, zone) {
1552
1624
  return new Observable((subscriber) => {
1553
1625
  let ro = new ResizeObserver((entries) => {
1554
- subscriber.next(entries);
1626
+ zone.run(() => subscriber.next(entries));
1555
1627
  });
1556
1628
  elems.forEach(e => ro.observe(e));
1557
1629
  return () => ro.disconnect();
@@ -1575,6 +1647,20 @@ const implementsWithInjector = (instance) => {
1575
1647
  return 'injector' in instance && 'get' in instance.injector;
1576
1648
  };
1577
1649
 
1650
+ /**
1651
+ * Service to fix cyclic dependency between node and resizable component
1652
+ */
1653
+ class NodeAccessorService {
1654
+ constructor() {
1655
+ this.model = signal(null);
1656
+ }
1657
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeAccessorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1658
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeAccessorService }); }
1659
+ }
1660
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeAccessorService, decorators: [{
1661
+ type: Injectable
1662
+ }] });
1663
+
1578
1664
  class HandleModel {
1579
1665
  constructor(rawHandle, parentNode) {
1580
1666
  this.rawHandle = rawHandle;
@@ -1704,42 +1790,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1704
1790
  type: Input
1705
1791
  }], ngOnInit: [] } });
1706
1792
 
1707
- class HandleSizeControllerDirective {
1708
- constructor() {
1709
- this.handleWrapper = inject(ElementRef);
1710
- }
1711
- ngAfterViewInit() {
1712
- const element = this.handleWrapper.nativeElement;
1713
- const rect = element.getBBox();
1714
- const stroke = getChildStrokeWidth(element);
1715
- this.handleModel.size.set({
1716
- width: rect.width + stroke,
1717
- height: rect.height + stroke
1718
- });
1719
- }
1720
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleSizeControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1721
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: { handleModel: ["handleSizeController", "handleModel"] }, ngImport: i0 }); }
1722
- }
1723
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleSizeControllerDirective, decorators: [{
1724
- type: Directive,
1725
- args: [{ selector: '[handleSizeController]' }]
1726
- }], propDecorators: { handleModel: [{
1727
- type: Input,
1728
- args: [{ required: true, alias: 'handleSizeController' }]
1729
- }] } });
1730
- function getChildStrokeWidth(element) {
1731
- const child = element.firstElementChild;
1732
- if (child) {
1733
- const stroke = getComputedStyle(child).strokeWidth;
1734
- const strokeAsNumber = Number(stroke.replace('px', ''));
1735
- if (isNaN(strokeAsNumber)) {
1736
- return 0;
1737
- }
1738
- return strokeAsNumber;
1739
- }
1740
- return 0;
1741
- }
1742
-
1743
1793
  class PointerDirective {
1744
1794
  constructor() {
1745
1795
  this.hostElement = inject(ElementRef).nativeElement;
@@ -1819,6 +1869,295 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1819
1869
  args: ['mouseout', ['$event']]
1820
1870
  }] } });
1821
1871
 
1872
+ class ResizableComponent {
1873
+ constructor() {
1874
+ this.nodeAccessor = inject(NodeAccessorService);
1875
+ this.rootPointer = inject(RootPointerDirective);
1876
+ this.viewportService = inject(ViewportService);
1877
+ this.hostRef = inject(ElementRef);
1878
+ this.resizerColor = '#2e414c';
1879
+ this.gap = 1.5;
1880
+ this.lineGap = 3;
1881
+ this.handleSize = 6;
1882
+ this.resizeSide = null;
1883
+ this.zoom = computed(() => this.viewportService.readableViewport().zoom ?? 0);
1884
+ this.minWidth = 0;
1885
+ this.minHeight = 0;
1886
+ // TODO: allow reszie beside the flow
1887
+ this.resizeOnGlobalMouseMove = this.rootPointer.pointerMovement$
1888
+ .pipe(filter(() => this.resizeSide !== null), tap((event) => this.resize(event)), takeUntilDestroyed())
1889
+ .subscribe();
1890
+ this.endResizeOnGlobalMouseUp = this.rootPointer.documentPointerEnd$
1891
+ .pipe(tap(() => this.endResize()), takeUntilDestroyed())
1892
+ .subscribe();
1893
+ }
1894
+ set resizable(value) {
1895
+ if (typeof value === 'boolean') {
1896
+ this.model.resizable.set(value);
1897
+ }
1898
+ else {
1899
+ this.model.resizable.set(true);
1900
+ }
1901
+ }
1902
+ get model() {
1903
+ return this.nodeAccessor.model();
1904
+ }
1905
+ ngOnInit() {
1906
+ this.model.resizerTemplate.set(this.resizer);
1907
+ }
1908
+ ngAfterViewInit() {
1909
+ this.minWidth = +getComputedStyle(this.hostRef.nativeElement).minWidth.replace('px', '') || 0;
1910
+ this.minHeight = +getComputedStyle(this.hostRef.nativeElement).minHeight.replace('px', '') || 0;
1911
+ }
1912
+ startResize(side, event) {
1913
+ event.stopPropagation();
1914
+ this.resizeSide = side;
1915
+ this.model.resizing.set(true);
1916
+ }
1917
+ resize({ movementX, movementY }) {
1918
+ const offsetX = round(movementX / this.zoom());
1919
+ const offsetY = round(movementY / this.zoom());
1920
+ switch (this.resizeSide) {
1921
+ case 'left':
1922
+ let x = this.model.point().x + offsetX;
1923
+ x = Math.max(x, this.getMinX());
1924
+ x = Math.min(x, this.getMaxX());
1925
+ // TODO this fixes increasing width when current node hits the parent
1926
+ if (x === this.getMinX() || x === this.getMaxX()) {
1927
+ return;
1928
+ }
1929
+ this.model.setPoint({ x, y: this.model.point().y }, false);
1930
+ this.model.size.update(({ height, width }) => {
1931
+ width -= offsetX;
1932
+ width = Math.max(width, this.minWidth);
1933
+ width = Math.min(width, this.getMaxWidth());
1934
+ return { height, width: width };
1935
+ });
1936
+ return;
1937
+ case 'right':
1938
+ this.model.size.update(({ height, width }) => {
1939
+ width += offsetX;
1940
+ width = Math.max(width, this.minWidth);
1941
+ width = Math.min(width, this.getMaxWidth());
1942
+ const bounds = getNodesBounds(this.model.children());
1943
+ width = Math.max(width, bounds.x + bounds.width);
1944
+ return { height, width };
1945
+ });
1946
+ return;
1947
+ case 'top':
1948
+ let y = this.model.point().y + offsetY;
1949
+ y = Math.max(y, this.getMinY());
1950
+ y = Math.min(y, this.getMaxY());
1951
+ if (y === this.getMinY() || y === this.getMaxY()) {
1952
+ return;
1953
+ }
1954
+ this.model.setPoint({ x: this.model.point().x, y }, false);
1955
+ this.model.size.update(({ height, width }) => {
1956
+ height -= offsetY;
1957
+ height = Math.max(height, this.minHeight);
1958
+ height = Math.min(height, this.getMaxHeight());
1959
+ return { width, height };
1960
+ });
1961
+ return;
1962
+ case 'bottom':
1963
+ this.model.size.update(({ height, width }) => {
1964
+ height += offsetY;
1965
+ height = Math.max(height, this.minHeight);
1966
+ height = Math.min(height, this.getMaxHeight());
1967
+ const bounds = getNodesBounds(this.model.children());
1968
+ height = Math.max(height, bounds.y + bounds.height);
1969
+ return { width, height };
1970
+ });
1971
+ return;
1972
+ case 'top-left': {
1973
+ let x = this.model.point().x + offsetX;
1974
+ x = Math.max(x, this.getMinX());
1975
+ x = Math.min(x, this.getMaxX());
1976
+ let y = this.model.point().y + offsetY;
1977
+ y = Math.max(y, this.getMinY());
1978
+ y = Math.min(y, this.getMaxY());
1979
+ if (x === this.getMinX() || y === this.getMinY() ||
1980
+ x === this.getMaxX() || y === this.getMaxY()) {
1981
+ return;
1982
+ }
1983
+ this.model.setPoint({ x, y }, false);
1984
+ this.model.size.update(({ height, width }) => {
1985
+ width -= offsetX;
1986
+ width = Math.max(width, this.minWidth);
1987
+ width = Math.min(width, this.getMaxWidth());
1988
+ height -= offsetY;
1989
+ height = Math.max(height, this.minHeight);
1990
+ height = Math.min(height, this.getMaxHeight());
1991
+ return { height, width };
1992
+ });
1993
+ return;
1994
+ }
1995
+ case 'top-right': {
1996
+ let y = this.model.point().y + offsetY;
1997
+ y = Math.max(y, this.getMinY());
1998
+ y = Math.min(y, this.getMaxY());
1999
+ if (y === this.getMinX() || y === this.getMaxY()) {
2000
+ return;
2001
+ }
2002
+ this.model.setPoint({ x: this.model.point().x, y }, false);
2003
+ this.model.size.update(({ height, width }) => {
2004
+ const bounds = getNodesBounds(this.model.children());
2005
+ width += offsetX;
2006
+ width = Math.max(width, this.minWidth);
2007
+ width = Math.min(width, this.getMaxWidth());
2008
+ width = Math.max(width, bounds.x + bounds.width);
2009
+ height -= offsetY;
2010
+ height = Math.max(height, this.minHeight);
2011
+ height = Math.min(height, this.getMaxHeight());
2012
+ return { height, width };
2013
+ });
2014
+ return;
2015
+ }
2016
+ case 'bottom-left': {
2017
+ let x = this.model.point().x + offsetX;
2018
+ x = Math.max(x, this.getMinX());
2019
+ x = Math.min(x, this.getMaxX());
2020
+ if (x === this.getMinX() || x === this.getMaxX()) {
2021
+ return;
2022
+ }
2023
+ this.model.setPoint({ x, y: this.model.point().y }, false);
2024
+ this.model.size.update(({ height, width }) => {
2025
+ width -= offsetX;
2026
+ width = Math.max(width, this.minWidth);
2027
+ width = Math.min(width, this.getMaxWidth());
2028
+ height += offsetY;
2029
+ height = Math.max(height, this.minHeight);
2030
+ height = Math.min(height, this.getMaxHeight());
2031
+ const bounds = getNodesBounds(this.model.children());
2032
+ height = Math.max(height, bounds.y + bounds.height);
2033
+ return { height, width };
2034
+ });
2035
+ return;
2036
+ }
2037
+ case 'bottom-right': {
2038
+ this.model.size.update(({ height, width }) => {
2039
+ const bounds = getNodesBounds(this.model.children());
2040
+ width += offsetX;
2041
+ width = Math.max(width, this.minWidth);
2042
+ width = Math.min(width, this.getMaxWidth());
2043
+ width = Math.max(width, bounds.x + bounds.width);
2044
+ height += offsetY;
2045
+ height = Math.max(height, this.minHeight);
2046
+ height = Math.min(height, this.getMaxHeight());
2047
+ height = Math.max(height, bounds.y + bounds.height);
2048
+ return { height, width };
2049
+ });
2050
+ }
2051
+ }
2052
+ }
2053
+ endResize() {
2054
+ this.resizeSide = null;
2055
+ this.model.resizing.set(false);
2056
+ }
2057
+ getMaxWidth() {
2058
+ const parent = this.model.parent();
2059
+ if (parent) {
2060
+ return parent.size().width - this.model.point().x;
2061
+ }
2062
+ return Infinity;
2063
+ }
2064
+ getMaxHeight() {
2065
+ const parent = this.model.parent();
2066
+ if (parent) {
2067
+ return parent.size().height - this.model.point().y;
2068
+ }
2069
+ return Infinity;
2070
+ }
2071
+ getMinX() {
2072
+ const parent = this.model.parent();
2073
+ if (parent) {
2074
+ return 0;
2075
+ }
2076
+ return -Infinity;
2077
+ }
2078
+ getMinY() {
2079
+ const parent = this.model.parent();
2080
+ if (parent) {
2081
+ return 0;
2082
+ }
2083
+ return -Infinity;
2084
+ }
2085
+ getMaxX() {
2086
+ const x = this.model.point().x;
2087
+ const width = this.model.size().width;
2088
+ const children = this.model.children();
2089
+ if (children) {
2090
+ const bounds = getNodesBounds(children);
2091
+ return x + (bounds.x + bounds.width) >= x + width ? x : (width - this.minWidth) + x;
2092
+ }
2093
+ return (width - this.minWidth) + x;
2094
+ }
2095
+ getMaxY() {
2096
+ const y = this.model.point().y;
2097
+ const height = this.model.size().height;
2098
+ const children = this.model.children();
2099
+ if (children) {
2100
+ const bounds = getNodesBounds(children);
2101
+ return y + (bounds.y + bounds.height) >= y + height ? y : (height - this.minHeight) + y;
2102
+ }
2103
+ return (height - this.minHeight) + y;
2104
+ }
2105
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ResizableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2106
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ResizableComponent, selector: "[resizable]", inputs: { resizable: "resizable", resizerColor: "resizerColor", gap: "gap" }, viewQueries: [{ propertyName: "resizer", first: true, predicate: ["resizer"], descendants: true, static: true }], ngImport: i0, template: "<ng-template #resizer>\n <svg:g>\n <!-- top line -->\n <svg:line\n class=\"top\"\n [attr.x1]=\"lineGap\"\n [attr.y1]=\"-gap\"\n [attr.x2]=\"model.size().width - lineGap\"\n [attr.y2]=\"-gap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('top', $event)\"\n />\n <!-- Left line -->\n <svg:line\n class=\"left\"\n [attr.x1]=\"-gap\"\n [attr.y1]=\"lineGap\"\n [attr.x2]=\"-gap\"\n [attr.y2]=\"model.size().height - lineGap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('left', $event)\"\n />\n <!-- Bottom line -->\n <svg:line\n class=\"bottom\"\n [attr.x1]=\"lineGap\"\n [attr.y1]=\"model.size().height + gap\"\n [attr.x2]=\"model.size().width - lineGap\"\n [attr.y2]=\"model.size().height + gap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('bottom', $event)\"\n />\n <!-- Right line -->\n <svg:line\n class=\"right\"\n [attr.x1]=\"model.size().width + gap\"\n [attr.y1]=\"lineGap\"\n [attr.x2]=\"model.size().width + gap\"\n [attr.y2]=\"model.size().height - lineGap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('right', $event)\"\n />\n\n <!-- Top Left -->\n <svg:rect\n class=\"top-left\"\n [attr.x]=\"-(handleSize / 2) - gap\"\n [attr.y]=\"-(handleSize / 2) - gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('top-left', $event)\"\n />\n\n <!-- Top right -->\n <svg:rect\n class=\"top-right\"\n [attr.x]=\"model.size().width - (handleSize / 2) + gap\"\n [attr.y]=\"-(handleSize / 2) - gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('top-right', $event)\"\n />\n\n <!-- Bottom left -->\n <svg:rect\n class=\"bottom-left\"\n [attr.x]=\"-(handleSize / 2) - gap\"\n [attr.y]=\"model.size().height - (handleSize / 2) + gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('bottom-left', $event)\"\n />\n\n <!-- Bottom right -->\n <svg:rect\n class=\"bottom-right\"\n [attr.x]=\"model.size().width - (handleSize / 2) + gap\"\n [attr.y]=\"model.size().height - (handleSize / 2) + gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('bottom-right', $event)\"\n />\n </svg:g>\n</ng-template>\n\n<ng-content />\n", styles: [".top{cursor:n-resize}.left{cursor:w-resize}.right{cursor:e-resize}.bottom{cursor:s-resize}.top-left{cursor:nw-resize}.top-right{cursor:ne-resize}.bottom-left{cursor:sw-resize}.bottom-right{cursor:se-resize}\n"], dependencies: [{ kind: "directive", type: PointerDirective, selector: "[pointerStart], [pointerEnd], [pointerOver], [pointerOut]", outputs: ["pointerOver", "pointerOut", "pointerStart", "pointerEnd"] }] }); }
2107
+ }
2108
+ __decorate([
2109
+ Microtask
2110
+ ], ResizableComponent.prototype, "ngAfterViewInit", null);
2111
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ResizableComponent, decorators: [{
2112
+ type: Component,
2113
+ args: [{ selector: '[resizable]', template: "<ng-template #resizer>\n <svg:g>\n <!-- top line -->\n <svg:line\n class=\"top\"\n [attr.x1]=\"lineGap\"\n [attr.y1]=\"-gap\"\n [attr.x2]=\"model.size().width - lineGap\"\n [attr.y2]=\"-gap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('top', $event)\"\n />\n <!-- Left line -->\n <svg:line\n class=\"left\"\n [attr.x1]=\"-gap\"\n [attr.y1]=\"lineGap\"\n [attr.x2]=\"-gap\"\n [attr.y2]=\"model.size().height - lineGap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('left', $event)\"\n />\n <!-- Bottom line -->\n <svg:line\n class=\"bottom\"\n [attr.x1]=\"lineGap\"\n [attr.y1]=\"model.size().height + gap\"\n [attr.x2]=\"model.size().width - lineGap\"\n [attr.y2]=\"model.size().height + gap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('bottom', $event)\"\n />\n <!-- Right line -->\n <svg:line\n class=\"right\"\n [attr.x1]=\"model.size().width + gap\"\n [attr.y1]=\"lineGap\"\n [attr.x2]=\"model.size().width + gap\"\n [attr.y2]=\"model.size().height - lineGap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('right', $event)\"\n />\n\n <!-- Top Left -->\n <svg:rect\n class=\"top-left\"\n [attr.x]=\"-(handleSize / 2) - gap\"\n [attr.y]=\"-(handleSize / 2) - gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('top-left', $event)\"\n />\n\n <!-- Top right -->\n <svg:rect\n class=\"top-right\"\n [attr.x]=\"model.size().width - (handleSize / 2) + gap\"\n [attr.y]=\"-(handleSize / 2) - gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('top-right', $event)\"\n />\n\n <!-- Bottom left -->\n <svg:rect\n class=\"bottom-left\"\n [attr.x]=\"-(handleSize / 2) - gap\"\n [attr.y]=\"model.size().height - (handleSize / 2) + gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('bottom-left', $event)\"\n />\n\n <!-- Bottom right -->\n <svg:rect\n class=\"bottom-right\"\n [attr.x]=\"model.size().width - (handleSize / 2) + gap\"\n [attr.y]=\"model.size().height - (handleSize / 2) + gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('bottom-right', $event)\"\n />\n </svg:g>\n</ng-template>\n\n<ng-content />\n", styles: [".top{cursor:n-resize}.left{cursor:w-resize}.right{cursor:e-resize}.bottom{cursor:s-resize}.top-left{cursor:nw-resize}.top-right{cursor:ne-resize}.bottom-left{cursor:sw-resize}.bottom-right{cursor:se-resize}\n"] }]
2114
+ }], propDecorators: { resizable: [{
2115
+ type: Input
2116
+ }], resizerColor: [{
2117
+ type: Input
2118
+ }], gap: [{
2119
+ type: Input
2120
+ }], resizer: [{
2121
+ type: ViewChild,
2122
+ args: ['resizer', { static: true }]
2123
+ }], ngAfterViewInit: [] } });
2124
+
2125
+ class HandleSizeControllerDirective {
2126
+ constructor() {
2127
+ this.handleWrapper = inject(ElementRef);
2128
+ }
2129
+ ngAfterViewInit() {
2130
+ const element = this.handleWrapper.nativeElement;
2131
+ const rect = element.getBBox();
2132
+ const stroke = getChildStrokeWidth(element);
2133
+ this.handleModel.size.set({
2134
+ width: rect.width + stroke,
2135
+ height: rect.height + stroke
2136
+ });
2137
+ }
2138
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleSizeControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2139
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: { handleModel: ["handleSizeController", "handleModel"] }, ngImport: i0 }); }
2140
+ }
2141
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleSizeControllerDirective, decorators: [{
2142
+ type: Directive,
2143
+ args: [{ selector: '[handleSizeController]' }]
2144
+ }], propDecorators: { handleModel: [{
2145
+ type: Input,
2146
+ args: [{ required: true, alias: 'handleSizeController' }]
2147
+ }] } });
2148
+ function getChildStrokeWidth(element) {
2149
+ const child = element.firstElementChild;
2150
+ if (child) {
2151
+ const stroke = getComputedStyle(child).strokeWidth;
2152
+ const strokeAsNumber = Number(stroke.replace('px', ''));
2153
+ if (isNaN(strokeAsNumber)) {
2154
+ return 0;
2155
+ }
2156
+ return strokeAsNumber;
2157
+ }
2158
+ return 0;
2159
+ }
2160
+
1822
2161
  class NodeComponent {
1823
2162
  constructor() {
1824
2163
  this.injector = inject(Injector);
@@ -1830,12 +2169,15 @@ class NodeComponent {
1830
2169
  this.selectionService = inject(SelectionService);
1831
2170
  this.hostRef = inject(ElementRef);
1832
2171
  this.connectionController = inject(ConnectionControllerDirective);
2172
+ this.nodeAccessor = inject(NodeAccessorService);
2173
+ this.zone = inject(NgZone);
1833
2174
  this.showMagnet = computed(() => this.flowStatusService.status().state === 'connection-start' ||
1834
2175
  this.flowStatusService.status().state === 'connection-validation');
1835
2176
  this.styleWidth = computed(() => `${this.nodeModel.size().width}px`);
1836
2177
  this.styleHeight = computed(() => `${this.nodeModel.size().height}px`);
1837
2178
  }
1838
2179
  ngOnInit() {
2180
+ this.nodeAccessor.model.set(this.nodeModel);
1839
2181
  this.handleService.node.set(this.nodeModel);
1840
2182
  effect(() => {
1841
2183
  if (this.nodeModel.draggable()) {
@@ -1846,7 +2188,8 @@ class NodeComponent {
1846
2188
  }
1847
2189
  });
1848
2190
  this.nodeModel.handles$
1849
- .pipe(switchMap((handles) => resizable(handles.map(h => h.parentReference)).pipe(map(() => handles))), tap((handles) => {
2191
+ .pipe(switchMap((handles) => resizable(handles.map(h => h.parentReference), this.zone)
2192
+ .pipe(map(() => handles))), tap((handles) => {
1850
2193
  // TODO (performance) inspect how to avoid calls of this when flow initially rendered
1851
2194
  handles.forEach(h => h.updateParent());
1852
2195
  }), takeUntilDestroyed())
@@ -1855,8 +2198,8 @@ class NodeComponent {
1855
2198
  ngAfterViewInit() {
1856
2199
  this.nodeModel.linkDefaultNodeSizeWithModelSize();
1857
2200
  if (this.nodeModel.node.type === 'html-template' || this.nodeModel.isComponentType) {
1858
- resizable([this.htmlWrapperRef.nativeElement])
1859
- .pipe(startWith(null), tap(() => {
2201
+ resizable([this.htmlWrapperRef.nativeElement], this.zone)
2202
+ .pipe(startWith(null), tap(() => this.nodeModel.handles().forEach(h => h.updateParent())), filter(() => !this.nodeModel.resizing()), tap(() => {
1860
2203
  const width = this.htmlWrapperRef.nativeElement.clientWidth;
1861
2204
  const height = this.htmlWrapperRef.nativeElement.clientHeight;
1862
2205
  this.nodeModel.size.set({ width, height });
@@ -1889,19 +2232,17 @@ class NodeComponent {
1889
2232
  }
1890
2233
  }
1891
2234
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1892
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: NodeComponent, selector: "g[node]", inputs: { nodeModel: "nodeModel", nodeTemplate: "nodeTemplate", groupNodeTemplate: "groupNodeTemplate" }, providers: [HandleService], viewQueries: [{ propertyName: "nodeContentRef", first: true, predicate: ["nodeContent"], descendants: true }, { propertyName: "htmlWrapperRef", first: true, predicate: ["htmlWrapper"], descendants: true }], ngImport: i0, template: "<!-- Default node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'default'\"\n class=\"selectable\"\n #nodeContent\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode(); selectNode()\"\n>\n <div\n #htmlWrapper\n class=\"default-node\"\n [class.default-node_selected]=\"nodeModel.selected()\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n [style.max-width]=\"styleWidth()\"\n [style.max-height]=\"styleHeight()\"\n >\n <div [outerHTML]=\"nodeModel.text()\"></div>\n\n <handle type=\"source\" [position]=\"nodeModel.sourcePosition()\" />\n <handle type=\"target\" [position]=\"nodeModel.targetPosition()\" />\n </div>\n</svg:foreignObject>\n\n<!-- Template node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'html-template' && nodeTemplate\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode()\"\n>\n <div #htmlWrapper class=\"wrapper\">\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Component node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.isComponentType\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode()\"\n>\n <div #htmlWrapper class=\"wrapper\">\n <ng-container\n [ngComponentOutlet]=\"$any(nodeModel.node.type)\"\n [ngComponentOutletInputs]=\"nodeModel.componentTypeInputs()\"\n [ngComponentOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Default group node -->\n<svg:rect\n *ngIf=\"nodeModel.node.type === 'default-group'\"\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [class.default-group-node_selected]=\"nodeModel.selected()\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n [style.stroke]=\"nodeModel.color()\"\n [style.fill]=\"nodeModel.color()\"\n (mousedown)=\"pullNode(); selectNode()\"\n/>\n\n<svg:g\n *ngIf=\"nodeModel.node.type === 'template-group' && groupNodeTemplate\"\n class=\"selectable\"\n (mousedown)=\"pullNode()\"\n>\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n</svg:g>\n\n<!-- Handles -->\n<ng-container *ngFor=\"let handle of nodeModel.handles()\">\n <svg:circle\n *ngIf=\"!handle.template\"\n class=\"default-handle\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n r=\"5\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n />\n\n <svg:g\n *ngIf=\"handle.template\"\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n >\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n\n <svg:circle\n *ngIf=\"showMagnet()\"\n class=\"magnet\"\n [attr.r]=\"nodeModel.magnetRadius\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n (pointerEnd)=\"endConnection(handle); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\"\n />\n</ng-container>\n", styles: [".wrapper{width:max-content}.magnet{opacity:0}.default-node{border:1.5px solid #1b262c;border-radius:5px;display:flex;align-items:center;justify-content:center;color:#000;background-color:#fff}.default-node_selected{border-width:2px}.default-group-node{stroke-width:1.5px;fill-opacity:.05}.default-group-node_selected{stroke-width:2px}.default-handle{stroke:#fff;fill:#1b262c}\n"], dependencies: [{ kind: "directive", type: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: HandleComponent, selector: "handle", inputs: ["position", "type", "id", "template"] }, { kind: "directive", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: ["handleSizeController"] }, { kind: "directive", type: PointerDirective, selector: "[pointerStart], [pointerEnd], [pointerOver], [pointerOut]", outputs: ["pointerOver", "pointerOut", "pointerStart", "pointerEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2235
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: NodeComponent, selector: "g[node]", inputs: { nodeModel: "nodeModel", nodeTemplate: "nodeTemplate", groupNodeTemplate: "groupNodeTemplate" }, providers: [HandleService, NodeAccessorService], viewQueries: [{ propertyName: "nodeContentRef", first: true, predicate: ["nodeContent"], descendants: true }, { propertyName: "htmlWrapperRef", first: true, predicate: ["htmlWrapper"], descendants: true }], ngImport: i0, template: "<!-- Default node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'default'\"\n class=\"selectable\"\n #nodeContent\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode(); selectNode()\"\n>\n <div\n #htmlWrapper\n class=\"default-node\"\n [class.default-node_selected]=\"nodeModel.selected()\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n [style.max-width]=\"styleWidth()\"\n [style.max-height]=\"styleHeight()\"\n >\n <div [outerHTML]=\"nodeModel.text()\"></div>\n\n <handle type=\"source\" [position]=\"nodeModel.sourcePosition()\" />\n <handle type=\"target\" [position]=\"nodeModel.targetPosition()\" />\n </div>\n</svg:foreignObject>\n\n<!-- Template node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'html-template' && nodeTemplate\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode()\"\n>\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Component node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.isComponentType\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode()\"\n>\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngComponentOutlet]=\"$any(nodeModel.node.type)\"\n [ngComponentOutletInputs]=\"nodeModel.componentTypeInputs()\"\n [ngComponentOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Default group node -->\n<svg:rect\n *ngIf=\"nodeModel.node.type === 'default-group'\"\n [resizable]=\"nodeModel.resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"nodeModel.color()\"\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [class.default-group-node_selected]=\"nodeModel.selected()\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n [style.stroke]=\"nodeModel.color()\"\n [style.fill]=\"nodeModel.color()\"\n (mousedown)=\"pullNode(); selectNode()\"\n/>\n\n<!-- Template group node -->\n<svg:g\n *ngIf=\"nodeModel.node.type === 'template-group' && groupNodeTemplate\"\n class=\"selectable\"\n (mousedown)=\"pullNode()\"\n>\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected, width: nodeModel.width, height: nodeModel.height } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n</svg:g>\n\n<!-- Resizer -->\n<ng-container *ngIf=\"nodeModel.resizerTemplate() as template\">\n <ng-container *ngIf=\"nodeModel.resizable()\">\n <ng-template [ngTemplateOutlet]=\"template\" />\n </ng-container>\n</ng-container>\n\n<!-- Handles -->\n<ng-container *ngFor=\"let handle of nodeModel.handles()\">\n <svg:circle\n *ngIf=\"!handle.template\"\n class=\"default-handle\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n r=\"5\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n />\n\n <svg:g\n *ngIf=\"handle.template\"\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n >\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n\n <svg:circle\n *ngIf=\"showMagnet()\"\n class=\"magnet\"\n [attr.r]=\"nodeModel.magnetRadius\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n (pointerEnd)=\"endConnection(handle); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\"\n />\n</ng-container>\n", styles: [".magnet{opacity:0}.wrapper{display:table-cell}.default-node{border:1.5px solid #1b262c;border-radius:5px;display:flex;align-items:center;justify-content:center;color:#000;background-color:#fff}.default-node_selected{border-width:2px}.default-group-node{stroke-width:1.5px;fill-opacity:.05}.default-group-node_selected{stroke-width:2px}.default-handle{stroke:#fff;fill:#1b262c}\n"], dependencies: [{ kind: "directive", type: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: HandleComponent, selector: "handle", inputs: ["position", "type", "id", "template"] }, { kind: "component", type: ResizableComponent, selector: "[resizable]", inputs: ["resizable", "resizerColor", "gap"] }, { kind: "directive", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: ["handleSizeController"] }, { kind: "directive", type: PointerDirective, selector: "[pointerStart], [pointerEnd], [pointerOver], [pointerOut]", outputs: ["pointerOver", "pointerOut", "pointerStart", "pointerEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1893
2236
  }
1894
2237
  __decorate([
1895
2238
  InjectionContext
1896
2239
  ], NodeComponent.prototype, "ngOnInit", null);
1897
2240
  __decorate([
1898
- Microtask // TODO (performance) check if we need microtask here
1899
- ,
1900
2241
  InjectionContext
1901
2242
  ], NodeComponent.prototype, "ngAfterViewInit", null);
1902
2243
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeComponent, decorators: [{
1903
2244
  type: Component,
1904
- args: [{ selector: 'g[node]', changeDetection: ChangeDetectionStrategy.OnPush, providers: [HandleService], template: "<!-- Default node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'default'\"\n class=\"selectable\"\n #nodeContent\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode(); selectNode()\"\n>\n <div\n #htmlWrapper\n class=\"default-node\"\n [class.default-node_selected]=\"nodeModel.selected()\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n [style.max-width]=\"styleWidth()\"\n [style.max-height]=\"styleHeight()\"\n >\n <div [outerHTML]=\"nodeModel.text()\"></div>\n\n <handle type=\"source\" [position]=\"nodeModel.sourcePosition()\" />\n <handle type=\"target\" [position]=\"nodeModel.targetPosition()\" />\n </div>\n</svg:foreignObject>\n\n<!-- Template node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'html-template' && nodeTemplate\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode()\"\n>\n <div #htmlWrapper class=\"wrapper\">\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Component node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.isComponentType\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode()\"\n>\n <div #htmlWrapper class=\"wrapper\">\n <ng-container\n [ngComponentOutlet]=\"$any(nodeModel.node.type)\"\n [ngComponentOutletInputs]=\"nodeModel.componentTypeInputs()\"\n [ngComponentOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Default group node -->\n<svg:rect\n *ngIf=\"nodeModel.node.type === 'default-group'\"\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [class.default-group-node_selected]=\"nodeModel.selected()\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n [style.stroke]=\"nodeModel.color()\"\n [style.fill]=\"nodeModel.color()\"\n (mousedown)=\"pullNode(); selectNode()\"\n/>\n\n<svg:g\n *ngIf=\"nodeModel.node.type === 'template-group' && groupNodeTemplate\"\n class=\"selectable\"\n (mousedown)=\"pullNode()\"\n>\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n</svg:g>\n\n<!-- Handles -->\n<ng-container *ngFor=\"let handle of nodeModel.handles()\">\n <svg:circle\n *ngIf=\"!handle.template\"\n class=\"default-handle\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n r=\"5\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n />\n\n <svg:g\n *ngIf=\"handle.template\"\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n >\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n\n <svg:circle\n *ngIf=\"showMagnet()\"\n class=\"magnet\"\n [attr.r]=\"nodeModel.magnetRadius\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n (pointerEnd)=\"endConnection(handle); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\"\n />\n</ng-container>\n", styles: [".wrapper{width:max-content}.magnet{opacity:0}.default-node{border:1.5px solid #1b262c;border-radius:5px;display:flex;align-items:center;justify-content:center;color:#000;background-color:#fff}.default-node_selected{border-width:2px}.default-group-node{stroke-width:1.5px;fill-opacity:.05}.default-group-node_selected{stroke-width:2px}.default-handle{stroke:#fff;fill:#1b262c}\n"] }]
2245
+ args: [{ selector: 'g[node]', changeDetection: ChangeDetectionStrategy.OnPush, providers: [HandleService, NodeAccessorService], template: "<!-- Default node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'default'\"\n class=\"selectable\"\n #nodeContent\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode(); selectNode()\"\n>\n <div\n #htmlWrapper\n class=\"default-node\"\n [class.default-node_selected]=\"nodeModel.selected()\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n [style.max-width]=\"styleWidth()\"\n [style.max-height]=\"styleHeight()\"\n >\n <div [outerHTML]=\"nodeModel.text()\"></div>\n\n <handle type=\"source\" [position]=\"nodeModel.sourcePosition()\" />\n <handle type=\"target\" [position]=\"nodeModel.targetPosition()\" />\n </div>\n</svg:foreignObject>\n\n<!-- Template node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'html-template' && nodeTemplate\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode()\"\n>\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Component node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.isComponentType\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode()\"\n>\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngComponentOutlet]=\"$any(nodeModel.node.type)\"\n [ngComponentOutletInputs]=\"nodeModel.componentTypeInputs()\"\n [ngComponentOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Default group node -->\n<svg:rect\n *ngIf=\"nodeModel.node.type === 'default-group'\"\n [resizable]=\"nodeModel.resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"nodeModel.color()\"\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [class.default-group-node_selected]=\"nodeModel.selected()\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n [style.stroke]=\"nodeModel.color()\"\n [style.fill]=\"nodeModel.color()\"\n (mousedown)=\"pullNode(); selectNode()\"\n/>\n\n<!-- Template group node -->\n<svg:g\n *ngIf=\"nodeModel.node.type === 'template-group' && groupNodeTemplate\"\n class=\"selectable\"\n (mousedown)=\"pullNode()\"\n>\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected, width: nodeModel.width, height: nodeModel.height } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n</svg:g>\n\n<!-- Resizer -->\n<ng-container *ngIf=\"nodeModel.resizerTemplate() as template\">\n <ng-container *ngIf=\"nodeModel.resizable()\">\n <ng-template [ngTemplateOutlet]=\"template\" />\n </ng-container>\n</ng-container>\n\n<!-- Handles -->\n<ng-container *ngFor=\"let handle of nodeModel.handles()\">\n <svg:circle\n *ngIf=\"!handle.template\"\n class=\"default-handle\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n r=\"5\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n />\n\n <svg:g\n *ngIf=\"handle.template\"\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n >\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n\n <svg:circle\n *ngIf=\"showMagnet()\"\n class=\"magnet\"\n [attr.r]=\"nodeModel.magnetRadius\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n (pointerEnd)=\"endConnection(handle); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\"\n />\n</ng-container>\n", styles: [".magnet{opacity:0}.wrapper{display:table-cell}.default-node{border:1.5px solid #1b262c;border-radius:5px;display:flex;align-items:center;justify-content:center;color:#000;background-color:#fff}.default-node_selected{border-width:2px}.default-group-node{stroke-width:1.5px;fill-opacity:.05}.default-group-node_selected{stroke-width:2px}.default-handle{stroke:#fff;fill:#1b262c}\n"] }]
1905
2246
  }], propDecorators: { nodeModel: [{
1906
2247
  type: Input
1907
2248
  }], nodeTemplate: [{
@@ -2249,7 +2590,7 @@ class FlowSizeControllerDirective {
2249
2590
  this.flowWidth = view === 'auto' ? '100%' : view[0];
2250
2591
  this.flowHeight = view === 'auto' ? '100%' : view[1];
2251
2592
  });
2252
- resizable([this.host.nativeElement]).pipe(tap(([entry]) => {
2593
+ resizable([this.host.nativeElement], inject(NgZone)).pipe(tap(([entry]) => {
2253
2594
  this.flowSettingsService.computedFlowWidth.set(entry.contentRect.width);
2254
2595
  this.flowSettingsService.computedFlowHeight.set(entry.contentRect.height);
2255
2596
  }), takeUntilDestroyed()).subscribe();
@@ -2279,6 +2620,9 @@ const changesControllerHostDirective = {
2279
2620
  'onNodesChange.position',
2280
2621
  'onNodesChange.position.single',
2281
2622
  'onNodesChange.position.many',
2623
+ 'onNodesChange.size',
2624
+ 'onNodesChange.size.single',
2625
+ 'onNodesChange.size.many',
2282
2626
  'onNodesChange.add',
2283
2627
  'onNodesChange.add.single',
2284
2628
  'onNodesChange.add.many',
@@ -2513,7 +2857,7 @@ class VflowComponent {
2513
2857
  SelectionService,
2514
2858
  FlowSettingsService,
2515
2859
  ComponentEventBusService
2516
- ], queries: [{ propertyName: "nodeTemplateDirective", first: true, predicate: NodeHtmlTemplateDirective, descendants: true }, { propertyName: "groupNodeTemplateDirective", first: true, predicate: GroupNodeTemplateDirective, descendants: true }, { propertyName: "edgeTemplateDirective", first: true, predicate: EdgeTemplateDirective, descendants: true }, { propertyName: "edgeLabelHtmlDirective", first: true, predicate: EdgeLabelHtmlTemplateDirective, descendants: true }, { propertyName: "connectionTemplateDirective", first: true, predicate: ConnectionTemplateDirective, descendants: true }], viewQueries: [{ propertyName: "mapContext", first: true, predicate: MapContextDirective, descendants: true }, { propertyName: "spacePointContext", first: true, predicate: SpacePointContextDirective, descendants: true }], hostDirectives: [{ directive: ConnectionControllerDirective, outputs: ["onConnect", "onConnect"] }, { directive: ChangesControllerDirective, outputs: ["onNodesChange", "onNodesChange", "onNodesChange.position", "onNodesChange.position", "onNodesChange.position.single", "onNodesChange.position.single", "onNodesChange.position.many", "onNodesChange.position.many", "onNodesChange.add", "onNodesChange.add", "onNodesChange.add.single", "onNodesChange.add.single", "onNodesChange.add.many", "onNodesChange.add.many", "onNodesChange.remove", "onNodesChange.remove", "onNodesChange.remove.single", "onNodesChange.remove.single", "onNodesChange.remove.many", "onNodesChange.remove.many", "onNodesChange.select", "onNodesChange.select", "onNodesChange.select.single", "onNodesChange.select.single", "onNodesChange.select.many", "onNodesChange.select.many", "onEdgesChange", "onEdgesChange", "onEdgesChange.detached", "onEdgesChange.detached", "onEdgesChange.detached.single", "onEdgesChange.detached.single", "onEdgesChange.detached.many", "onEdgesChange.detached.many", "onEdgesChange.add", "onEdgesChange.add", "onEdgesChange.add.single", "onEdgesChange.add.single", "onEdgesChange.add.many", "onEdgesChange.add.many", "onEdgesChange.remove", "onEdgesChange.remove", "onEdgesChange.remove.single", "onEdgesChange.remove.single", "onEdgesChange.remove.many", "onEdgesChange.remove.many", "onEdgesChange.select", "onEdgesChange.select", "onEdgesChange.select.single", "onEdgesChange.select.single", "onEdgesChange.select.many", "onEdgesChange.select.many"] }], ngImport: i0, template: "<svg:svg\n rootSvgRef\n rootSvgContext\n rootPointer\n flowSizeController\n class=\"root-svg\"\n #flow\n>\n <defs [markers]=\"markers()\" flowDefs />\n\n <g [background]=\"background\"/>\n\n <svg:g\n mapContext\n spacePointContext\n >\n <!-- Connection -->\n <svg:g\n connection\n [model]=\"connection\"\n [template]=\"connectionTemplateDirective?.templateRef\"\n />\n\n <!-- Edges -->\n <svg:g\n *ngFor=\"let model of edgeModels(); trackBy: trackEdges\"\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective?.templateRef\"\n />\n\n <!-- Nodes -->\n <svg:g\n *ngFor=\"let model of nodeModels(); trackBy: trackNodes\"\n node\n [nodeModel]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective?.templateRef\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective?.templateRef\"\n [attr.transform]=\"model.pointTransform()\"\n />\n </svg:g>\n\n</svg:svg>\n", styles: [":host{display:block;width:100%;height:100%;-webkit-user-select:none;user-select:none}:host ::ng-deep *{box-sizing:border-box}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: NodeComponent, selector: "g[node]", inputs: ["nodeModel", "nodeTemplate", "groupNodeTemplate"] }, { kind: "component", type: EdgeComponent, selector: "g[edge]", inputs: ["model", "edgeTemplate", "edgeLabelHtmlTemplate"] }, { kind: "component", type: ConnectionComponent, selector: "g[connection]", inputs: ["model", "template"] }, { kind: "component", type: DefsComponent, selector: "defs[flowDefs]", inputs: ["markers"] }, { kind: "component", type: BackgroundComponent, selector: "g[background]", inputs: ["background"] }, { kind: "directive", type: SpacePointContextDirective, selector: "g[spacePointContext]" }, { kind: "directive", type: MapContextDirective, selector: "g[mapContext]" }, { kind: "directive", type: RootSvgReferenceDirective, selector: "svg[rootSvgRef]" }, { kind: "directive", type: RootSvgContextDirective, selector: "svg[rootSvgContext]" }, { kind: "directive", type: RootPointerDirective, selector: "svg[rootPointer]" }, { kind: "directive", type: FlowSizeControllerDirective, selector: "svg[flowSizeController]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2860
+ ], queries: [{ propertyName: "nodeTemplateDirective", first: true, predicate: NodeHtmlTemplateDirective, descendants: true }, { propertyName: "groupNodeTemplateDirective", first: true, predicate: GroupNodeTemplateDirective, descendants: true }, { propertyName: "edgeTemplateDirective", first: true, predicate: EdgeTemplateDirective, descendants: true }, { propertyName: "edgeLabelHtmlDirective", first: true, predicate: EdgeLabelHtmlTemplateDirective, descendants: true }, { propertyName: "connectionTemplateDirective", first: true, predicate: ConnectionTemplateDirective, descendants: true }], viewQueries: [{ propertyName: "mapContext", first: true, predicate: MapContextDirective, descendants: true }, { propertyName: "spacePointContext", first: true, predicate: SpacePointContextDirective, descendants: true }], hostDirectives: [{ directive: ConnectionControllerDirective, outputs: ["onConnect", "onConnect"] }, { directive: ChangesControllerDirective, outputs: ["onNodesChange", "onNodesChange", "onNodesChange.position", "onNodesChange.position", "onNodesChange.position.single", "onNodesChange.position.single", "onNodesChange.position.many", "onNodesChange.position.many", "onNodesChange.size", "onNodesChange.size", "onNodesChange.size.single", "onNodesChange.size.single", "onNodesChange.size.many", "onNodesChange.size.many", "onNodesChange.add", "onNodesChange.add", "onNodesChange.add.single", "onNodesChange.add.single", "onNodesChange.add.many", "onNodesChange.add.many", "onNodesChange.remove", "onNodesChange.remove", "onNodesChange.remove.single", "onNodesChange.remove.single", "onNodesChange.remove.many", "onNodesChange.remove.many", "onNodesChange.select", "onNodesChange.select", "onNodesChange.select.single", "onNodesChange.select.single", "onNodesChange.select.many", "onNodesChange.select.many", "onEdgesChange", "onEdgesChange", "onEdgesChange.detached", "onEdgesChange.detached", "onEdgesChange.detached.single", "onEdgesChange.detached.single", "onEdgesChange.detached.many", "onEdgesChange.detached.many", "onEdgesChange.add", "onEdgesChange.add", "onEdgesChange.add.single", "onEdgesChange.add.single", "onEdgesChange.add.many", "onEdgesChange.add.many", "onEdgesChange.remove", "onEdgesChange.remove", "onEdgesChange.remove.single", "onEdgesChange.remove.single", "onEdgesChange.remove.many", "onEdgesChange.remove.many", "onEdgesChange.select", "onEdgesChange.select", "onEdgesChange.select.single", "onEdgesChange.select.single", "onEdgesChange.select.many", "onEdgesChange.select.many"] }], ngImport: i0, template: "<svg:svg\n rootSvgRef\n rootSvgContext\n rootPointer\n flowSizeController\n class=\"root-svg\"\n #flow\n>\n <defs [markers]=\"markers()\" flowDefs />\n\n <g [background]=\"background\"/>\n\n <svg:g\n mapContext\n spacePointContext\n >\n <!-- Connection -->\n <svg:g\n connection\n [model]=\"connection\"\n [template]=\"connectionTemplateDirective?.templateRef\"\n />\n\n <!-- Edges -->\n <svg:g\n *ngFor=\"let model of edgeModels(); trackBy: trackEdges\"\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective?.templateRef\"\n />\n\n <!-- Nodes -->\n <svg:g\n *ngFor=\"let model of nodeModels(); trackBy: trackNodes\"\n node\n [nodeModel]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective?.templateRef\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective?.templateRef\"\n [attr.transform]=\"model.pointTransform()\"\n />\n </svg:g>\n\n</svg:svg>\n", styles: [":host{display:block;width:100%;height:100%;-webkit-user-select:none;user-select:none}:host ::ng-deep *{box-sizing:border-box}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: NodeComponent, selector: "g[node]", inputs: ["nodeModel", "nodeTemplate", "groupNodeTemplate"] }, { kind: "component", type: EdgeComponent, selector: "g[edge]", inputs: ["model", "edgeTemplate", "edgeLabelHtmlTemplate"] }, { kind: "component", type: ConnectionComponent, selector: "g[connection]", inputs: ["model", "template"] }, { kind: "component", type: DefsComponent, selector: "defs[flowDefs]", inputs: ["markers"] }, { kind: "component", type: BackgroundComponent, selector: "g[background]", inputs: ["background"] }, { kind: "directive", type: SpacePointContextDirective, selector: "g[spacePointContext]" }, { kind: "directive", type: MapContextDirective, selector: "g[mapContext]" }, { kind: "directive", type: RootSvgReferenceDirective, selector: "svg[rootSvgRef]" }, { kind: "directive", type: RootSvgContextDirective, selector: "svg[rootSvgContext]" }, { kind: "directive", type: RootPointerDirective, selector: "svg[rootPointer]" }, { kind: "directive", type: FlowSizeControllerDirective, selector: "svg[flowSizeController]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2517
2861
  }
2518
2862
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: VflowComponent, decorators: [{
2519
2863
  type: Component,
@@ -2620,7 +2964,8 @@ const components = [
2620
2964
  ConnectionComponent,
2621
2965
  HandleComponent,
2622
2966
  DefsComponent,
2623
- BackgroundComponent
2967
+ BackgroundComponent,
2968
+ ResizableComponent,
2624
2969
  ];
2625
2970
  const directives = [
2626
2971
  SpacePointContextDirective,
@@ -2631,7 +2976,7 @@ const directives = [
2631
2976
  SelectableDirective,
2632
2977
  PointerDirective,
2633
2978
  RootPointerDirective,
2634
- FlowSizeControllerDirective
2979
+ FlowSizeControllerDirective,
2635
2980
  ];
2636
2981
  const templateDirectives = [
2637
2982
  NodeHtmlTemplateDirective,
@@ -2650,7 +2995,8 @@ class VflowModule {
2650
2995
  ConnectionComponent,
2651
2996
  HandleComponent,
2652
2997
  DefsComponent,
2653
- BackgroundComponent, SpacePointContextDirective,
2998
+ BackgroundComponent,
2999
+ ResizableComponent, SpacePointContextDirective,
2654
3000
  MapContextDirective,
2655
3001
  RootSvgReferenceDirective,
2656
3002
  RootSvgContextDirective,
@@ -2665,6 +3011,7 @@ class VflowModule {
2665
3011
  ConnectionTemplateDirective,
2666
3012
  HandleTemplateDirective], imports: [CommonModule], exports: [VflowComponent,
2667
3013
  HandleComponent,
3014
+ ResizableComponent,
2668
3015
  SelectableDirective, NodeHtmlTemplateDirective,
2669
3016
  GroupNodeTemplateDirective,
2670
3017
  EdgeLabelHtmlTemplateDirective,
@@ -2680,6 +3027,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
2680
3027
  exports: [
2681
3028
  VflowComponent,
2682
3029
  HandleComponent,
3030
+ ResizableComponent,
2683
3031
  SelectableDirective,
2684
3032
  ...templateDirectives
2685
3033
  ],
@@ -2693,5 +3041,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
2693
3041
  * Generated bundle index. Do not edit.
2694
3042
  */
2695
3043
 
2696
- export { ChangesControllerDirective, ConnectionControllerDirective, ConnectionTemplateDirective, CustomDynamicNodeComponent, CustomNodeComponent, EdgeLabelHtmlTemplateDirective, EdgeTemplateDirective, GroupNodeTemplateDirective, HandleComponent, HandleTemplateDirective, NodeHtmlTemplateDirective, SelectableDirective, VflowComponent, VflowModule, isComponentDynamicNode, isComponentStaticNode, isDefaultDynamicGroupNode, isDefaultDynamicNode, isDefaultStaticGroupNode, isDefaultStaticNode, isDynamicNode, isStaticNode, isTemplateDynamicGroupNode, isTemplateDynamicNode, isTemplateStaticGroupNode, isTemplateStaticNode };
3044
+ export { ChangesControllerDirective, ConnectionControllerDirective, ConnectionTemplateDirective, CustomDynamicNodeComponent, CustomNodeComponent, EdgeLabelHtmlTemplateDirective, EdgeTemplateDirective, GroupNodeTemplateDirective, HandleComponent, HandleTemplateDirective, NodeHtmlTemplateDirective, ResizableComponent, SelectableDirective, VflowComponent, VflowModule, isComponentDynamicNode, isComponentStaticNode, isDefaultDynamicGroupNode, isDefaultDynamicNode, isDefaultStaticGroupNode, isDefaultStaticNode, isDynamicNode, isStaticNode, isTemplateDynamicGroupNode, isTemplateDynamicNode, isTemplateStaticGroupNode, isTemplateStaticNode };
2697
3045
  //# sourceMappingURL=ngx-vflow.mjs.map