ngx-vflow 0.11.0 → 0.13.0-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 (44) hide show
  1. package/esm2022/lib/vflow/components/custom-node-base/custom-node-base.component.mjs +7 -3
  2. package/esm2022/lib/vflow/components/node/node.component.mjs +16 -13
  3. package/esm2022/lib/vflow/components/vflow/vflow.component.mjs +5 -2
  4. package/esm2022/lib/vflow/directives/changes-controller.directive.mjs +14 -2
  5. package/esm2022/lib/vflow/directives/flow-size-controller.directive.mjs +18 -17
  6. package/esm2022/lib/vflow/directives/root-pointer.directive.mjs +21 -4
  7. package/esm2022/lib/vflow/interfaces/component-node-event.interface.mjs +1 -1
  8. package/esm2022/lib/vflow/interfaces/node.interface.mjs +3 -3
  9. package/esm2022/lib/vflow/models/node.model.mjs +46 -7
  10. package/esm2022/lib/vflow/public-components/custom-dynamic-node/custom-dynamic-node.component.mjs +19 -0
  11. package/esm2022/lib/vflow/public-components/custom-node/custom-node.component.mjs +19 -0
  12. package/esm2022/lib/vflow/public-components/resizable/resizable.component.mjs +265 -0
  13. package/esm2022/lib/vflow/services/component-event-bus.service.mjs +1 -1
  14. package/esm2022/lib/vflow/services/draggable.service.mjs +2 -2
  15. package/esm2022/lib/vflow/services/node-accessor.service.mjs +16 -0
  16. package/esm2022/lib/vflow/services/node-changes.service.mjs +6 -2
  17. package/esm2022/lib/vflow/types/node-change.type.mjs +1 -1
  18. package/esm2022/lib/vflow/utils/resizable.mjs +3 -3
  19. package/esm2022/lib/vflow/vflow.module.mjs +9 -4
  20. package/esm2022/public-api.mjs +4 -3
  21. package/fesm2022/ngx-vflow.mjs +430 -77
  22. package/fesm2022/ngx-vflow.mjs.map +1 -1
  23. package/lib/vflow/components/node/node.component.d.ts +2 -0
  24. package/lib/vflow/components/vflow/vflow.component.d.ts +1 -1
  25. package/lib/vflow/directives/changes-controller.directive.d.ts +5 -2
  26. package/lib/vflow/directives/flow-size-controller.directive.d.ts +3 -2
  27. package/lib/vflow/directives/root-pointer.directive.d.ts +24 -6
  28. package/lib/vflow/directives/space-point-context.directive.d.ts +5 -0
  29. package/lib/vflow/interfaces/component-node-event.interface.d.ts +2 -2
  30. package/lib/vflow/interfaces/node.interface.d.ts +12 -2
  31. package/lib/vflow/models/edge.model.d.ts +1 -17
  32. package/lib/vflow/models/node.model.d.ts +13 -2
  33. package/lib/vflow/public-components/{custom-dynamic-node.component.d.ts → custom-dynamic-node/custom-dynamic-node.component.d.ts} +2 -2
  34. package/lib/vflow/public-components/{custom-node.component.d.ts → custom-node/custom-node.component.d.ts} +2 -2
  35. package/lib/vflow/public-components/resizable/resizable.component.d.ts +39 -0
  36. package/lib/vflow/services/node-accessor.service.d.ts +10 -0
  37. package/lib/vflow/services/node-changes.service.d.ts +8 -0
  38. package/lib/vflow/types/node-change.type.d.ts +8 -1
  39. package/lib/vflow/utils/resizable.d.ts +2 -1
  40. package/lib/vflow/vflow.module.d.ts +13 -12
  41. package/package.json +1 -1
  42. package/public-api.d.ts +3 -2
  43. package/esm2022/lib/vflow/public-components/custom-dynamic-node.component.mjs +0 -19
  44. package/esm2022/lib/vflow/public-components/custom-node.component.mjs +0 -19
@@ -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, 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
  /**
@@ -734,7 +734,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
734
734
 
735
735
  class CustomNodeBaseComponent {
736
736
  constructor() {
737
- this.eventBus = inject(ComponentEventBusService);
737
+ this.eventBus = inject(ComponentEventBusService, { optional: true });
738
738
  this.destroyRef = inject(DestroyRef);
739
739
  /**
740
740
  * Signal with selected state of node
@@ -746,7 +746,11 @@ class CustomNodeBaseComponent {
746
746
  this.selected.set(value);
747
747
  }
748
748
  ngOnInit() {
749
- this.trackEvents().pipe(takeUntilDestroyed(this.destroyRef)).subscribe();
749
+ if (this.eventBus) {
750
+ this.trackEvents()
751
+ .pipe(takeUntilDestroyed(this.destroyRef))
752
+ .subscribe();
753
+ }
750
754
  }
751
755
  trackEvents() {
752
756
  const props = Object.getOwnPropertyNames(this);
@@ -844,6 +848,7 @@ function isTemplateDynamicGroupNode(node) {
844
848
  return node.type === 'template-group';
845
849
  }
846
850
 
851
+ // TODO bad naming around points
847
852
  class NodeModel {
848
853
  static { this.defaultWidth = 100; }
849
854
  static { this.defaultHeight = 50; }
@@ -854,11 +859,15 @@ class NodeModel {
854
859
  this.entitiesService = inject(FlowEntitiesService);
855
860
  this.internalPoint = this.createInternalPointSignal();
856
861
  this.throttledPoint$ = toObservable(this.internalPoint).pipe(observeOn(animationFrameScheduler));
857
- this.point = toSignal(this.throttledPoint$, {
862
+ this.notThrottledPoint$ = new Subject();
863
+ this.point = toSignal(merge(this.throttledPoint$, this.notThrottledPoint$), {
858
864
  initialValue: this.internalPoint()
859
865
  });
860
866
  this.point$ = this.throttledPoint$;
861
867
  this.size = signal({ width: 0, height: 0 });
868
+ this.size$ = toObservable(this.size);
869
+ this.width = computed(() => this.size().width);
870
+ this.height = computed(() => this.size().height);
862
871
  this.renderOrder = signal(0);
863
872
  this.selected = signal(false);
864
873
  this.selected$ = toObservable(this.selected);
@@ -895,7 +904,11 @@ class NodeModel {
895
904
  };
896
905
  });
897
906
  this.parent = computed(() => this.entitiesService.nodes().find(n => n.node.id === this.parentId()) ?? null);
907
+ this.children = computed(() => this.entitiesService.nodes().filter(n => n.parentId() === this.node.id));
898
908
  this.color = signal(NodeModel.defaultColor);
909
+ this.resizable = signal(false);
910
+ this.resizing = signal(false);
911
+ this.resizerTemplate = signal(null);
899
912
  this.parentId = signal(null);
900
913
  if (isDefined(node.draggable)) {
901
914
  if (isDynamicNode(node)) {
@@ -921,9 +934,22 @@ class NodeModel {
921
934
  this.color.set(node.color);
922
935
  }
923
936
  }
937
+ if (node.type === 'default-group' && node.resizable) {
938
+ if (isDynamicNode(node)) {
939
+ this.resizable = node.resizable;
940
+ }
941
+ else {
942
+ this.resizable.set(node.resizable);
943
+ }
944
+ }
924
945
  }
925
- setPoint(point) {
926
- this.internalPoint.set(point);
946
+ setPoint(point, throttle) {
947
+ if (throttle) {
948
+ this.internalPoint.set(point);
949
+ }
950
+ else {
951
+ this.notThrottledPoint$.next(point);
952
+ }
927
953
  }
928
954
  /**
929
955
  * TODO find the way to implement this better
@@ -950,6 +976,23 @@ class NodeModel {
950
976
  }
951
977
  }
952
978
  }
979
+ if (node.type === 'html-template' || this.isComponentType) {
980
+ if (isDynamicNode(node)) {
981
+ effect(() => {
982
+ if (node.width && node.height) {
983
+ this.size.set({
984
+ width: node.width(),
985
+ height: node.height(),
986
+ });
987
+ }
988
+ }, { allowSignalWrites: true });
989
+ }
990
+ else {
991
+ if (node.width && node.height) {
992
+ this.size.set({ width: node.width, height: node.height });
993
+ }
994
+ }
995
+ }
953
996
  }
954
997
  createTextSignal() {
955
998
  const node = this.node;
@@ -1210,6 +1253,10 @@ class NodesChangeService {
1210
1253
  map(changedNode => [
1211
1254
  { type: 'position', id: changedNode.node.id, point: changedNode.point() }
1212
1255
  ]));
1256
+ this.nodeSizeChange$ = toObservable(this.entitiesService.nodes)
1257
+ .pipe(switchMap((nodes) => merge(...nodes.map(node => node.size$.pipe(skip(1), map(() => node))))), map(changedNode => [
1258
+ { type: 'size', id: changedNode.node.id, size: changedNode.size() }
1259
+ ]));
1213
1260
  this.nodeAddChange$ = toObservable(this.entitiesService.nodes)
1214
1261
  .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
1262
  this.nodeRemoveChange$ = toObservable(this.entitiesService.nodes)
@@ -1218,7 +1265,7 @@ class NodesChangeService {
1218
1265
  .pipe(switchMap((nodes) => merge(...nodes.map(node => node.selected$.pipe(distinctUntilChanged(), skip(1), map(() => node))))), map((changedNode) => [
1219
1266
  { type: 'select', id: changedNode.node.id, selected: changedNode.selected() }
1220
1267
  ]));
1221
- this.changes$ = merge(this.nodesPositionChange$, this.nodeAddChange$, this.nodeRemoveChange$, this.nodeSelectedChange$).pipe(
1268
+ this.changes$ = merge(this.nodesPositionChange$, this.nodeSizeChange$, this.nodeAddChange$, this.nodeRemoveChange$, this.nodeSelectedChange$).pipe(
1222
1269
  // this fixes a bug when on fire node event change,
1223
1270
  // you can't get valid list of detached edges
1224
1271
  observeOn(asyncScheduler, DELAY_FOR_SCHEDULER));
@@ -1285,6 +1332,9 @@ class ChangesControllerDirective {
1285
1332
  this.onNodesChangePosition = this.nodeChangesOfType('position');
1286
1333
  this.onNodesChangePositionSignle = this.singleChange(this.nodeChangesOfType('position'));
1287
1334
  this.onNodesChangePositionMany = this.manyChanges(this.nodeChangesOfType('position'));
1335
+ this.onNodesChangeSize = this.nodeChangesOfType('size');
1336
+ this.onNodesChangeSizeSingle = this.singleChange(this.nodeChangesOfType('size'));
1337
+ this.onNodesChangeSizeMany = this.manyChanges(this.nodeChangesOfType('size'));
1288
1338
  this.onNodesChangeAdd = this.nodeChangesOfType('add');
1289
1339
  this.onNodesChangeAddSingle = this.singleChange(this.nodeChangesOfType('add'));
1290
1340
  this.onNodesChangeAddMany = this.manyChanges(this.nodeChangesOfType('add'));
@@ -1324,7 +1374,7 @@ class ChangesControllerDirective {
1324
1374
  return changes$.pipe(filter(changes => changes.length > 1));
1325
1375
  }
1326
1376
  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 }); }
1377
+ 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
1378
  }
1329
1379
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ChangesControllerDirective, decorators: [{
1330
1380
  type: Directive,
@@ -1343,6 +1393,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1343
1393
  }], onNodesChangePositionMany: [{
1344
1394
  type: Output,
1345
1395
  args: ['onNodesChange.position.many']
1396
+ }], onNodesChangeSize: [{
1397
+ type: Output,
1398
+ args: ['onNodesChange.size']
1399
+ }], onNodesChangeSizeSingle: [{
1400
+ type: Output,
1401
+ args: ['onNodesChange.size.single']
1402
+ }], onNodesChangeSizeMany: [{
1403
+ type: Output,
1404
+ args: ['onNodesChange.size.many']
1346
1405
  }], onNodesChangeAdd: [{
1347
1406
  type: Output,
1348
1407
  args: ['onNodesChange.add']
@@ -1442,25 +1501,42 @@ class RootPointerDirective {
1442
1501
  constructor() {
1443
1502
  this.host = inject(ElementRef).nativeElement;
1444
1503
  this.initialTouch$ = new Subject();
1504
+ this.prevTouchEvent = null;
1445
1505
  // TODO: do not emit if mouse not down
1446
1506
  this.mouseMovement$ = fromEvent(this.host, 'mousemove').pipe(map(event => ({
1447
1507
  x: event.clientX,
1448
1508
  y: event.clientY,
1509
+ movementX: event.movementX,
1510
+ movementY: event.movementY,
1511
+ target: event.target,
1449
1512
  originalEvent: event
1450
1513
  })), observeOn(animationFrameScheduler), share());
1451
1514
  this.touchMovement$ = merge(this.initialTouch$, fromEvent(this.host, 'touchmove')).pipe(tap((event) => event.preventDefault()), map((originalEvent) => {
1452
1515
  const x = originalEvent.touches[0]?.clientX ?? 0;
1453
1516
  const y = originalEvent.touches[0]?.clientY ?? 0;
1517
+ const movementX = this.prevTouchEvent
1518
+ ? originalEvent.touches[0].pageX - this.prevTouchEvent.touches[0].pageX
1519
+ : 0;
1520
+ const movementY = this.prevTouchEvent
1521
+ ? originalEvent.touches[0].pageY - this.prevTouchEvent.touches[0].pageY
1522
+ : 0;
1454
1523
  const target = document.elementFromPoint(x, y);
1455
- return { x, y, target, originalEvent };
1456
- }), observeOn(animationFrameScheduler), share());
1524
+ return { x, y, movementX, movementY, target, originalEvent };
1525
+ }), tap((event) => this.prevTouchEvent = event.originalEvent), observeOn(animationFrameScheduler), share());
1526
+ this.pointerMovement$ = merge(this.mouseMovement$, this.touchMovement$);
1457
1527
  this.touchEnd$ = fromEvent(this.host, 'touchend').pipe(map((originalEvent) => {
1458
1528
  const x = originalEvent.changedTouches[0]?.clientX ?? 0;
1459
1529
  const y = originalEvent.changedTouches[0]?.clientY ?? 0;
1460
1530
  const target = document.elementFromPoint(x, y);
1461
1531
  return { x, y, target, originalEvent };
1532
+ }), tap(() => this.prevTouchEvent = null), share());
1533
+ this.mouseUp$ = fromEvent(this.host, 'mouseup').pipe(map((originalEvent) => {
1534
+ const x = originalEvent.clientX;
1535
+ const y = originalEvent.clientY;
1536
+ const target = originalEvent.target;
1537
+ return { x, y, target, originalEvent };
1462
1538
  }), share());
1463
- this.pointerMovement$ = merge(this.mouseMovement$, this.touchMovement$);
1539
+ this.documentPointerEnd$ = merge(fromEvent(document, 'mouseup'), fromEvent(document, 'touchend')).pipe(share());
1464
1540
  }
1465
1541
  /**
1466
1542
  * We should know when user started a touch in order to not
@@ -1548,10 +1624,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1548
1624
  type: Injectable
1549
1625
  }], propDecorators: { createHandle: [] } });
1550
1626
 
1551
- function resizable(elems) {
1627
+ function resizable(elems, zone) {
1552
1628
  return new Observable((subscriber) => {
1553
1629
  let ro = new ResizeObserver((entries) => {
1554
- subscriber.next(entries);
1630
+ zone.run(() => subscriber.next(entries));
1555
1631
  });
1556
1632
  elems.forEach(e => ro.observe(e));
1557
1633
  return () => ro.disconnect();
@@ -1575,6 +1651,20 @@ const implementsWithInjector = (instance) => {
1575
1651
  return 'injector' in instance && 'get' in instance.injector;
1576
1652
  };
1577
1653
 
1654
+ /**
1655
+ * Service to fix cyclic dependency between node and resizable component
1656
+ */
1657
+ class NodeAccessorService {
1658
+ constructor() {
1659
+ this.model = signal(null);
1660
+ }
1661
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeAccessorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1662
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeAccessorService }); }
1663
+ }
1664
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeAccessorService, decorators: [{
1665
+ type: Injectable
1666
+ }] });
1667
+
1578
1668
  class HandleModel {
1579
1669
  constructor(rawHandle, parentNode) {
1580
1670
  this.rawHandle = rawHandle;
@@ -1704,42 +1794,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1704
1794
  type: Input
1705
1795
  }], ngOnInit: [] } });
1706
1796
 
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
1797
  class PointerDirective {
1744
1798
  constructor() {
1745
1799
  this.hostElement = inject(ElementRef).nativeElement;
@@ -1819,6 +1873,295 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1819
1873
  args: ['mouseout', ['$event']]
1820
1874
  }] } });
1821
1875
 
1876
+ class ResizableComponent {
1877
+ constructor() {
1878
+ this.nodeAccessor = inject(NodeAccessorService);
1879
+ this.rootPointer = inject(RootPointerDirective);
1880
+ this.viewportService = inject(ViewportService);
1881
+ this.hostRef = inject(ElementRef);
1882
+ this.resizerColor = '#2e414c';
1883
+ this.gap = 1.5;
1884
+ this.lineGap = 3;
1885
+ this.handleSize = 6;
1886
+ this.resizeSide = null;
1887
+ this.zoom = computed(() => this.viewportService.readableViewport().zoom ?? 0);
1888
+ this.minWidth = 0;
1889
+ this.minHeight = 0;
1890
+ // TODO: allow reszie beside the flow
1891
+ this.resizeOnGlobalMouseMove = this.rootPointer.pointerMovement$
1892
+ .pipe(filter(() => this.resizeSide !== null), tap((event) => this.resize(event)), takeUntilDestroyed())
1893
+ .subscribe();
1894
+ this.endResizeOnGlobalMouseUp = this.rootPointer.documentPointerEnd$
1895
+ .pipe(tap(() => this.endResize()), takeUntilDestroyed())
1896
+ .subscribe();
1897
+ }
1898
+ set resizable(value) {
1899
+ if (typeof value === 'boolean') {
1900
+ this.model.resizable.set(value);
1901
+ }
1902
+ else {
1903
+ this.model.resizable.set(true);
1904
+ }
1905
+ }
1906
+ get model() {
1907
+ return this.nodeAccessor.model();
1908
+ }
1909
+ ngOnInit() {
1910
+ this.model.resizerTemplate.set(this.resizer);
1911
+ }
1912
+ ngAfterViewInit() {
1913
+ this.minWidth = +getComputedStyle(this.hostRef.nativeElement).minWidth.replace('px', '') || 0;
1914
+ this.minHeight = +getComputedStyle(this.hostRef.nativeElement).minHeight.replace('px', '') || 0;
1915
+ }
1916
+ startResize(side, event) {
1917
+ event.stopPropagation();
1918
+ this.resizeSide = side;
1919
+ this.model.resizing.set(true);
1920
+ }
1921
+ resize({ movementX, movementY }) {
1922
+ const offsetX = round(movementX / this.zoom());
1923
+ const offsetY = round(movementY / this.zoom());
1924
+ switch (this.resizeSide) {
1925
+ case 'left':
1926
+ let x = this.model.point().x + offsetX;
1927
+ x = Math.max(x, this.getMinX());
1928
+ x = Math.min(x, this.getMaxX());
1929
+ // TODO this fixes increasing width when current node hits the parent
1930
+ if (x === this.getMinX() || x === this.getMaxX()) {
1931
+ return;
1932
+ }
1933
+ this.model.setPoint({ x, y: this.model.point().y }, false);
1934
+ this.model.size.update(({ height, width }) => {
1935
+ width -= offsetX;
1936
+ width = Math.max(width, this.minWidth);
1937
+ width = Math.min(width, this.getMaxWidth());
1938
+ return { height, width: width };
1939
+ });
1940
+ return;
1941
+ case 'right':
1942
+ this.model.size.update(({ height, width }) => {
1943
+ width += offsetX;
1944
+ width = Math.max(width, this.minWidth);
1945
+ width = Math.min(width, this.getMaxWidth());
1946
+ const bounds = getNodesBounds(this.model.children());
1947
+ width = Math.max(width, bounds.x + bounds.width);
1948
+ return { height, width };
1949
+ });
1950
+ return;
1951
+ case 'top':
1952
+ let y = this.model.point().y + offsetY;
1953
+ y = Math.max(y, this.getMinY());
1954
+ y = Math.min(y, this.getMaxY());
1955
+ if (y === this.getMinY() || y === this.getMaxY()) {
1956
+ return;
1957
+ }
1958
+ this.model.setPoint({ x: this.model.point().x, y }, false);
1959
+ this.model.size.update(({ height, width }) => {
1960
+ height -= offsetY;
1961
+ height = Math.max(height, this.minHeight);
1962
+ height = Math.min(height, this.getMaxHeight());
1963
+ return { width, height };
1964
+ });
1965
+ return;
1966
+ case 'bottom':
1967
+ this.model.size.update(({ height, width }) => {
1968
+ height += offsetY;
1969
+ height = Math.max(height, this.minHeight);
1970
+ height = Math.min(height, this.getMaxHeight());
1971
+ const bounds = getNodesBounds(this.model.children());
1972
+ height = Math.max(height, bounds.y + bounds.height);
1973
+ return { width, height };
1974
+ });
1975
+ return;
1976
+ case 'top-left': {
1977
+ let x = this.model.point().x + offsetX;
1978
+ x = Math.max(x, this.getMinX());
1979
+ x = Math.min(x, this.getMaxX());
1980
+ let y = this.model.point().y + offsetY;
1981
+ y = Math.max(y, this.getMinY());
1982
+ y = Math.min(y, this.getMaxY());
1983
+ if (x === this.getMinX() || y === this.getMinY() ||
1984
+ x === this.getMaxX() || y === this.getMaxY()) {
1985
+ return;
1986
+ }
1987
+ this.model.setPoint({ x, y }, false);
1988
+ this.model.size.update(({ height, width }) => {
1989
+ width -= offsetX;
1990
+ width = Math.max(width, this.minWidth);
1991
+ width = Math.min(width, this.getMaxWidth());
1992
+ height -= offsetY;
1993
+ height = Math.max(height, this.minHeight);
1994
+ height = Math.min(height, this.getMaxHeight());
1995
+ return { height, width };
1996
+ });
1997
+ return;
1998
+ }
1999
+ case 'top-right': {
2000
+ let y = this.model.point().y + offsetY;
2001
+ y = Math.max(y, this.getMinY());
2002
+ y = Math.min(y, this.getMaxY());
2003
+ if (y === this.getMinX() || y === this.getMaxY()) {
2004
+ return;
2005
+ }
2006
+ this.model.setPoint({ x: this.model.point().x, y }, false);
2007
+ this.model.size.update(({ height, width }) => {
2008
+ const bounds = getNodesBounds(this.model.children());
2009
+ width += offsetX;
2010
+ width = Math.max(width, this.minWidth);
2011
+ width = Math.min(width, this.getMaxWidth());
2012
+ width = Math.max(width, bounds.x + bounds.width);
2013
+ height -= offsetY;
2014
+ height = Math.max(height, this.minHeight);
2015
+ height = Math.min(height, this.getMaxHeight());
2016
+ return { height, width };
2017
+ });
2018
+ return;
2019
+ }
2020
+ case 'bottom-left': {
2021
+ let x = this.model.point().x + offsetX;
2022
+ x = Math.max(x, this.getMinX());
2023
+ x = Math.min(x, this.getMaxX());
2024
+ if (x === this.getMinX() || x === this.getMaxX()) {
2025
+ return;
2026
+ }
2027
+ this.model.setPoint({ x, y: this.model.point().y }, false);
2028
+ this.model.size.update(({ height, width }) => {
2029
+ width -= offsetX;
2030
+ width = Math.max(width, this.minWidth);
2031
+ width = Math.min(width, this.getMaxWidth());
2032
+ height += offsetY;
2033
+ height = Math.max(height, this.minHeight);
2034
+ height = Math.min(height, this.getMaxHeight());
2035
+ const bounds = getNodesBounds(this.model.children());
2036
+ height = Math.max(height, bounds.y + bounds.height);
2037
+ return { height, width };
2038
+ });
2039
+ return;
2040
+ }
2041
+ case 'bottom-right': {
2042
+ this.model.size.update(({ height, width }) => {
2043
+ const bounds = getNodesBounds(this.model.children());
2044
+ width += offsetX;
2045
+ width = Math.max(width, this.minWidth);
2046
+ width = Math.min(width, this.getMaxWidth());
2047
+ width = Math.max(width, bounds.x + bounds.width);
2048
+ height += offsetY;
2049
+ height = Math.max(height, this.minHeight);
2050
+ height = Math.min(height, this.getMaxHeight());
2051
+ height = Math.max(height, bounds.y + bounds.height);
2052
+ return { height, width };
2053
+ });
2054
+ }
2055
+ }
2056
+ }
2057
+ endResize() {
2058
+ this.resizeSide = null;
2059
+ this.model.resizing.set(false);
2060
+ }
2061
+ getMaxWidth() {
2062
+ const parent = this.model.parent();
2063
+ if (parent) {
2064
+ return parent.size().width - this.model.point().x;
2065
+ }
2066
+ return Infinity;
2067
+ }
2068
+ getMaxHeight() {
2069
+ const parent = this.model.parent();
2070
+ if (parent) {
2071
+ return parent.size().height - this.model.point().y;
2072
+ }
2073
+ return Infinity;
2074
+ }
2075
+ getMinX() {
2076
+ const parent = this.model.parent();
2077
+ if (parent) {
2078
+ return 0;
2079
+ }
2080
+ return -Infinity;
2081
+ }
2082
+ getMinY() {
2083
+ const parent = this.model.parent();
2084
+ if (parent) {
2085
+ return 0;
2086
+ }
2087
+ return -Infinity;
2088
+ }
2089
+ getMaxX() {
2090
+ const x = this.model.point().x;
2091
+ const width = this.model.size().width;
2092
+ const children = this.model.children();
2093
+ if (children) {
2094
+ const bounds = getNodesBounds(children);
2095
+ return x + (bounds.x + bounds.width) >= x + width ? x : (width - this.minWidth) + x;
2096
+ }
2097
+ return (width - this.minWidth) + x;
2098
+ }
2099
+ getMaxY() {
2100
+ const y = this.model.point().y;
2101
+ const height = this.model.size().height;
2102
+ const children = this.model.children();
2103
+ if (children) {
2104
+ const bounds = getNodesBounds(children);
2105
+ return y + (bounds.y + bounds.height) >= y + height ? y : (height - this.minHeight) + y;
2106
+ }
2107
+ return (height - this.minHeight) + y;
2108
+ }
2109
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ResizableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2110
+ 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"] }] }); }
2111
+ }
2112
+ __decorate([
2113
+ Microtask
2114
+ ], ResizableComponent.prototype, "ngAfterViewInit", null);
2115
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ResizableComponent, decorators: [{
2116
+ type: Component,
2117
+ 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"] }]
2118
+ }], propDecorators: { resizable: [{
2119
+ type: Input
2120
+ }], resizerColor: [{
2121
+ type: Input
2122
+ }], gap: [{
2123
+ type: Input
2124
+ }], resizer: [{
2125
+ type: ViewChild,
2126
+ args: ['resizer', { static: true }]
2127
+ }], ngAfterViewInit: [] } });
2128
+
2129
+ class HandleSizeControllerDirective {
2130
+ constructor() {
2131
+ this.handleWrapper = inject(ElementRef);
2132
+ }
2133
+ ngAfterViewInit() {
2134
+ const element = this.handleWrapper.nativeElement;
2135
+ const rect = element.getBBox();
2136
+ const stroke = getChildStrokeWidth(element);
2137
+ this.handleModel.size.set({
2138
+ width: rect.width + stroke,
2139
+ height: rect.height + stroke
2140
+ });
2141
+ }
2142
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleSizeControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2143
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: { handleModel: ["handleSizeController", "handleModel"] }, ngImport: i0 }); }
2144
+ }
2145
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleSizeControllerDirective, decorators: [{
2146
+ type: Directive,
2147
+ args: [{ selector: '[handleSizeController]' }]
2148
+ }], propDecorators: { handleModel: [{
2149
+ type: Input,
2150
+ args: [{ required: true, alias: 'handleSizeController' }]
2151
+ }] } });
2152
+ function getChildStrokeWidth(element) {
2153
+ const child = element.firstElementChild;
2154
+ if (child) {
2155
+ const stroke = getComputedStyle(child).strokeWidth;
2156
+ const strokeAsNumber = Number(stroke.replace('px', ''));
2157
+ if (isNaN(strokeAsNumber)) {
2158
+ return 0;
2159
+ }
2160
+ return strokeAsNumber;
2161
+ }
2162
+ return 0;
2163
+ }
2164
+
1822
2165
  class NodeComponent {
1823
2166
  constructor() {
1824
2167
  this.injector = inject(Injector);
@@ -1830,12 +2173,15 @@ class NodeComponent {
1830
2173
  this.selectionService = inject(SelectionService);
1831
2174
  this.hostRef = inject(ElementRef);
1832
2175
  this.connectionController = inject(ConnectionControllerDirective);
2176
+ this.nodeAccessor = inject(NodeAccessorService);
2177
+ this.zone = inject(NgZone);
1833
2178
  this.showMagnet = computed(() => this.flowStatusService.status().state === 'connection-start' ||
1834
2179
  this.flowStatusService.status().state === 'connection-validation');
1835
2180
  this.styleWidth = computed(() => `${this.nodeModel.size().width}px`);
1836
2181
  this.styleHeight = computed(() => `${this.nodeModel.size().height}px`);
1837
2182
  }
1838
2183
  ngOnInit() {
2184
+ this.nodeAccessor.model.set(this.nodeModel);
1839
2185
  this.handleService.node.set(this.nodeModel);
1840
2186
  effect(() => {
1841
2187
  if (this.nodeModel.draggable()) {
@@ -1846,7 +2192,8 @@ class NodeComponent {
1846
2192
  }
1847
2193
  });
1848
2194
  this.nodeModel.handles$
1849
- .pipe(switchMap((handles) => resizable(handles.map(h => h.parentReference)).pipe(map(() => handles))), tap((handles) => {
2195
+ .pipe(switchMap((handles) => resizable(handles.map(h => h.parentReference), this.zone)
2196
+ .pipe(map(() => handles))), tap((handles) => {
1850
2197
  // TODO (performance) inspect how to avoid calls of this when flow initially rendered
1851
2198
  handles.forEach(h => h.updateParent());
1852
2199
  }), takeUntilDestroyed())
@@ -1855,8 +2202,8 @@ class NodeComponent {
1855
2202
  ngAfterViewInit() {
1856
2203
  this.nodeModel.linkDefaultNodeSizeWithModelSize();
1857
2204
  if (this.nodeModel.node.type === 'html-template' || this.nodeModel.isComponentType) {
1858
- resizable([this.htmlWrapperRef.nativeElement])
1859
- .pipe(startWith(null), tap(() => {
2205
+ resizable([this.htmlWrapperRef.nativeElement], this.zone)
2206
+ .pipe(startWith(null), tap(() => this.nodeModel.handles().forEach(h => h.updateParent())), filter(() => !this.nodeModel.resizing()), tap(() => {
1860
2207
  const width = this.htmlWrapperRef.nativeElement.clientWidth;
1861
2208
  const height = this.htmlWrapperRef.nativeElement.clientHeight;
1862
2209
  this.nodeModel.size.set({ width, height });
@@ -1889,19 +2236,17 @@ class NodeComponent {
1889
2236
  }
1890
2237
  }
1891
2238
  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 }); }
2239
+ 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
2240
  }
1894
2241
  __decorate([
1895
2242
  InjectionContext
1896
2243
  ], NodeComponent.prototype, "ngOnInit", null);
1897
2244
  __decorate([
1898
- Microtask // TODO (performance) check if we need microtask here
1899
- ,
1900
2245
  InjectionContext
1901
2246
  ], NodeComponent.prototype, "ngAfterViewInit", null);
1902
2247
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeComponent, decorators: [{
1903
2248
  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"] }]
2249
+ 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
2250
  }], propDecorators: { nodeModel: [{
1906
2251
  type: Input
1907
2252
  }], nodeTemplate: [{
@@ -2242,31 +2587,32 @@ class FlowSizeControllerDirective {
2242
2587
  constructor() {
2243
2588
  this.host = inject(ElementRef);
2244
2589
  this.flowSettingsService = inject(FlowSettingsService);
2245
- this.flowWidth = 0;
2246
- this.flowHeight = 0;
2247
- effect(() => {
2590
+ this.flowWidth = computed(() => {
2248
2591
  const view = this.flowSettingsService.view();
2249
- this.flowWidth = view === 'auto' ? '100%' : view[0];
2250
- this.flowHeight = view === 'auto' ? '100%' : view[1];
2592
+ return view === 'auto' ? '100%' : view[0];
2251
2593
  });
2252
- resizable([this.host.nativeElement]).pipe(tap(([entry]) => {
2594
+ this.flowHeight = computed(() => {
2595
+ const view = this.flowSettingsService.view();
2596
+ return view === 'auto' ? '100%' : view[1];
2597
+ });
2598
+ resizable([this.host.nativeElement], inject(NgZone)).pipe(tap(([entry]) => {
2253
2599
  this.flowSettingsService.computedFlowWidth.set(entry.contentRect.width);
2254
2600
  this.flowSettingsService.computedFlowHeight.set(entry.contentRect.height);
2255
2601
  }), takeUntilDestroyed()).subscribe();
2256
2602
  }
2257
2603
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowSizeControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2258
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: FlowSizeControllerDirective, selector: "svg[flowSizeController]", host: { properties: { "attr.width": "this.flowWidth", "attr.height": "this.flowHeight" } }, ngImport: i0 }); }
2604
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: FlowSizeControllerDirective, selector: "svg[flowSizeController]", host: { properties: { "attr.width": "flowWidth()", "attr.height": "flowHeight()" } }, ngImport: i0 }); }
2259
2605
  }
2260
2606
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowSizeControllerDirective, decorators: [{
2261
2607
  type: Directive,
2262
- args: [{ selector: 'svg[flowSizeController]' }]
2263
- }], ctorParameters: function () { return []; }, propDecorators: { flowWidth: [{
2264
- type: HostBinding,
2265
- args: ['attr.width']
2266
- }], flowHeight: [{
2267
- type: HostBinding,
2268
- args: ['attr.height']
2269
- }] } });
2608
+ args: [{
2609
+ selector: 'svg[flowSizeController]',
2610
+ host: {
2611
+ '[attr.width]': 'flowWidth()',
2612
+ '[attr.height]': 'flowHeight()'
2613
+ }
2614
+ }]
2615
+ }], ctorParameters: function () { return []; } });
2270
2616
 
2271
2617
  const connectionControllerHostDirective = {
2272
2618
  directive: ConnectionControllerDirective,
@@ -2279,6 +2625,9 @@ const changesControllerHostDirective = {
2279
2625
  'onNodesChange.position',
2280
2626
  'onNodesChange.position.single',
2281
2627
  'onNodesChange.position.many',
2628
+ 'onNodesChange.size',
2629
+ 'onNodesChange.size.single',
2630
+ 'onNodesChange.size.many',
2282
2631
  'onNodesChange.add',
2283
2632
  'onNodesChange.add.single',
2284
2633
  'onNodesChange.add.many',
@@ -2513,7 +2862,7 @@ class VflowComponent {
2513
2862
  SelectionService,
2514
2863
  FlowSettingsService,
2515
2864
  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 }); }
2865
+ ], 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
2866
  }
2518
2867
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: VflowComponent, decorators: [{
2519
2868
  type: Component,
@@ -2620,7 +2969,8 @@ const components = [
2620
2969
  ConnectionComponent,
2621
2970
  HandleComponent,
2622
2971
  DefsComponent,
2623
- BackgroundComponent
2972
+ BackgroundComponent,
2973
+ ResizableComponent,
2624
2974
  ];
2625
2975
  const directives = [
2626
2976
  SpacePointContextDirective,
@@ -2631,7 +2981,7 @@ const directives = [
2631
2981
  SelectableDirective,
2632
2982
  PointerDirective,
2633
2983
  RootPointerDirective,
2634
- FlowSizeControllerDirective
2984
+ FlowSizeControllerDirective,
2635
2985
  ];
2636
2986
  const templateDirectives = [
2637
2987
  NodeHtmlTemplateDirective,
@@ -2650,7 +3000,8 @@ class VflowModule {
2650
3000
  ConnectionComponent,
2651
3001
  HandleComponent,
2652
3002
  DefsComponent,
2653
- BackgroundComponent, SpacePointContextDirective,
3003
+ BackgroundComponent,
3004
+ ResizableComponent, SpacePointContextDirective,
2654
3005
  MapContextDirective,
2655
3006
  RootSvgReferenceDirective,
2656
3007
  RootSvgContextDirective,
@@ -2665,6 +3016,7 @@ class VflowModule {
2665
3016
  ConnectionTemplateDirective,
2666
3017
  HandleTemplateDirective], imports: [CommonModule], exports: [VflowComponent,
2667
3018
  HandleComponent,
3019
+ ResizableComponent,
2668
3020
  SelectableDirective, NodeHtmlTemplateDirective,
2669
3021
  GroupNodeTemplateDirective,
2670
3022
  EdgeLabelHtmlTemplateDirective,
@@ -2680,6 +3032,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
2680
3032
  exports: [
2681
3033
  VflowComponent,
2682
3034
  HandleComponent,
3035
+ ResizableComponent,
2683
3036
  SelectableDirective,
2684
3037
  ...templateDirectives
2685
3038
  ],
@@ -2693,5 +3046,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
2693
3046
  * Generated bundle index. Do not edit.
2694
3047
  */
2695
3048
 
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 };
3049
+ 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
3050
  //# sourceMappingURL=ngx-vflow.mjs.map