ngx-vflow 1.0.7 → 1.1.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 (45) hide show
  1. package/esm2022/lib/vflow/components/node/node.component.mjs +18 -49
  2. package/esm2022/lib/vflow/components/vflow/vflow.component.mjs +3 -3
  3. package/esm2022/lib/vflow/directives/changes-controller.directive.mjs +55 -1
  4. package/esm2022/lib/vflow/directives/node-handles-controller.directive.mjs +33 -0
  5. package/esm2022/lib/vflow/directives/node-resize-controller.directive.mjs +35 -0
  6. package/esm2022/lib/vflow/directives/selectable.directive.mjs +2 -2
  7. package/esm2022/lib/vflow/models/handle.model.mjs +33 -33
  8. package/esm2022/lib/vflow/models/node.model.mjs +30 -67
  9. package/esm2022/lib/vflow/public-components/handle/handle.component.mjs +3 -3
  10. package/esm2022/lib/vflow/public-components/resizable/resizable.component.mjs +4 -3
  11. package/esm2022/lib/vflow/services/draggable.service.mjs +2 -2
  12. package/esm2022/lib/vflow/services/handle.service.mjs +1 -1
  13. package/esm2022/lib/vflow/testing-utils/component-mocks/handle-mock.component.mjs +22 -0
  14. package/esm2022/lib/vflow/testing-utils/component-mocks/minimap-mock.component.mjs +22 -0
  15. package/esm2022/lib/vflow/testing-utils/component-mocks/node-toolbar-mock.component.mjs +19 -0
  16. package/esm2022/lib/vflow/testing-utils/component-mocks/resizable-mock.component.mjs +21 -0
  17. package/esm2022/lib/vflow/testing-utils/component-mocks/vflow-mock.component.mjs +251 -0
  18. package/esm2022/lib/vflow/testing-utils/directive-mocks/connection-controller-mock.directive.mjs +15 -0
  19. package/esm2022/lib/vflow/testing-utils/directive-mocks/drag-handle-mock.directive.mjs +11 -0
  20. package/esm2022/lib/vflow/testing-utils/directive-mocks/selectable-mock.directive.mjs +14 -0
  21. package/esm2022/lib/vflow/testing-utils/directive-mocks/template-mock.directive.mjs +87 -0
  22. package/esm2022/lib/vflow/testing-utils/provide-custom-node-mocks.mjs +9 -8
  23. package/esm2022/lib/vflow/testing-utils/vflow-mocks.mjs +26 -0
  24. package/esm2022/public-api.mjs +11 -1
  25. package/fesm2022/ngx-vflow.mjs +689 -182
  26. package/fesm2022/ngx-vflow.mjs.map +1 -1
  27. package/lib/vflow/components/node/node.component.d.ts +5 -11
  28. package/lib/vflow/directives/changes-controller.directive.d.ts +54 -0
  29. package/lib/vflow/directives/node-handles-controller.directive.d.ts +11 -0
  30. package/lib/vflow/directives/node-resize-controller.directive.d.ts +11 -0
  31. package/lib/vflow/models/handle.model.d.ts +8 -23
  32. package/lib/vflow/models/node.model.d.ts +17 -13
  33. package/lib/vflow/services/handle.service.d.ts +1 -1
  34. package/lib/vflow/testing-utils/component-mocks/handle-mock.component.d.ts +11 -0
  35. package/lib/vflow/testing-utils/component-mocks/minimap-mock.component.d.ts +10 -0
  36. package/lib/vflow/testing-utils/component-mocks/node-toolbar-mock.component.d.ts +7 -0
  37. package/lib/vflow/testing-utils/component-mocks/resizable-mock.component.d.ts +8 -0
  38. package/lib/vflow/testing-utils/component-mocks/vflow-mock.component.d.ts +48 -0
  39. package/lib/vflow/testing-utils/directive-mocks/connection-controller-mock.directive.d.ts +7 -0
  40. package/lib/vflow/testing-utils/directive-mocks/drag-handle-mock.directive.d.ts +5 -0
  41. package/lib/vflow/testing-utils/directive-mocks/selectable-mock.directive.d.ts +5 -0
  42. package/lib/vflow/testing-utils/directive-mocks/template-mock.directive.d.ts +32 -0
  43. package/lib/vflow/testing-utils/vflow-mocks.d.ts +10 -0
  44. package/package.json +1 -1
  45. package/public-api.d.ts +10 -0
@@ -1,9 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
- import { signal, computed, Injectable, inject, ElementRef, Directive, effect, untracked, TemplateRef, DestroyRef, EventEmitter, OutputEmitterRef, input, viewChild, Component, ChangeDetectionStrategy, Injector, runInInjectionContext, output, HostListener, NgZone, contentChild, Input, forwardRef } from '@angular/core';
2
+ import { signal, computed, Injectable, inject, ElementRef, Directive, effect, untracked, TemplateRef, DestroyRef, EventEmitter, OutputEmitterRef, input, viewChild, Component, ChangeDetectionStrategy, Injector, output, HostListener, runInInjectionContext, NgZone, contentChild, Input, forwardRef } from '@angular/core';
3
3
  import { select } from 'd3-selection';
4
4
  import { zoomIdentity, zoom } from 'd3-zoom';
5
- import { switchMap, merge, fromEvent, tap, Subject, Observable, observeOn, animationFrameScheduler, skip, map, pairwise, filter, distinctUntilChanged, asyncScheduler, zip, share, startWith, of } from 'rxjs';
6
- import { toObservable, takeUntilDestroyed, toSignal, outputFromObservable } from '@angular/core/rxjs-interop';
5
+ import { switchMap, merge, fromEvent, tap, Subject, Observable, skip, map, pairwise, filter, distinctUntilChanged, observeOn, asyncScheduler, zip, animationFrameScheduler, share, startWith, of } from 'rxjs';
6
+ import { toObservable, takeUntilDestroyed, outputFromObservable, toSignal } from '@angular/core/rxjs-interop';
7
7
  import { drag } from 'd3-drag';
8
8
  import { __decorate } from 'tslib';
9
9
  import { NgTemplateOutlet, NgComponentOutlet, KeyValuePipe } from '@angular/common';
@@ -545,7 +545,7 @@ function moveNode(model, point) {
545
545
  point.y = Math.min(parent.size().height - model.size().height, point.y);
546
546
  point.y = Math.max(0, point.y);
547
547
  }
548
- model.setPoint(point, true);
548
+ model.setPoint(point);
549
549
  }
550
550
 
551
551
  class EdgeTemplateDirective {
@@ -827,26 +827,29 @@ function isTemplateDynamicGroupNode(node) {
827
827
  return node.type === 'template-group';
828
828
  }
829
829
 
830
- // TODO bad naming around points
831
830
  class NodeModel {
832
831
  static { this.defaultWidth = 100; }
833
832
  static { this.defaultHeight = 50; }
834
833
  static { this.defaultColor = '#1b262c'; }
835
834
  constructor(node) {
836
835
  this.node = node;
837
- this.flowSettingsService = inject(FlowSettingsService);
838
836
  this.entitiesService = inject(FlowEntitiesService);
839
- this.internalPoint = this.createInternalPointSignal();
840
- this.throttledPoint$ = toObservable(this.internalPoint).pipe(observeOn(animationFrameScheduler));
841
- this.notThrottledPoint$ = new Subject();
842
- this.point = toSignal(merge(this.throttledPoint$, this.notThrottledPoint$), {
843
- initialValue: this.internalPoint(),
844
- });
845
- this.point$ = this.throttledPoint$;
846
- this.size = signal({ width: 0, height: 0 });
837
+ this.point = this.createInternalPointSignal();
838
+ this.point$ = toObservable(this.point);
839
+ this.width = this.createWidthSignal(NodeModel.defaultWidth);
840
+ this.width$ = toObservable(this.width);
841
+ this.height = this.createHeightSignal(NodeModel.defaultHeight);
842
+ this.height$ = toObservable(this.height);
843
+ /**
844
+ * @deprecated use width or height signals
845
+ */
846
+ this.size = computed(() => ({ width: this.width(), height: this.height() }));
847
+ /**
848
+ * @deprecated use width$ or height$
849
+ */
847
850
  this.size$ = toObservable(this.size);
848
- this.width = computed(() => this.size().width);
849
- this.height = computed(() => this.size().height);
851
+ this.styleWidth = computed(() => `${this.width()}px`);
852
+ this.styleHeight = computed(() => `${this.height()}px`);
850
853
  this.renderOrder = signal(0);
851
854
  this.selected = signal(false);
852
855
  this.selected$ = toObservable(this.selected);
@@ -916,56 +919,8 @@ class NodeModel {
916
919
  }
917
920
  }
918
921
  }
919
- setPoint(point, throttle) {
920
- if (throttle) {
921
- this.internalPoint.set(point);
922
- }
923
- else {
924
- this.notThrottledPoint$.next(point);
925
- }
926
- }
927
- /**
928
- * TODO find the way to implement this better
929
- */
930
- linkDefaultNodeSizeWithModelSize() {
931
- const node = this.node;
932
- switch (node.type) {
933
- case 'default':
934
- case 'default-group':
935
- case 'template-group': {
936
- if (isDynamicNode(node)) {
937
- effect(() => {
938
- this.size.set({
939
- width: node.width?.() ?? NodeModel.defaultWidth,
940
- height: node.height?.() ?? NodeModel.defaultHeight,
941
- });
942
- }, { allowSignalWrites: true });
943
- }
944
- else {
945
- this.size.set({
946
- width: node.width ?? NodeModel.defaultWidth,
947
- height: node.height ?? NodeModel.defaultHeight,
948
- });
949
- }
950
- }
951
- }
952
- if (node.type === 'html-template' || this.isComponentType) {
953
- if (isDynamicNode(node)) {
954
- effect(() => {
955
- if (node.width && node.height) {
956
- this.size.set({
957
- width: node.width(),
958
- height: node.height(),
959
- });
960
- }
961
- }, { allowSignalWrites: true });
962
- }
963
- else {
964
- if (node.width && node.height) {
965
- this.size.set({ width: node.width, height: node.height });
966
- }
967
- }
968
- }
922
+ setPoint(point) {
923
+ this.point.set(point);
969
924
  }
970
925
  createTextSignal() {
971
926
  const node = this.node;
@@ -982,6 +937,16 @@ class NodeModel {
982
937
  createInternalPointSignal() {
983
938
  return isDynamicNode(this.node) ? this.node.point : signal({ x: this.node.point.x, y: this.node.point.y });
984
939
  }
940
+ createWidthSignal(defaultValue) {
941
+ return isDynamicNode(this.node)
942
+ ? (this.node.width ?? signal(defaultValue))
943
+ : signal(this.node.width ?? defaultValue);
944
+ }
945
+ createHeightSignal(defaultValue) {
946
+ return isDynamicNode(this.node)
947
+ ? (this.node.height ?? signal(defaultValue))
948
+ : signal(this.node.height ?? defaultValue);
949
+ }
985
950
  }
986
951
 
987
952
  class EdgeLabelModel {
@@ -1451,37 +1416,67 @@ class ChangesControllerDirective {
1451
1416
  this.onNodesChangePosition = outputFromObservable(this.nodeChangesOfType('position'), {
1452
1417
  alias: 'onNodesChange.position',
1453
1418
  });
1419
+ /**
1420
+ * @deprecated use `onNodesChange.position` instead
1421
+ */
1454
1422
  this.onNodesChangePositionSignle = outputFromObservable(this.singleChange(this.nodeChangesOfType('position')), { alias: 'onNodesChange.position.single' });
1423
+ /**
1424
+ * @deprecated use `onNodesChange.position` instead
1425
+ */
1455
1426
  this.onNodesChangePositionMany = outputFromObservable(this.manyChanges(this.nodeChangesOfType('position')), { alias: 'onNodesChange.position.many' });
1456
1427
  this.onNodesChangeSize = outputFromObservable(this.nodeChangesOfType('size'), {
1457
1428
  alias: 'onNodesChange.size',
1458
1429
  });
1430
+ /**
1431
+ * @deprecated use `onNodesChange.size` instead
1432
+ */
1459
1433
  this.onNodesChangeSizeSingle = outputFromObservable(this.singleChange(this.nodeChangesOfType('size')), {
1460
1434
  alias: 'onNodesChange.size.single',
1461
1435
  });
1436
+ /**
1437
+ * @deprecated use `onNodesChange.size` instead
1438
+ */
1462
1439
  this.onNodesChangeSizeMany = outputFromObservable(this.manyChanges(this.nodeChangesOfType('size')), {
1463
1440
  alias: 'onNodesChange.size.many',
1464
1441
  });
1465
1442
  this.onNodesChangeAdd = outputFromObservable(this.nodeChangesOfType('add'), {
1466
1443
  alias: 'onNodesChange.add',
1467
1444
  });
1445
+ /**
1446
+ * @deprecated use `onNodesChange.add` instead
1447
+ */
1468
1448
  this.onNodesChangeAddSingle = outputFromObservable(this.singleChange(this.nodeChangesOfType('add')), {
1469
1449
  alias: 'onNodesChange.add.single',
1470
1450
  });
1451
+ /**
1452
+ * @deprecated use `onNodesChange.add` instead
1453
+ */
1471
1454
  this.onNodesChangeAddMany = outputFromObservable(this.manyChanges(this.nodeChangesOfType('add')), {
1472
1455
  alias: 'onNodesChange.add.many',
1473
1456
  });
1474
1457
  this.onNodesChangeRemove = outputFromObservable(this.nodeChangesOfType('remove'), {
1475
1458
  alias: 'onNodesChange.remove',
1476
1459
  });
1460
+ /**
1461
+ * @deprecated use `onNodesChange.remove` instead
1462
+ */
1477
1463
  this.onNodesChangeRemoveSingle = outputFromObservable(this.singleChange(this.nodeChangesOfType('remove')), { alias: 'onNodesChange.remove.single' });
1464
+ /**
1465
+ * @deprecated use `onNodesChange.remove` instead
1466
+ */
1478
1467
  this.onNodesChangeRemoveMany = outputFromObservable(this.manyChanges(this.nodeChangesOfType('remove')), {
1479
1468
  alias: 'onNodesChange.remove.many',
1480
1469
  });
1481
1470
  this.onNodesChangeSelect = outputFromObservable(this.nodeChangesOfType('select'), {
1482
1471
  alias: 'onNodesChange.select',
1483
1472
  });
1473
+ /**
1474
+ * @deprecated use `onNodesChange.select` instead
1475
+ */
1484
1476
  this.onNodesChangeSelectSingle = outputFromObservable(this.singleChange(this.nodeChangesOfType('select')), { alias: 'onNodesChange.select.single' });
1477
+ /**
1478
+ * @deprecated use `onNodesChange.select` instead
1479
+ */
1485
1480
  this.onNodesChangeSelectMany = outputFromObservable(this.manyChanges(this.nodeChangesOfType('select')), {
1486
1481
  alias: 'onNodesChange.select.many',
1487
1482
  });
@@ -1492,32 +1487,56 @@ class ChangesControllerDirective {
1492
1487
  this.onNodesChangeDetached = outputFromObservable(this.edgeChangesOfType('detached'), {
1493
1488
  alias: 'onEdgesChange.detached',
1494
1489
  });
1490
+ /**
1491
+ * @deprecated use `onEdgesChange.detached` instead
1492
+ */
1495
1493
  this.onNodesChangeDetachedSingle = outputFromObservable(this.singleChange(this.edgeChangesOfType('detached')), { alias: 'onEdgesChange.detached.single' });
1494
+ /**
1495
+ * @deprecated use `onEdgesChange.detached` instead
1496
+ */
1496
1497
  this.onNodesChangeDetachedMany = outputFromObservable(this.manyChanges(this.edgeChangesOfType('detached')), { alias: 'onEdgesChange.detached.many' });
1497
1498
  this.onEdgesChangeAdd = outputFromObservable(this.edgeChangesOfType('add'), {
1498
1499
  alias: 'onEdgesChange.add',
1499
1500
  });
1501
+ /**
1502
+ * @deprecated use `onEdgesChange.add` instead
1503
+ */
1500
1504
  this.onEdgeChangeAddSingle = outputFromObservable(this.singleChange(this.edgeChangesOfType('add')), {
1501
1505
  alias: 'onEdgesChange.add.single',
1502
1506
  });
1507
+ /**
1508
+ * @deprecated use `onEdgesChange.add` instead
1509
+ */
1503
1510
  this.onEdgeChangeAddMany = outputFromObservable(this.manyChanges(this.edgeChangesOfType('add')), {
1504
1511
  alias: 'onEdgesChange.add.many',
1505
1512
  });
1506
1513
  this.onEdgeChangeRemove = outputFromObservable(this.edgeChangesOfType('remove'), {
1507
1514
  alias: 'onEdgesChange.remove',
1508
1515
  });
1516
+ /**
1517
+ * @deprecated use `onEdgesChange.remove` instead
1518
+ */
1509
1519
  this.onEdgeChangeRemoveSingle = outputFromObservable(this.singleChange(this.edgeChangesOfType('remove')), {
1510
1520
  alias: 'onEdgesChange.remove.single',
1511
1521
  });
1522
+ /**
1523
+ * @deprecated use `onEdgesChange.remove` instead
1524
+ */
1512
1525
  this.onEdgeChangeRemoveMany = outputFromObservable(this.manyChanges(this.edgeChangesOfType('remove')), {
1513
1526
  alias: 'onEdgesChange.remove.many',
1514
1527
  });
1515
1528
  this.onEdgeChangeSelect = outputFromObservable(this.edgeChangesOfType('select'), {
1516
1529
  alias: 'onEdgesChange.select',
1517
1530
  });
1531
+ /**
1532
+ * @deprecated use `onEdgesChange.select` instead
1533
+ */
1518
1534
  this.onEdgeChangeSelectSingle = outputFromObservable(this.singleChange(this.edgeChangesOfType('select')), {
1519
1535
  alias: 'onEdgesChange.select.single',
1520
1536
  });
1537
+ /**
1538
+ * @deprecated use `onEdgesChange.select` instead
1539
+ */
1521
1540
  this.onEdgeChangeSelectMany = outputFromObservable(this.manyChanges(this.edgeChangesOfType('select')), {
1522
1541
  alias: 'onEdgesChange.select.many',
1523
1542
  });
@@ -1838,33 +1857,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
1838
1857
  type: Injectable
1839
1858
  }], propDecorators: { createHandle: [] } });
1840
1859
 
1841
- function resizable(elems, zone) {
1842
- return new Observable((subscriber) => {
1843
- const ro = new ResizeObserver((entries) => {
1844
- zone.run(() => subscriber.next(entries));
1845
- });
1846
- elems.forEach((e) => ro.observe(e));
1847
- return () => ro.disconnect();
1848
- });
1849
- }
1850
-
1851
- function InjectionContext(target, key, descriptor) {
1852
- const originalMethod = descriptor.value;
1853
- descriptor.value = function (...args) {
1854
- if (implementsWithInjector(this)) {
1855
- return runInInjectionContext(this.injector, () => originalMethod.apply(this, args));
1856
- }
1857
- else {
1858
- throw new Error('Class that contains decorated method must extends WithInjectorDirective class');
1859
- }
1860
- };
1861
- // Return the modified descriptor
1862
- return descriptor;
1863
- }
1864
- const implementsWithInjector = (instance) => {
1865
- return 'injector' in instance && 'get' in instance.injector;
1866
- };
1867
-
1868
1860
  /**
1869
1861
  * This function contains a hack-y behavior.
1870
1862
  * If the handles are of the same type (source-source or target-target),
@@ -2193,8 +2185,9 @@ class ResizableComponent {
2193
2185
  return;
2194
2186
  const offset = calcOffset(event.movementX, event.movementY, this.zoom());
2195
2187
  const { x, y, width, height } = constrainRect(applyResize(this.resizeSide, this.model, offset), this.model, this.resizeSide, this.minWidth, this.minHeight);
2196
- this.model.setPoint({ x, y }, false);
2197
- this.model.size.set({ width, height });
2188
+ this.model.setPoint({ x, y });
2189
+ this.model.width.set(width);
2190
+ this.model.height.set(height);
2198
2191
  }
2199
2192
  endResize() {
2200
2193
  this.resizeSide = null;
@@ -2355,26 +2348,43 @@ class HandleModel {
2355
2348
  width: 10 + 2 * this.strokeWidth,
2356
2349
  height: 10 + 2 * this.strokeWidth,
2357
2350
  });
2358
- this.offset = computed(() => {
2351
+ this.pointAbsolute = computed(() => {
2352
+ return {
2353
+ x: this.parentNode.globalPoint().x + this.hostOffset().x + this.sizeOffset().x,
2354
+ y: this.parentNode.globalPoint().y + this.hostOffset().y + this.sizeOffset().y,
2355
+ };
2356
+ });
2357
+ this.state = signal('idle');
2358
+ this.updateHostSizeAndPosition$ = new Subject();
2359
+ this.hostSize = toSignal(this.updateHostSizeAndPosition$.pipe(map(() => this.getHostSize())), {
2360
+ initialValue: { width: 0, height: 0 },
2361
+ });
2362
+ this.hostPosition = toSignal(this.updateHostSizeAndPosition$.pipe(map(() => ({
2363
+ x: this.hostReference instanceof HTMLElement ? this.hostReference.offsetLeft : 0, // for now just 0 for group nodes
2364
+ y: this.hostReference instanceof HTMLElement ? this.hostReference.offsetTop : 0, // for now just 0 for group nodes
2365
+ }))), {
2366
+ initialValue: { x: 0, y: 0 },
2367
+ });
2368
+ this.hostOffset = computed(() => {
2359
2369
  switch (this.rawHandle.position) {
2360
2370
  case 'left':
2361
2371
  return {
2362
2372
  x: 0,
2363
- y: this.parentPosition().y + this.parentSize().height / 2,
2373
+ y: this.hostPosition().y + this.hostSize().height / 2,
2364
2374
  };
2365
2375
  case 'right':
2366
2376
  return {
2367
2377
  x: this.parentNode.size().width,
2368
- y: this.parentPosition().y + this.parentSize().height / 2,
2378
+ y: this.hostPosition().y + this.hostSize().height / 2,
2369
2379
  };
2370
2380
  case 'top':
2371
2381
  return {
2372
- x: this.parentPosition().x + this.parentSize().width / 2,
2382
+ x: this.hostPosition().x + this.hostSize().width / 2,
2373
2383
  y: 0,
2374
2384
  };
2375
2385
  case 'bottom':
2376
2386
  return {
2377
- x: this.parentPosition().x + this.parentSize().width / 2,
2387
+ x: this.hostPosition().x + this.hostSize().width / 2,
2378
2388
  y: this.parentNode.size().height,
2379
2389
  };
2380
2390
  }
@@ -2391,50 +2401,50 @@ class HandleModel {
2391
2401
  return { x: 0, y: this.size().height / 2 };
2392
2402
  }
2393
2403
  });
2394
- this.pointAbsolute = computed(() => {
2395
- return {
2396
- x: this.parentNode.globalPoint().x + this.offset().x + this.sizeOffset().x,
2397
- y: this.parentNode.globalPoint().y + this.offset().y + this.sizeOffset().y,
2398
- };
2399
- });
2400
- this.state = signal('idle');
2401
- this.updateParentSizeAndPosition$ = new Subject();
2402
- this.parentSize = toSignal(this.updateParentSizeAndPosition$.pipe(map(() => this.getParentSize())), {
2403
- initialValue: { width: 0, height: 0 },
2404
- });
2405
- this.parentPosition = toSignal(this.updateParentSizeAndPosition$.pipe(map(() => ({
2406
- x: this.parentReference instanceof HTMLElement ? this.parentReference.offsetLeft : 0, // for now just 0 for group nodes
2407
- y: this.parentReference instanceof HTMLElement ? this.parentReference.offsetTop : 0, // for now just 0 for group nodes
2408
- }))), {
2409
- initialValue: { x: 0, y: 0 },
2410
- });
2411
- this.parentReference = this.rawHandle.parentReference;
2404
+ this.hostReference = this.rawHandle.hostReference;
2412
2405
  this.template = this.rawHandle.template;
2413
2406
  this.templateContext = {
2414
2407
  $implicit: {
2415
- point: this.offset,
2408
+ point: this.hostOffset,
2416
2409
  state: this.state,
2417
2410
  node: this.parentNode.node,
2418
2411
  },
2419
2412
  };
2420
2413
  }
2421
- updateParent() {
2422
- this.updateParentSizeAndPosition$.next();
2414
+ updateHost() {
2415
+ this.updateHostSizeAndPosition$.next();
2423
2416
  }
2424
- getParentSize() {
2425
- if (this.parentReference instanceof HTMLElement) {
2417
+ getHostSize() {
2418
+ if (this.hostReference instanceof HTMLElement) {
2426
2419
  return {
2427
- width: this.parentReference.offsetWidth,
2428
- height: this.parentReference.offsetHeight,
2420
+ width: this.hostReference.offsetWidth,
2421
+ height: this.hostReference.offsetHeight,
2429
2422
  };
2430
2423
  }
2431
- else if (this.parentReference instanceof SVGGraphicsElement) {
2432
- return this.parentReference.getBBox();
2424
+ else if (this.hostReference instanceof SVGGraphicsElement) {
2425
+ return this.hostReference.getBBox();
2433
2426
  }
2434
2427
  return { width: 0, height: 0 };
2435
2428
  }
2436
2429
  }
2437
2430
 
2431
+ function InjectionContext(target, key, descriptor) {
2432
+ const originalMethod = descriptor.value;
2433
+ descriptor.value = function (...args) {
2434
+ if (implementsWithInjector(this)) {
2435
+ return runInInjectionContext(this.injector, () => originalMethod.apply(this, args));
2436
+ }
2437
+ else {
2438
+ throw new Error('Class that contains decorated method must extends WithInjectorDirective class');
2439
+ }
2440
+ };
2441
+ // Return the modified descriptor
2442
+ return descriptor;
2443
+ }
2444
+ const implementsWithInjector = (instance) => {
2445
+ return 'injector' in instance && 'get' in instance.injector;
2446
+ };
2447
+
2438
2448
  class HandleComponent {
2439
2449
  constructor() {
2440
2450
  this.injector = inject(Injector);
@@ -2462,11 +2472,11 @@ class HandleComponent {
2462
2472
  position: this.position(),
2463
2473
  type: this.type(),
2464
2474
  id: this.id(),
2465
- parentReference: this.element.parentElement,
2475
+ hostReference: this.element.parentElement,
2466
2476
  template: this.template(),
2467
2477
  }, node);
2468
2478
  this.handleService.createHandle(this.model);
2469
- requestAnimationFrame(() => this.model.updateParent());
2479
+ requestAnimationFrame(() => this.model.updateHost());
2470
2480
  this.destroyRef.onDestroy(() => this.handleService.destroyHandle(this.model));
2471
2481
  }
2472
2482
  }
@@ -2481,6 +2491,72 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
2481
2491
  args: [{ standalone: true, selector: 'handle', changeDetection: ChangeDetectionStrategy.OnPush, template: "" }]
2482
2492
  }], propDecorators: { ngOnInit: [] } });
2483
2493
 
2494
+ function resizable(elems, zone) {
2495
+ return new Observable((subscriber) => {
2496
+ const ro = new ResizeObserver((entries) => {
2497
+ zone.run(() => subscriber.next(entries));
2498
+ });
2499
+ elems.forEach((e) => ro.observe(e));
2500
+ return () => ro.disconnect();
2501
+ });
2502
+ }
2503
+
2504
+ class NodeHandlesControllerDirective {
2505
+ constructor() {
2506
+ this.nodeAccessor = inject(NodeAccessorService);
2507
+ this.zone = inject(NgZone);
2508
+ this.destroyRef = inject(DestroyRef);
2509
+ this.hostElementRef = inject(ElementRef);
2510
+ }
2511
+ ngOnInit() {
2512
+ const model = this.nodeAccessor.model();
2513
+ model.handles$
2514
+ .pipe(switchMap((handles) => resizable([...handles.map((h) => h.hostReference), this.hostElementRef.nativeElement], this.zone).pipe(map(() => handles))), tap((handles) => {
2515
+ // TODO (performance) inspect how to avoid calls of this when flow initially rendered
2516
+ handles.forEach((h) => h.updateHost());
2517
+ }), takeUntilDestroyed(this.destroyRef))
2518
+ .subscribe();
2519
+ }
2520
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeHandlesControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2521
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: NodeHandlesControllerDirective, isStandalone: true, selector: "[nodeHandlesController]", ngImport: i0 }); }
2522
+ }
2523
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeHandlesControllerDirective, decorators: [{
2524
+ type: Directive,
2525
+ args: [{
2526
+ selector: '[nodeHandlesController]',
2527
+ standalone: true,
2528
+ }]
2529
+ }] });
2530
+
2531
+ class NodeResizeControllerDirective {
2532
+ constructor() {
2533
+ this.nodeAccessor = inject(NodeAccessorService);
2534
+ this.zone = inject(NgZone);
2535
+ this.destroyRef = inject(DestroyRef);
2536
+ this.hostElementRef = inject(ElementRef);
2537
+ }
2538
+ ngOnInit() {
2539
+ const model = this.nodeAccessor.model();
2540
+ resizable([this.hostElementRef.nativeElement], this.zone)
2541
+ .pipe(startWith(null), filter(() => !model.resizing()), tap(() => {
2542
+ const width = this.hostElementRef.nativeElement.clientWidth;
2543
+ const height = this.hostElementRef.nativeElement.clientHeight;
2544
+ model.width.set(width);
2545
+ model.height.set(height);
2546
+ }), takeUntilDestroyed(this.destroyRef))
2547
+ .subscribe();
2548
+ }
2549
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeResizeControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2550
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: NodeResizeControllerDirective, isStandalone: true, selector: "[nodeResizeController]", ngImport: i0 }); }
2551
+ }
2552
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeResizeControllerDirective, decorators: [{
2553
+ type: Directive,
2554
+ args: [{
2555
+ selector: '[nodeResizeController]',
2556
+ standalone: true,
2557
+ }]
2558
+ }] });
2559
+
2484
2560
  class NodeComponent {
2485
2561
  constructor() {
2486
2562
  this.injector = inject(Injector);
@@ -2493,50 +2569,26 @@ class NodeComponent {
2493
2569
  this.hostRef = inject(ElementRef);
2494
2570
  this.nodeAccessor = inject(NodeAccessorService);
2495
2571
  this.overlaysService = inject(OverlaysService);
2496
- this.zone = inject(NgZone);
2497
2572
  // TODO remove dependency from this directive
2498
2573
  this.connectionController = inject(ConnectionControllerDirective, { optional: true });
2499
- this.nodeModel = input.required();
2574
+ this.model = input.required();
2500
2575
  this.nodeTemplate = input();
2501
2576
  this.groupNodeTemplate = input();
2502
- this.htmlWrapperRef = viewChild.required('htmlWrapper');
2503
2577
  this.showMagnet = computed(() => this.flowStatusService.status().state === 'connection-start' ||
2504
2578
  this.flowStatusService.status().state === 'connection-validation');
2505
- this.styleWidth = computed(() => `${this.nodeModel().size().width}px`);
2506
- this.styleHeight = computed(() => `${this.nodeModel().size().height}px`);
2507
- this.toolbar = computed(() => this.overlaysService.nodeToolbars().get(this.nodeModel()));
2579
+ this.toolbar = computed(() => this.overlaysService.nodeToolbars().get(this.model()));
2508
2580
  }
2509
2581
  ngOnInit() {
2510
- this.nodeAccessor.model.set(this.nodeModel());
2511
- this.handleService.node.set(this.nodeModel());
2582
+ this.nodeAccessor.model.set(this.model());
2583
+ this.handleService.node.set(this.model());
2512
2584
  effect(() => {
2513
- if (this.nodeModel().draggable()) {
2514
- this.draggableService.enable(this.hostRef.nativeElement, this.nodeModel());
2585
+ if (this.model().draggable()) {
2586
+ this.draggableService.enable(this.hostRef.nativeElement, this.model());
2515
2587
  }
2516
2588
  else {
2517
2589
  this.draggableService.disable(this.hostRef.nativeElement);
2518
2590
  }
2519
- });
2520
- this.nodeModel()
2521
- .handles$.pipe(switchMap((handles) => resizable(handles.map((h) => h.parentReference), this.zone).pipe(map(() => handles))), tap((handles) => {
2522
- // TODO (performance) inspect how to avoid calls of this when flow initially rendered
2523
- handles.forEach((h) => h.updateParent());
2524
- }), takeUntilDestroyed())
2525
- .subscribe();
2526
- }
2527
- ngAfterViewInit() {
2528
- this.nodeModel().linkDefaultNodeSizeWithModelSize();
2529
- if (this.nodeModel().node.type === 'html-template' || this.nodeModel().isComponentType) {
2530
- resizable([this.htmlWrapperRef().nativeElement], this.zone)
2531
- .pipe(startWith(null), tap(() => this.nodeModel()
2532
- .handles()
2533
- .forEach((h) => h.updateParent())), filter(() => !this.nodeModel().resizing()), tap(() => {
2534
- const width = this.htmlWrapperRef().nativeElement.clientWidth;
2535
- const height = this.htmlWrapperRef().nativeElement.clientHeight;
2536
- this.nodeModel().size.set({ width, height });
2537
- }), takeUntilDestroyed())
2538
- .subscribe();
2539
- }
2591
+ }, { injector: this.injector });
2540
2592
  }
2541
2593
  ngOnDestroy() {
2542
2594
  this.draggableService.destroy(this.hostRef.nativeElement);
@@ -2556,22 +2608,16 @@ class NodeComponent {
2556
2608
  this.connectionController?.endConnection();
2557
2609
  }
2558
2610
  pullNode() {
2559
- this.nodeRenderingService.pullNode(this.nodeModel());
2611
+ this.nodeRenderingService.pullNode(this.model());
2560
2612
  }
2561
2613
  selectNode() {
2562
2614
  if (this.flowSettingsService.entitiesSelectable()) {
2563
- this.selectionService.select(this.nodeModel());
2615
+ this.selectionService.select(this.model());
2564
2616
  }
2565
2617
  }
2566
2618
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2567
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: NodeComponent, isStandalone: true, selector: "g[node]", inputs: { nodeModel: { classPropertyName: "nodeModel", publicName: "nodeModel", isSignal: true, isRequired: true, transformFunction: null }, nodeTemplate: { classPropertyName: "nodeTemplate", publicName: "nodeTemplate", isSignal: true, isRequired: false, transformFunction: null }, groupNodeTemplate: { classPropertyName: "groupNodeTemplate", publicName: "groupNodeTemplate", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "vflow-node" }, providers: [HandleService, NodeAccessorService], viewQueries: [{ propertyName: "htmlWrapperRef", first: true, predicate: ["htmlWrapper"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Default node -->\n@if (nodeModel().node.type === 'default') {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"nodeModel().size().width\"\n [attr.height]=\"nodeModel().size().height\"\n (pointerStart)=\"pullNode(); selectNode()\">\n <default-node\n #htmlWrapper\n [selected]=\"nodeModel().selected()\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n [style.max-width]=\"styleWidth()\"\n [style.max-height]=\"styleHeight()\">\n <div [outerHTML]=\"nodeModel().text()\"></div>\n\n <handle type=\"source\" position=\"right\" />\n <handle type=\"target\" position=\"left\" />\n </default-node>\n </svg:foreignObject>\n}\n\n<!-- Template node -->\n@if (nodeModel().node.type === 'html-template' && nodeTemplate()) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"nodeModel().size().width\"\n [attr.height]=\"nodeModel().size().height\"\n (pointerStart)=\"pullNode()\">\n <div #htmlWrapper class=\"wrapper\" [style.width]=\"styleWidth()\" [style.height]=\"styleHeight()\">\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{\n $implicit: { node: nodeModel().node, selected: nodeModel().selected },\n }\"\n [ngTemplateOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- Component node -->\n@if (nodeModel().isComponentType) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"nodeModel().size().width\"\n [attr.height]=\"nodeModel().size().height\"\n (pointerStart)=\"pullNode()\">\n <div #htmlWrapper class=\"wrapper\" [style.width]=\"styleWidth()\" [style.height]=\"styleHeight()\">\n <ng-container\n [ngComponentOutlet]=\"$any(nodeModel().node.type)\"\n [ngComponentOutletInputs]=\"nodeModel().componentTypeInputs\"\n [ngComponentOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- Default group node -->\n@if (nodeModel().node.type === 'default-group') {\n <svg:rect\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [resizable]=\"nodeModel().resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"nodeModel().color()\"\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 (pointerStart)=\"pullNode(); selectNode()\" />\n}\n\n<!-- Template group node -->\n@if (nodeModel().node.type === 'template-group' && groupNodeTemplate()) {\n <svg:g class=\"selectable\" (pointerStart)=\"pullNode()\">\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{\n $implicit: {\n node: nodeModel().node,\n selected: nodeModel().selected,\n width: nodeModel().width,\n height: nodeModel().height,\n },\n }\"\n [ngTemplateOutletInjector]=\"injector\" />\n </svg:g>\n}\n\n<!-- Resizer -->\n@if (nodeModel().resizerTemplate(); as template) {\n @if (nodeModel().resizable()) {\n <ng-template [ngTemplateOutlet]=\"template\" />\n }\n}\n\n<!-- Handles -->\n@for (handle of nodeModel().handles(); track handle) {\n @if (!handle.template) {\n <svg:circle\n class=\"default-handle\"\n r=\"5\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection()\" />\n }\n\n @if (handle.template) {\n <svg:g\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection()\">\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n }\n\n @if (showMagnet()) {\n <svg:circle\n class=\"magnet\"\n [attr.r]=\"nodeModel().magnetRadius\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n (pointerEnd)=\"endConnection(); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\" />\n }\n}\n\n<!-- Toolbar -->\n@if (toolbar(); as toolbar) {\n <svg:foreignObject\n [attr.width]=\"toolbar.size().width\"\n [attr.height]=\"toolbar.size().height\"\n [attr.transform]=\"toolbar.transform()\">\n <ng-container [ngTemplateOutlet]=\"toolbar.template()\" />\n </svg:foreignObject>\n}\n", styles: [".magnet{opacity:0}.wrapper{display:table-cell}.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: PointerDirective, selector: "[pointerStart], [pointerEnd], [pointerOver], [pointerOut]", outputs: ["pointerOver", "pointerOut", "pointerStart", "pointerEnd"] }, { kind: "component", type: DefaultNodeComponent, selector: "default-node", inputs: ["selected"] }, { kind: "component", type: HandleComponent, selector: "handle", inputs: ["position", "type", "id", "template"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "component", type: ResizableComponent, selector: "[resizable]", inputs: ["resizable", "resizerColor", "gap"] }, { kind: "directive", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: ["handleSizeController"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2619
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: NodeComponent, isStandalone: true, selector: "g[node]", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, nodeTemplate: { classPropertyName: "nodeTemplate", publicName: "nodeTemplate", isSignal: true, isRequired: false, transformFunction: null }, groupNodeTemplate: { classPropertyName: "groupNodeTemplate", publicName: "groupNodeTemplate", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "vflow-node" }, providers: [HandleService, NodeAccessorService], ngImport: i0, template: "<!-- Default node -->\n@if (model().node.type === 'default') {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().size().width\"\n [attr.height]=\"model().size().height\"\n (pointerStart)=\"pullNode(); selectNode()\">\n <default-node\n nodeHandlesController\n [selected]=\"model().selected()\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\"\n [style.max-width]=\"model().styleWidth()\"\n [style.max-height]=\"model().styleHeight()\">\n <div [outerHTML]=\"model().text()\"></div>\n\n <handle type=\"source\" position=\"right\" />\n <handle type=\"target\" position=\"left\" />\n </default-node>\n </svg:foreignObject>\n}\n\n<!-- Template node -->\n@if (model().node.type === 'html-template' && nodeTemplate()) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().size().width\"\n [attr.height]=\"model().size().height\"\n (pointerStart)=\"pullNode()\">\n <div\n nodeHandlesController\n nodeResizeController\n class=\"wrapper\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\">\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{\n $implicit: { node: model().node, selected: model().selected },\n }\"\n [ngTemplateOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- Component node -->\n@if (model().isComponentType) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().size().width\"\n [attr.height]=\"model().size().height\"\n (pointerStart)=\"pullNode()\">\n <div\n nodeHandlesController\n nodeResizeController\n class=\"wrapper\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\">\n <ng-container\n [ngComponentOutlet]=\"$any(model().node.type)\"\n [ngComponentOutletInputs]=\"model().componentTypeInputs\"\n [ngComponentOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- Default group node -->\n@if (model().node.type === 'default-group') {\n <svg:rect\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [resizable]=\"model().resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"model().color()\"\n [class.default-group-node_selected]=\"model().selected()\"\n [attr.width]=\"model().size().width\"\n [attr.height]=\"model().size().height\"\n [style.stroke]=\"model().color()\"\n [style.fill]=\"model().color()\"\n (pointerStart)=\"pullNode(); selectNode()\" />\n}\n\n<!-- Template group node -->\n@if (model().node.type === 'template-group' && groupNodeTemplate()) {\n <svg:g class=\"selectable\" nodeHandlesController (pointerStart)=\"pullNode()\">\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{\n $implicit: {\n node: model().node,\n selected: model().selected,\n width: model().width,\n height: model().height,\n },\n }\"\n [ngTemplateOutletInjector]=\"injector\" />\n </svg:g>\n}\n\n<!-- Resizer -->\n@if (model().resizerTemplate(); as template) {\n @if (model().resizable()) {\n <ng-template [ngTemplateOutlet]=\"template\" />\n }\n}\n\n<!-- Handles -->\n@for (handle of model().handles(); track handle) {\n @if (!handle.template) {\n <svg:circle\n class=\"default-handle\"\n r=\"5\"\n [attr.cx]=\"handle.hostOffset().x\"\n [attr.cy]=\"handle.hostOffset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection()\" />\n }\n\n @if (handle.template) {\n <svg:g\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection()\">\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n }\n\n @if (showMagnet()) {\n <svg:circle\n class=\"magnet\"\n [attr.r]=\"model().magnetRadius\"\n [attr.cx]=\"handle.hostOffset().x\"\n [attr.cy]=\"handle.hostOffset().y\"\n (pointerEnd)=\"endConnection(); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\" />\n }\n}\n\n<!-- Toolbar -->\n@if (toolbar(); as toolbar) {\n <svg:foreignObject\n [attr.width]=\"toolbar.size().width\"\n [attr.height]=\"toolbar.size().height\"\n [attr.transform]=\"toolbar.transform()\">\n <ng-container [ngTemplateOutlet]=\"toolbar.template()\" />\n </svg:foreignObject>\n}\n", styles: [".magnet{opacity:0}.wrapper{display:table-cell}.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: PointerDirective, selector: "[pointerStart], [pointerEnd], [pointerOver], [pointerOut]", outputs: ["pointerOver", "pointerOut", "pointerStart", "pointerEnd"] }, { kind: "component", type: DefaultNodeComponent, selector: "default-node", inputs: ["selected"] }, { kind: "component", type: HandleComponent, selector: "handle", inputs: ["position", "type", "id", "template"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "component", type: ResizableComponent, selector: "[resizable]", inputs: ["resizable", "resizerColor", "gap"] }, { kind: "directive", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: ["handleSizeController"] }, { kind: "directive", type: NodeHandlesControllerDirective, selector: "[nodeHandlesController]" }, { kind: "directive", type: NodeResizeControllerDirective, selector: "[nodeResizeController]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2568
2620
  }
2569
- __decorate([
2570
- InjectionContext
2571
- ], NodeComponent.prototype, "ngOnInit", null);
2572
- __decorate([
2573
- InjectionContext
2574
- ], NodeComponent.prototype, "ngAfterViewInit", null);
2575
2621
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeComponent, decorators: [{
2576
2622
  type: Component,
2577
2623
  args: [{ standalone: true, selector: 'g[node]', changeDetection: ChangeDetectionStrategy.OnPush, providers: [HandleService, NodeAccessorService], host: {
@@ -2584,8 +2630,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
2584
2630
  NgComponentOutlet,
2585
2631
  ResizableComponent,
2586
2632
  HandleSizeControllerDirective,
2587
- ], template: "<!-- Default node -->\n@if (nodeModel().node.type === 'default') {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"nodeModel().size().width\"\n [attr.height]=\"nodeModel().size().height\"\n (pointerStart)=\"pullNode(); selectNode()\">\n <default-node\n #htmlWrapper\n [selected]=\"nodeModel().selected()\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n [style.max-width]=\"styleWidth()\"\n [style.max-height]=\"styleHeight()\">\n <div [outerHTML]=\"nodeModel().text()\"></div>\n\n <handle type=\"source\" position=\"right\" />\n <handle type=\"target\" position=\"left\" />\n </default-node>\n </svg:foreignObject>\n}\n\n<!-- Template node -->\n@if (nodeModel().node.type === 'html-template' && nodeTemplate()) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"nodeModel().size().width\"\n [attr.height]=\"nodeModel().size().height\"\n (pointerStart)=\"pullNode()\">\n <div #htmlWrapper class=\"wrapper\" [style.width]=\"styleWidth()\" [style.height]=\"styleHeight()\">\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{\n $implicit: { node: nodeModel().node, selected: nodeModel().selected },\n }\"\n [ngTemplateOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- Component node -->\n@if (nodeModel().isComponentType) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"nodeModel().size().width\"\n [attr.height]=\"nodeModel().size().height\"\n (pointerStart)=\"pullNode()\">\n <div #htmlWrapper class=\"wrapper\" [style.width]=\"styleWidth()\" [style.height]=\"styleHeight()\">\n <ng-container\n [ngComponentOutlet]=\"$any(nodeModel().node.type)\"\n [ngComponentOutletInputs]=\"nodeModel().componentTypeInputs\"\n [ngComponentOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- Default group node -->\n@if (nodeModel().node.type === 'default-group') {\n <svg:rect\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [resizable]=\"nodeModel().resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"nodeModel().color()\"\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 (pointerStart)=\"pullNode(); selectNode()\" />\n}\n\n<!-- Template group node -->\n@if (nodeModel().node.type === 'template-group' && groupNodeTemplate()) {\n <svg:g class=\"selectable\" (pointerStart)=\"pullNode()\">\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{\n $implicit: {\n node: nodeModel().node,\n selected: nodeModel().selected,\n width: nodeModel().width,\n height: nodeModel().height,\n },\n }\"\n [ngTemplateOutletInjector]=\"injector\" />\n </svg:g>\n}\n\n<!-- Resizer -->\n@if (nodeModel().resizerTemplate(); as template) {\n @if (nodeModel().resizable()) {\n <ng-template [ngTemplateOutlet]=\"template\" />\n }\n}\n\n<!-- Handles -->\n@for (handle of nodeModel().handles(); track handle) {\n @if (!handle.template) {\n <svg:circle\n class=\"default-handle\"\n r=\"5\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection()\" />\n }\n\n @if (handle.template) {\n <svg:g\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection()\">\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n }\n\n @if (showMagnet()) {\n <svg:circle\n class=\"magnet\"\n [attr.r]=\"nodeModel().magnetRadius\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n (pointerEnd)=\"endConnection(); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\" />\n }\n}\n\n<!-- Toolbar -->\n@if (toolbar(); as toolbar) {\n <svg:foreignObject\n [attr.width]=\"toolbar.size().width\"\n [attr.height]=\"toolbar.size().height\"\n [attr.transform]=\"toolbar.transform()\">\n <ng-container [ngTemplateOutlet]=\"toolbar.template()\" />\n </svg:foreignObject>\n}\n", styles: [".magnet{opacity:0}.wrapper{display:table-cell}.default-group-node{stroke-width:1.5px;fill-opacity:.05}.default-group-node_selected{stroke-width:2px}.default-handle{stroke:#fff;fill:#1b262c}\n"] }]
2588
- }], propDecorators: { ngOnInit: [], ngAfterViewInit: [] } });
2633
+ NodeHandlesControllerDirective,
2634
+ NodeResizeControllerDirective,
2635
+ ], template: "<!-- Default node -->\n@if (model().node.type === 'default') {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().size().width\"\n [attr.height]=\"model().size().height\"\n (pointerStart)=\"pullNode(); selectNode()\">\n <default-node\n nodeHandlesController\n [selected]=\"model().selected()\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\"\n [style.max-width]=\"model().styleWidth()\"\n [style.max-height]=\"model().styleHeight()\">\n <div [outerHTML]=\"model().text()\"></div>\n\n <handle type=\"source\" position=\"right\" />\n <handle type=\"target\" position=\"left\" />\n </default-node>\n </svg:foreignObject>\n}\n\n<!-- Template node -->\n@if (model().node.type === 'html-template' && nodeTemplate()) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().size().width\"\n [attr.height]=\"model().size().height\"\n (pointerStart)=\"pullNode()\">\n <div\n nodeHandlesController\n nodeResizeController\n class=\"wrapper\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\">\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{\n $implicit: { node: model().node, selected: model().selected },\n }\"\n [ngTemplateOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- Component node -->\n@if (model().isComponentType) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().size().width\"\n [attr.height]=\"model().size().height\"\n (pointerStart)=\"pullNode()\">\n <div\n nodeHandlesController\n nodeResizeController\n class=\"wrapper\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\">\n <ng-container\n [ngComponentOutlet]=\"$any(model().node.type)\"\n [ngComponentOutletInputs]=\"model().componentTypeInputs\"\n [ngComponentOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- Default group node -->\n@if (model().node.type === 'default-group') {\n <svg:rect\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [resizable]=\"model().resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"model().color()\"\n [class.default-group-node_selected]=\"model().selected()\"\n [attr.width]=\"model().size().width\"\n [attr.height]=\"model().size().height\"\n [style.stroke]=\"model().color()\"\n [style.fill]=\"model().color()\"\n (pointerStart)=\"pullNode(); selectNode()\" />\n}\n\n<!-- Template group node -->\n@if (model().node.type === 'template-group' && groupNodeTemplate()) {\n <svg:g class=\"selectable\" nodeHandlesController (pointerStart)=\"pullNode()\">\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{\n $implicit: {\n node: model().node,\n selected: model().selected,\n width: model().width,\n height: model().height,\n },\n }\"\n [ngTemplateOutletInjector]=\"injector\" />\n </svg:g>\n}\n\n<!-- Resizer -->\n@if (model().resizerTemplate(); as template) {\n @if (model().resizable()) {\n <ng-template [ngTemplateOutlet]=\"template\" />\n }\n}\n\n<!-- Handles -->\n@for (handle of model().handles(); track handle) {\n @if (!handle.template) {\n <svg:circle\n class=\"default-handle\"\n r=\"5\"\n [attr.cx]=\"handle.hostOffset().x\"\n [attr.cy]=\"handle.hostOffset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection()\" />\n }\n\n @if (handle.template) {\n <svg:g\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection()\">\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n }\n\n @if (showMagnet()) {\n <svg:circle\n class=\"magnet\"\n [attr.r]=\"model().magnetRadius\"\n [attr.cx]=\"handle.hostOffset().x\"\n [attr.cy]=\"handle.hostOffset().y\"\n (pointerEnd)=\"endConnection(); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\" />\n }\n}\n\n<!-- Toolbar -->\n@if (toolbar(); as toolbar) {\n <svg:foreignObject\n [attr.width]=\"toolbar.size().width\"\n [attr.height]=\"toolbar.size().height\"\n [attr.transform]=\"toolbar.transform()\">\n <ng-container [ngTemplateOutlet]=\"toolbar.template()\" />\n </svg:foreignObject>\n}\n", styles: [".magnet{opacity:0}.wrapper{display:table-cell}.default-group-node{stroke-width:1.5px;fill-opacity:.05}.default-group-node_selected{stroke-width:2px}.default-handle{stroke:#fff;fill:#1b262c}\n"] }]
2636
+ }] });
2589
2637
 
2590
2638
  class ConnectionComponent {
2591
2639
  constructor() {
@@ -3179,7 +3227,7 @@ class VflowComponent {
3179
3227
  ComponentEventBusService,
3180
3228
  KeyboardService,
3181
3229
  OverlaysService,
3182
- ], queries: [{ propertyName: "nodeTemplateDirective", first: true, predicate: NodeHtmlTemplateDirective, descendants: true, isSignal: true }, { propertyName: "groupNodeTemplateDirective", first: true, predicate: GroupNodeTemplateDirective, descendants: true, isSignal: true }, { propertyName: "edgeTemplateDirective", first: true, predicate: EdgeTemplateDirective, descendants: true, isSignal: true }, { propertyName: "edgeLabelHtmlDirective", first: true, predicate: EdgeLabelHtmlTemplateDirective, descendants: true, isSignal: true }, { propertyName: "connectionTemplateDirective", first: true, predicate: ConnectionTemplateDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "mapContext", first: true, predicate: MapContextDirective, descendants: true, isSignal: true }, { propertyName: "spacePointContext", first: true, predicate: SpacePointContextDirective, descendants: true, isSignal: true }], hostDirectives: [{ directive: ChangesControllerDirective, outputs: ["onNodesChange", "onNodesChange", "onNodesChange.position", "onNodesChange.position", "onNodesChange.position.single", "onNodesChange.position.single", "onNodesChange.position.many", "onNodesChange.position.many", "onNodesChange.size", "onNodesChange.size", "onNodesChange.size.single", "onNodesChange.size.single", "onNodesChange.size.many", "onNodesChange.size.many", "onNodesChange.add", "onNodesChange.add", "onNodesChange.add.single", "onNodesChange.add.single", "onNodesChange.add.many", "onNodesChange.add.many", "onNodesChange.remove", "onNodesChange.remove", "onNodesChange.remove.single", "onNodesChange.remove.single", "onNodesChange.remove.many", "onNodesChange.remove.many", "onNodesChange.select", "onNodesChange.select", "onNodesChange.select.single", "onNodesChange.select.single", "onNodesChange.select.many", "onNodesChange.select.many", "onEdgesChange", "onEdgesChange", "onEdgesChange.detached", "onEdgesChange.detached", "onEdgesChange.detached.single", "onEdgesChange.detached.single", "onEdgesChange.detached.many", "onEdgesChange.detached.many", "onEdgesChange.add", "onEdgesChange.add", "onEdgesChange.add.single", "onEdgesChange.add.single", "onEdgesChange.add.many", "onEdgesChange.add.many", "onEdgesChange.remove", "onEdgesChange.remove", "onEdgesChange.remove.single", "onEdgesChange.remove.single", "onEdgesChange.remove.many", "onEdgesChange.remove.many", "onEdgesChange.select", "onEdgesChange.select", "onEdgesChange.select.single", "onEdgesChange.select.single", "onEdgesChange.select.many", "onEdgesChange.select.many"] }], ngImport: i0, template: "<svg:svg #flow rootSvgRef rootSvgContext rootPointer flowSizeController class=\"root-svg\">\n <defs flowDefs [markers]=\"markers()\" />\n\n <g background />\n\n <svg:g mapContext spacePointContext>\n <!-- Connection -->\n <svg:g connection [model]=\"connection\" [template]=\"connectionTemplateDirective()?.templateRef\" />\n\n @if (optimization().detachedGroupsLayer) {\n <!-- Groups -->\n @for (model of groups(); track trackNodes($index, model)) {\n <svg:g\n node\n [nodeModel]=\"model\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective()?.templateRef\"\n [attr.transform]=\"model.pointTransform()\" />\n }\n <!-- Edges -->\n @for (model of edgeModels(); track trackEdges($index, model)) {\n <svg:g\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective()?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective()?.templateRef\" />\n }\n <!-- Nodes -->\n @for (model of nonGroups(); track trackNodes($index, model)) {\n <svg:g\n node\n [nodeModel]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective()?.templateRef\"\n [attr.transform]=\"model.pointTransform()\" />\n }\n }\n\n @if (!optimization().detachedGroupsLayer) {\n <!-- Edges -->\n @for (model of edgeModels(); track trackEdges($index, model)) {\n <svg:g\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective()?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective()?.templateRef\" />\n }\n <!-- Nodes -->\n @for (model of nodeModels(); track trackNodes($index, model)) {\n <svg:g\n node\n [nodeModel]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective()?.templateRef\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective()?.templateRef\"\n [attr.transform]=\"model.pointTransform()\" />\n }\n }\n </svg:g>\n\n <!-- Minimap -->\n @if (minimap(); as minimap) {\n <ng-container [ngTemplateOutlet]=\"minimap.template()\" />\n }\n</svg:svg>\n", styles: [":host{display:block;width:100%;height:100%;-webkit-user-select:none;user-select:none}:host ::ng-deep *{box-sizing:border-box}\n"], dependencies: [{ kind: "directive", type: RootSvgReferenceDirective, selector: "svg[rootSvgRef]" }, { kind: "directive", type: RootSvgContextDirective, selector: "svg[rootSvgContext]" }, { kind: "directive", type: RootPointerDirective, selector: "svg[rootPointer]" }, { kind: "directive", type: FlowSizeControllerDirective, selector: "svg[flowSizeController]" }, { kind: "component", type: DefsComponent, selector: "defs[flowDefs]", inputs: ["markers"] }, { kind: "component", type: BackgroundComponent, selector: "g[background]" }, { kind: "directive", type: MapContextDirective, selector: "g[mapContext]" }, { kind: "directive", type: SpacePointContextDirective, selector: "g[spacePointContext]" }, { kind: "component", type: ConnectionComponent, selector: "g[connection]", inputs: ["model", "template"] }, { kind: "component", type: NodeComponent, selector: "g[node]", inputs: ["nodeModel", "nodeTemplate", "groupNodeTemplate"] }, { kind: "component", type: EdgeComponent, selector: "g[edge]", inputs: ["model", "edgeTemplate", "edgeLabelHtmlTemplate"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3230
+ ], queries: [{ propertyName: "nodeTemplateDirective", first: true, predicate: NodeHtmlTemplateDirective, descendants: true, isSignal: true }, { propertyName: "groupNodeTemplateDirective", first: true, predicate: GroupNodeTemplateDirective, descendants: true, isSignal: true }, { propertyName: "edgeTemplateDirective", first: true, predicate: EdgeTemplateDirective, descendants: true, isSignal: true }, { propertyName: "edgeLabelHtmlDirective", first: true, predicate: EdgeLabelHtmlTemplateDirective, descendants: true, isSignal: true }, { propertyName: "connectionTemplateDirective", first: true, predicate: ConnectionTemplateDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "mapContext", first: true, predicate: MapContextDirective, descendants: true, isSignal: true }, { propertyName: "spacePointContext", first: true, predicate: SpacePointContextDirective, descendants: true, isSignal: true }], hostDirectives: [{ directive: ChangesControllerDirective, outputs: ["onNodesChange", "onNodesChange", "onNodesChange.position", "onNodesChange.position", "onNodesChange.position.single", "onNodesChange.position.single", "onNodesChange.position.many", "onNodesChange.position.many", "onNodesChange.size", "onNodesChange.size", "onNodesChange.size.single", "onNodesChange.size.single", "onNodesChange.size.many", "onNodesChange.size.many", "onNodesChange.add", "onNodesChange.add", "onNodesChange.add.single", "onNodesChange.add.single", "onNodesChange.add.many", "onNodesChange.add.many", "onNodesChange.remove", "onNodesChange.remove", "onNodesChange.remove.single", "onNodesChange.remove.single", "onNodesChange.remove.many", "onNodesChange.remove.many", "onNodesChange.select", "onNodesChange.select", "onNodesChange.select.single", "onNodesChange.select.single", "onNodesChange.select.many", "onNodesChange.select.many", "onEdgesChange", "onEdgesChange", "onEdgesChange.detached", "onEdgesChange.detached", "onEdgesChange.detached.single", "onEdgesChange.detached.single", "onEdgesChange.detached.many", "onEdgesChange.detached.many", "onEdgesChange.add", "onEdgesChange.add", "onEdgesChange.add.single", "onEdgesChange.add.single", "onEdgesChange.add.many", "onEdgesChange.add.many", "onEdgesChange.remove", "onEdgesChange.remove", "onEdgesChange.remove.single", "onEdgesChange.remove.single", "onEdgesChange.remove.many", "onEdgesChange.remove.many", "onEdgesChange.select", "onEdgesChange.select", "onEdgesChange.select.single", "onEdgesChange.select.single", "onEdgesChange.select.many", "onEdgesChange.select.many"] }], ngImport: i0, template: "<svg:svg #flow rootSvgRef rootSvgContext rootPointer flowSizeController class=\"root-svg\">\n <defs flowDefs [markers]=\"markers()\" />\n\n <g background />\n\n <svg:g mapContext spacePointContext>\n <!-- Connection -->\n <svg:g connection [model]=\"connection\" [template]=\"connectionTemplateDirective()?.templateRef\" />\n\n @if (optimization().detachedGroupsLayer) {\n <!-- Groups -->\n @for (model of groups(); track trackNodes($index, model)) {\n <svg:g\n node\n [model]=\"model\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective()?.templateRef\"\n [attr.transform]=\"model.pointTransform()\" />\n }\n <!-- Edges -->\n @for (model of edgeModels(); track trackEdges($index, model)) {\n <svg:g\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective()?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective()?.templateRef\" />\n }\n <!-- Nodes -->\n @for (model of nonGroups(); track trackNodes($index, model)) {\n <svg:g\n node\n [model]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective()?.templateRef\"\n [attr.transform]=\"model.pointTransform()\" />\n }\n }\n\n @if (!optimization().detachedGroupsLayer) {\n <!-- Edges -->\n @for (model of edgeModels(); track trackEdges($index, model)) {\n <svg:g\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective()?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective()?.templateRef\" />\n }\n <!-- Nodes -->\n @for (model of nodeModels(); track trackNodes($index, model)) {\n <svg:g\n node\n [model]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective()?.templateRef\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective()?.templateRef\"\n [attr.transform]=\"model.pointTransform()\" />\n }\n }\n </svg:g>\n\n <!-- Minimap -->\n @if (minimap(); as minimap) {\n <ng-container [ngTemplateOutlet]=\"minimap.template()\" />\n }\n</svg:svg>\n", styles: [":host{display:block;width:100%;height:100%;-webkit-user-select:none;user-select:none}:host ::ng-deep *{box-sizing:border-box}\n"], dependencies: [{ kind: "directive", type: RootSvgReferenceDirective, selector: "svg[rootSvgRef]" }, { kind: "directive", type: RootSvgContextDirective, selector: "svg[rootSvgContext]" }, { kind: "directive", type: RootPointerDirective, selector: "svg[rootPointer]" }, { kind: "directive", type: FlowSizeControllerDirective, selector: "svg[flowSizeController]" }, { kind: "component", type: DefsComponent, selector: "defs[flowDefs]", inputs: ["markers"] }, { kind: "component", type: BackgroundComponent, selector: "g[background]" }, { kind: "directive", type: MapContextDirective, selector: "g[mapContext]" }, { kind: "directive", type: SpacePointContextDirective, selector: "g[spacePointContext]" }, { kind: "component", type: ConnectionComponent, selector: "g[connection]", inputs: ["model", "template"] }, { kind: "component", type: NodeComponent, selector: "g[node]", inputs: ["model", "nodeTemplate", "groupNodeTemplate"] }, { kind: "component", type: EdgeComponent, selector: "g[edge]", inputs: ["model", "edgeTemplate", "edgeLabelHtmlTemplate"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3183
3231
  }
3184
3232
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: VflowComponent, decorators: [{
3185
3233
  type: Component,
@@ -3209,7 +3257,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3209
3257
  NodeComponent,
3210
3258
  EdgeComponent,
3211
3259
  NgTemplateOutlet,
3212
- ], template: "<svg:svg #flow rootSvgRef rootSvgContext rootPointer flowSizeController class=\"root-svg\">\n <defs flowDefs [markers]=\"markers()\" />\n\n <g background />\n\n <svg:g mapContext spacePointContext>\n <!-- Connection -->\n <svg:g connection [model]=\"connection\" [template]=\"connectionTemplateDirective()?.templateRef\" />\n\n @if (optimization().detachedGroupsLayer) {\n <!-- Groups -->\n @for (model of groups(); track trackNodes($index, model)) {\n <svg:g\n node\n [nodeModel]=\"model\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective()?.templateRef\"\n [attr.transform]=\"model.pointTransform()\" />\n }\n <!-- Edges -->\n @for (model of edgeModels(); track trackEdges($index, model)) {\n <svg:g\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective()?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective()?.templateRef\" />\n }\n <!-- Nodes -->\n @for (model of nonGroups(); track trackNodes($index, model)) {\n <svg:g\n node\n [nodeModel]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective()?.templateRef\"\n [attr.transform]=\"model.pointTransform()\" />\n }\n }\n\n @if (!optimization().detachedGroupsLayer) {\n <!-- Edges -->\n @for (model of edgeModels(); track trackEdges($index, model)) {\n <svg:g\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective()?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective()?.templateRef\" />\n }\n <!-- Nodes -->\n @for (model of nodeModels(); track trackNodes($index, model)) {\n <svg:g\n node\n [nodeModel]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective()?.templateRef\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective()?.templateRef\"\n [attr.transform]=\"model.pointTransform()\" />\n }\n }\n </svg:g>\n\n <!-- Minimap -->\n @if (minimap(); as minimap) {\n <ng-container [ngTemplateOutlet]=\"minimap.template()\" />\n }\n</svg:svg>\n", styles: [":host{display:block;width:100%;height:100%;-webkit-user-select:none;user-select:none}:host ::ng-deep *{box-sizing:border-box}\n"] }]
3260
+ ], template: "<svg:svg #flow rootSvgRef rootSvgContext rootPointer flowSizeController class=\"root-svg\">\n <defs flowDefs [markers]=\"markers()\" />\n\n <g background />\n\n <svg:g mapContext spacePointContext>\n <!-- Connection -->\n <svg:g connection [model]=\"connection\" [template]=\"connectionTemplateDirective()?.templateRef\" />\n\n @if (optimization().detachedGroupsLayer) {\n <!-- Groups -->\n @for (model of groups(); track trackNodes($index, model)) {\n <svg:g\n node\n [model]=\"model\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective()?.templateRef\"\n [attr.transform]=\"model.pointTransform()\" />\n }\n <!-- Edges -->\n @for (model of edgeModels(); track trackEdges($index, model)) {\n <svg:g\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective()?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective()?.templateRef\" />\n }\n <!-- Nodes -->\n @for (model of nonGroups(); track trackNodes($index, model)) {\n <svg:g\n node\n [model]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective()?.templateRef\"\n [attr.transform]=\"model.pointTransform()\" />\n }\n }\n\n @if (!optimization().detachedGroupsLayer) {\n <!-- Edges -->\n @for (model of edgeModels(); track trackEdges($index, model)) {\n <svg:g\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective()?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective()?.templateRef\" />\n }\n <!-- Nodes -->\n @for (model of nodeModels(); track trackNodes($index, model)) {\n <svg:g\n node\n [model]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective()?.templateRef\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective()?.templateRef\"\n [attr.transform]=\"model.pointTransform()\" />\n }\n }\n </svg:g>\n\n <!-- Minimap -->\n @if (minimap(); as minimap) {\n <ng-container [ngTemplateOutlet]=\"minimap.template()\" />\n }\n</svg:svg>\n", styles: [":host{display:block;width:100%;height:100%;-webkit-user-select:none;user-select:none}:host ::ng-deep *{box-sizing:border-box}\n"] }]
3213
3261
  }], propDecorators: { view: [{
3214
3262
  type: Input
3215
3263
  }], minZoom: [{
@@ -3274,7 +3322,7 @@ class SelectableDirective {
3274
3322
  }
3275
3323
  entity() {
3276
3324
  if (this.parentNode) {
3277
- return this.parentNode.nodeModel();
3325
+ return this.parentNode.model();
3278
3326
  }
3279
3327
  else if (this.parentEdge) {
3280
3328
  return this.parentEdge.model();
@@ -3521,6 +3569,14 @@ function provideCustomNodeMocks() {
3521
3569
  pushEvent: () => { },
3522
3570
  },
3523
3571
  },
3572
+ {
3573
+ provide: NodeAccessorService,
3574
+ useFactory: () => ({
3575
+ model: signal(mockModel()),
3576
+ }),
3577
+ },
3578
+ FlowEntitiesService,
3579
+ // TODO: mocks below should be removed after the major release
3524
3580
  {
3525
3581
  provide: HandleService,
3526
3582
  useFactory: () => ({
@@ -3549,12 +3605,6 @@ function provideCustomNodeMocks() {
3549
3605
  documentPointToFlowPoint: (point) => point,
3550
3606
  },
3551
3607
  },
3552
- {
3553
- provide: NodeAccessorService,
3554
- useFactory: () => ({
3555
- model: signal(mockModel()),
3556
- }),
3557
- },
3558
3608
  {
3559
3609
  provide: SelectionService,
3560
3610
  useValue: {
@@ -3562,16 +3612,473 @@ function provideCustomNodeMocks() {
3562
3612
  },
3563
3613
  },
3564
3614
  FlowSettingsService,
3565
- FlowEntitiesService,
3566
3615
  ViewportService,
3567
3616
  ];
3568
3617
  }
3569
3618
 
3619
+ class EdgeTemplateMockDirective {
3620
+ constructor() {
3621
+ this.templateRef = inject(TemplateRef);
3622
+ }
3623
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeTemplateMockDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3624
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: EdgeTemplateMockDirective, isStandalone: true, selector: "ng-template[edge]", ngImport: i0 }); }
3625
+ }
3626
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeTemplateMockDirective, decorators: [{
3627
+ type: Directive,
3628
+ args: [{
3629
+ standalone: true,
3630
+ selector: 'ng-template[edge]',
3631
+ }]
3632
+ }] });
3633
+ class ConnectionTemplateMockDirective {
3634
+ constructor() {
3635
+ this.templateRef = inject(TemplateRef);
3636
+ }
3637
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConnectionTemplateMockDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3638
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: ConnectionTemplateMockDirective, isStandalone: true, selector: "ng-template[connection]", ngImport: i0 }); }
3639
+ }
3640
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConnectionTemplateMockDirective, decorators: [{
3641
+ type: Directive,
3642
+ args: [{
3643
+ standalone: true,
3644
+ selector: 'ng-template[connection]',
3645
+ }]
3646
+ }] });
3647
+ class EdgeLabelHtmlTemplateMockDirective {
3648
+ constructor() {
3649
+ this.templateRef = inject(TemplateRef);
3650
+ }
3651
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeLabelHtmlTemplateMockDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3652
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: EdgeLabelHtmlTemplateMockDirective, isStandalone: true, selector: "ng-template[edgeLabelHtml]", ngImport: i0 }); }
3653
+ }
3654
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeLabelHtmlTemplateMockDirective, decorators: [{
3655
+ type: Directive,
3656
+ args: [{
3657
+ standalone: true,
3658
+ selector: 'ng-template[edgeLabelHtml]',
3659
+ }]
3660
+ }] });
3661
+ class NodeHtmlTemplateMockDirective {
3662
+ constructor() {
3663
+ this.templateRef = inject(TemplateRef);
3664
+ }
3665
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeHtmlTemplateMockDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3666
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: NodeHtmlTemplateMockDirective, isStandalone: true, selector: "ng-template[nodeHtml]", ngImport: i0 }); }
3667
+ }
3668
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeHtmlTemplateMockDirective, decorators: [{
3669
+ type: Directive,
3670
+ args: [{
3671
+ standalone: true,
3672
+ selector: 'ng-template[nodeHtml]',
3673
+ }]
3674
+ }] });
3675
+ class GroupNodeTemplateMockDirective {
3676
+ constructor() {
3677
+ this.templateRef = inject(TemplateRef);
3678
+ }
3679
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: GroupNodeTemplateMockDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3680
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: GroupNodeTemplateMockDirective, isStandalone: true, selector: "ng-template[groupNode]", ngImport: i0 }); }
3681
+ }
3682
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: GroupNodeTemplateMockDirective, decorators: [{
3683
+ type: Directive,
3684
+ args: [{
3685
+ standalone: true,
3686
+ selector: 'ng-template[groupNode]',
3687
+ }]
3688
+ }] });
3689
+ class HandleTemplateMockDirective {
3690
+ constructor() {
3691
+ this.templateRef = inject(TemplateRef);
3692
+ }
3693
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleTemplateMockDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3694
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: HandleTemplateMockDirective, isStandalone: true, selector: "ng-template[handle]", ngImport: i0 }); }
3695
+ }
3696
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleTemplateMockDirective, decorators: [{
3697
+ type: Directive,
3698
+ args: [{
3699
+ standalone: true,
3700
+ selector: 'ng-template[handle]',
3701
+ }]
3702
+ }] });
3703
+
3704
+ class VflowMockComponent {
3705
+ constructor() {
3706
+ this.nodes = input.required();
3707
+ this.edges = input.required();
3708
+ this.view = input([400, 400]);
3709
+ this.minZoom = input(0.5);
3710
+ this.maxZoom = input(3);
3711
+ this.background = input('#fff');
3712
+ this.optimization = input({
3713
+ detachedGroupsLayer: false,
3714
+ });
3715
+ this.entitiesSelectable = input(true);
3716
+ this.keyboardShortcuts = input({
3717
+ multiSelection: null,
3718
+ });
3719
+ this.connection = input();
3720
+ // eslint-disable-next-line @angular-eslint/no-output-on-prefix
3721
+ this.onComponentNodeEvent = output();
3722
+ this.nodeTemplateDirective = contentChild(NodeHtmlTemplateMockDirective);
3723
+ this.groupNodeTemplateDirective = contentChild(GroupNodeTemplateMockDirective);
3724
+ this.edgeTemplateDirective = contentChild(EdgeTemplateMockDirective);
3725
+ this.edgeLabelHtmlDirective = contentChild(EdgeLabelHtmlTemplateMockDirective);
3726
+ this.connectionTemplateDirective = contentChild(ConnectionTemplateMockDirective);
3727
+ this.viewport = signal({
3728
+ x: 0,
3729
+ y: 0,
3730
+ zoom: 1,
3731
+ });
3732
+ this.nodesChange = signal([]);
3733
+ this.edgesChange = signal([]);
3734
+ this.viewportChange$ = toObservable(this.viewport);
3735
+ this.nodesChange$ = toObservable(this.nodesChange);
3736
+ this.edgesChange$ = toObservable(this.edgesChange);
3737
+ }
3738
+ viewportTo(viewport) {
3739
+ this.viewport.set(viewport);
3740
+ }
3741
+ zoomTo(zoom) {
3742
+ this.viewport.update((prev) => ({ ...prev, zoom }));
3743
+ }
3744
+ panTo(point) {
3745
+ this.viewport.update((prev) => ({ ...prev, x: point.x, y: point.y }));
3746
+ }
3747
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
3748
+ fitView(options) { }
3749
+ documentPointToFlowPoint(point) {
3750
+ return point;
3751
+ }
3752
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
3753
+ getNode(id) {
3754
+ return this.nodes().find((node) => node.id === id);
3755
+ }
3756
+ getDetachedEdges() {
3757
+ return [];
3758
+ }
3759
+ createSignal(value) {
3760
+ return signal(value);
3761
+ }
3762
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: VflowMockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3763
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: VflowMockComponent, isStandalone: true, selector: "vflow", inputs: { nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: true, transformFunction: null }, edges: { classPropertyName: "edges", publicName: "edges", isSignal: true, isRequired: true, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null }, minZoom: { classPropertyName: "minZoom", publicName: "minZoom", isSignal: true, isRequired: false, transformFunction: null }, maxZoom: { classPropertyName: "maxZoom", publicName: "maxZoom", isSignal: true, isRequired: false, transformFunction: null }, background: { classPropertyName: "background", publicName: "background", isSignal: true, isRequired: false, transformFunction: null }, optimization: { classPropertyName: "optimization", publicName: "optimization", isSignal: true, isRequired: false, transformFunction: null }, entitiesSelectable: { classPropertyName: "entitiesSelectable", publicName: "entitiesSelectable", isSignal: true, isRequired: false, transformFunction: null }, keyboardShortcuts: { classPropertyName: "keyboardShortcuts", publicName: "keyboardShortcuts", isSignal: true, isRequired: false, transformFunction: null }, connection: { classPropertyName: "connection", publicName: "connection", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onComponentNodeEvent: "onComponentNodeEvent" }, queries: [{ propertyName: "nodeTemplateDirective", first: true, predicate: NodeHtmlTemplateMockDirective, descendants: true, isSignal: true }, { propertyName: "groupNodeTemplateDirective", first: true, predicate: GroupNodeTemplateMockDirective, descendants: true, isSignal: true }, { propertyName: "edgeTemplateDirective", first: true, predicate: EdgeTemplateMockDirective, descendants: true, isSignal: true }, { propertyName: "edgeLabelHtmlDirective", first: true, predicate: EdgeLabelHtmlTemplateMockDirective, descendants: true, isSignal: true }, { propertyName: "connectionTemplateDirective", first: true, predicate: ConnectionTemplateMockDirective, descendants: true, isSignal: true }], ngImport: i0, template: `
3764
+ <ng-content />
3765
+
3766
+ @for (node of nodes(); track $index) {
3767
+ @if (node.type === 'html-template') {
3768
+ <ng-component
3769
+ [ngTemplateOutlet]="nodeTemplateDirective()?.templateRef ?? null"
3770
+ [ngTemplateOutletContext]="{
3771
+ $implicit: {
3772
+ node: node,
3773
+ selected: createSignal(false),
3774
+ },
3775
+ }" />
3776
+ }
3777
+
3778
+ @if (node.type === 'template-group') {
3779
+ <ng-component
3780
+ [ngTemplateOutlet]="groupNodeTemplateDirective()?.templateRef ?? null"
3781
+ [ngTemplateOutletContext]="{
3782
+ $implicit: {
3783
+ node: node,
3784
+ selected: createSignal(false),
3785
+ width: createSignal(node.width),
3786
+ height: createSignal(node.height),
3787
+ },
3788
+ }" />
3789
+ }
3790
+ }
3791
+
3792
+ @for (edge of edges(); track $index) {
3793
+ @if (edge.type === 'template') {
3794
+ <ng-component
3795
+ [ngTemplateOutlet]="edgeTemplateDirective()?.templateRef ?? null"
3796
+ [ngTemplateOutletContext]="{
3797
+ $implicit: {
3798
+ edge: edge,
3799
+ selected: createSignal(false),
3800
+ path: createSignal(''),
3801
+ markerStart: createSignal(''),
3802
+ markerEnd: createSignal(''),
3803
+ },
3804
+ }" />
3805
+
3806
+ @if (edge.edgeLabels?.start) {
3807
+ <ng-component
3808
+ [ngTemplateOutlet]="edgeLabelHtmlDirective()?.templateRef ?? null"
3809
+ [ngTemplateOutletContext]="{
3810
+ $implicit: {
3811
+ edge: edge,
3812
+ },
3813
+ }" />
3814
+ }
3815
+
3816
+ @if (edge.edgeLabels?.center) {
3817
+ <ng-component
3818
+ [ngTemplateOutlet]="edgeLabelHtmlDirective()?.templateRef ?? null"
3819
+ [ngTemplateOutletContext]="{
3820
+ $implicit: {
3821
+ edge: edge,
3822
+ label: edge.edgeLabels?.center,
3823
+ },
3824
+ }" />
3825
+ }
3826
+
3827
+ @if (edge.edgeLabels?.end) {
3828
+ <ng-component
3829
+ [ngTemplateOutlet]="edgeLabelHtmlDirective()?.templateRef ?? null"
3830
+ [ngTemplateOutletContext]="{
3831
+ $implicit: {
3832
+ edge: edge,
3833
+ label: edge.edgeLabels?.end,
3834
+ },
3835
+ }" />
3836
+ }
3837
+ }
3838
+ }
3839
+
3840
+ @if (connection()?.type === 'template') {
3841
+ <ng-component
3842
+ [ngTemplateOutlet]="connectionTemplateDirective()?.templateRef ?? null"
3843
+ [ngTemplateOutletContext]="{
3844
+ $implicit: {
3845
+ path: createSignal(''),
3846
+ marker: createSignal(''),
3847
+ },
3848
+ }" />
3849
+ }
3850
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3851
+ }
3852
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: VflowMockComponent, decorators: [{
3853
+ type: Component,
3854
+ args: [{
3855
+ selector: 'vflow',
3856
+ template: `
3857
+ <ng-content />
3858
+
3859
+ @for (node of nodes(); track $index) {
3860
+ @if (node.type === 'html-template') {
3861
+ <ng-component
3862
+ [ngTemplateOutlet]="nodeTemplateDirective()?.templateRef ?? null"
3863
+ [ngTemplateOutletContext]="{
3864
+ $implicit: {
3865
+ node: node,
3866
+ selected: createSignal(false),
3867
+ },
3868
+ }" />
3869
+ }
3870
+
3871
+ @if (node.type === 'template-group') {
3872
+ <ng-component
3873
+ [ngTemplateOutlet]="groupNodeTemplateDirective()?.templateRef ?? null"
3874
+ [ngTemplateOutletContext]="{
3875
+ $implicit: {
3876
+ node: node,
3877
+ selected: createSignal(false),
3878
+ width: createSignal(node.width),
3879
+ height: createSignal(node.height),
3880
+ },
3881
+ }" />
3882
+ }
3883
+ }
3884
+
3885
+ @for (edge of edges(); track $index) {
3886
+ @if (edge.type === 'template') {
3887
+ <ng-component
3888
+ [ngTemplateOutlet]="edgeTemplateDirective()?.templateRef ?? null"
3889
+ [ngTemplateOutletContext]="{
3890
+ $implicit: {
3891
+ edge: edge,
3892
+ selected: createSignal(false),
3893
+ path: createSignal(''),
3894
+ markerStart: createSignal(''),
3895
+ markerEnd: createSignal(''),
3896
+ },
3897
+ }" />
3898
+
3899
+ @if (edge.edgeLabels?.start) {
3900
+ <ng-component
3901
+ [ngTemplateOutlet]="edgeLabelHtmlDirective()?.templateRef ?? null"
3902
+ [ngTemplateOutletContext]="{
3903
+ $implicit: {
3904
+ edge: edge,
3905
+ },
3906
+ }" />
3907
+ }
3908
+
3909
+ @if (edge.edgeLabels?.center) {
3910
+ <ng-component
3911
+ [ngTemplateOutlet]="edgeLabelHtmlDirective()?.templateRef ?? null"
3912
+ [ngTemplateOutletContext]="{
3913
+ $implicit: {
3914
+ edge: edge,
3915
+ label: edge.edgeLabels?.center,
3916
+ },
3917
+ }" />
3918
+ }
3919
+
3920
+ @if (edge.edgeLabels?.end) {
3921
+ <ng-component
3922
+ [ngTemplateOutlet]="edgeLabelHtmlDirective()?.templateRef ?? null"
3923
+ [ngTemplateOutletContext]="{
3924
+ $implicit: {
3925
+ edge: edge,
3926
+ label: edge.edgeLabels?.end,
3927
+ },
3928
+ }" />
3929
+ }
3930
+ }
3931
+ }
3932
+
3933
+ @if (connection()?.type === 'template') {
3934
+ <ng-component
3935
+ [ngTemplateOutlet]="connectionTemplateDirective()?.templateRef ?? null"
3936
+ [ngTemplateOutletContext]="{
3937
+ $implicit: {
3938
+ path: createSignal(''),
3939
+ marker: createSignal(''),
3940
+ },
3941
+ }" />
3942
+ }
3943
+ `,
3944
+ changeDetection: ChangeDetectionStrategy.OnPush,
3945
+ standalone: true,
3946
+ imports: [NgTemplateOutlet],
3947
+ }]
3948
+ }] });
3949
+
3950
+ class HandleMockComponent {
3951
+ constructor() {
3952
+ this.position = input.required();
3953
+ this.type = input.required();
3954
+ this.id = input();
3955
+ this.template = input();
3956
+ }
3957
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleMockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3958
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: HandleMockComponent, isStandalone: true, selector: "handle", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: true, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: true, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, template: { classPropertyName: "template", publicName: "template", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3959
+ }
3960
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleMockComponent, decorators: [{
3961
+ type: Component,
3962
+ args: [{
3963
+ selector: 'handle',
3964
+ template: '',
3965
+ changeDetection: ChangeDetectionStrategy.OnPush,
3966
+ standalone: true,
3967
+ }]
3968
+ }] });
3969
+
3970
+ class ResizableMockComponent {
3971
+ constructor() {
3972
+ this.resizable = input();
3973
+ this.resizerColor = input('#2e414c');
3974
+ this.gap = input(1.5);
3975
+ }
3976
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ResizableMockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3977
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: ResizableMockComponent, isStandalone: true, selector: "[resizable]", inputs: { resizable: { classPropertyName: "resizable", publicName: "resizable", isSignal: true, isRequired: false, transformFunction: null }, resizerColor: { classPropertyName: "resizerColor", publicName: "resizerColor", isSignal: true, isRequired: false, transformFunction: null }, gap: { classPropertyName: "gap", publicName: "gap", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '<ng-content />', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3978
+ }
3979
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ResizableMockComponent, decorators: [{
3980
+ type: Component,
3981
+ args: [{
3982
+ selector: '[resizable]',
3983
+ template: '<ng-content />',
3984
+ standalone: true,
3985
+ changeDetection: ChangeDetectionStrategy.OnPush,
3986
+ }]
3987
+ }] });
3988
+
3989
+ class MiniMapMockComponent {
3990
+ constructor() {
3991
+ this.maskColor = input(`rgba(215, 215, 215, 0.6)`);
3992
+ this.strokeColor = input(`rgb(200, 200, 200)`);
3993
+ this.position = input('bottom-right');
3994
+ this.scaleOnHover = input(false);
3995
+ }
3996
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MiniMapMockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3997
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: MiniMapMockComponent, isStandalone: true, selector: "mini-map", inputs: { maskColor: { classPropertyName: "maskColor", publicName: "maskColor", isSignal: true, isRequired: false, transformFunction: null }, strokeColor: { classPropertyName: "strokeColor", publicName: "strokeColor", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, scaleOnHover: { classPropertyName: "scaleOnHover", publicName: "scaleOnHover", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3998
+ }
3999
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MiniMapMockComponent, decorators: [{
4000
+ type: Component,
4001
+ args: [{
4002
+ selector: 'mini-map',
4003
+ template: '',
4004
+ standalone: true,
4005
+ changeDetection: ChangeDetectionStrategy.OnPush,
4006
+ }]
4007
+ }] });
4008
+
4009
+ class NodeToolbarMockComponent {
4010
+ constructor() {
4011
+ this.position = input('top');
4012
+ }
4013
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeToolbarMockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4014
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: NodeToolbarMockComponent, isStandalone: true, selector: "node-toolbar", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '<ng-content />', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4015
+ }
4016
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeToolbarMockComponent, decorators: [{
4017
+ type: Component,
4018
+ args: [{
4019
+ selector: 'node-toolbar',
4020
+ template: '<ng-content />',
4021
+ standalone: true,
4022
+ changeDetection: ChangeDetectionStrategy.OnPush,
4023
+ }]
4024
+ }] });
4025
+
4026
+ class ConnectionControllerMockDirective {
4027
+ constructor() {
4028
+ // eslint-disable-next-line @angular-eslint/no-output-on-prefix
4029
+ this.onConnect = output();
4030
+ }
4031
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConnectionControllerMockDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4032
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: ConnectionControllerMockDirective, isStandalone: true, selector: "[onConnect]", outputs: { onConnect: "onConnect" }, ngImport: i0 }); }
4033
+ }
4034
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConnectionControllerMockDirective, decorators: [{
4035
+ type: Directive,
4036
+ args: [{ selector: '[onConnect]', standalone: true }]
4037
+ }] });
4038
+
4039
+ class DragHandleMockDirective {
4040
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DragHandleMockDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4041
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: DragHandleMockDirective, isStandalone: true, selector: "[dragHandle]", ngImport: i0 }); }
4042
+ }
4043
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DragHandleMockDirective, decorators: [{
4044
+ type: Directive,
4045
+ args: [{ selector: '[dragHandle]', standalone: true }]
4046
+ }] });
4047
+
4048
+ class SelectableMockDirective {
4049
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectableMockDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4050
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: SelectableMockDirective, isStandalone: true, selector: "[selectable]", ngImport: i0 }); }
4051
+ }
4052
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectableMockDirective, decorators: [{
4053
+ type: Directive,
4054
+ args: [{
4055
+ selector: '[selectable]',
4056
+ standalone: true,
4057
+ }]
4058
+ }] });
4059
+
4060
+ const VflowMocks = [
4061
+ VflowMockComponent,
4062
+ HandleMockComponent,
4063
+ ResizableMockComponent,
4064
+ SelectableMockDirective,
4065
+ MiniMapMockComponent,
4066
+ NodeToolbarMockComponent,
4067
+ DragHandleMockDirective,
4068
+ ConnectionControllerMockDirective,
4069
+ NodeHtmlTemplateMockDirective,
4070
+ GroupNodeTemplateMockDirective,
4071
+ EdgeLabelHtmlTemplateMockDirective,
4072
+ EdgeTemplateMockDirective,
4073
+ ConnectionTemplateMockDirective,
4074
+ HandleTemplateMockDirective,
4075
+ ];
4076
+
3570
4077
  // Standalone Util
3571
4078
 
3572
4079
  /**
3573
4080
  * Generated bundle index. Do not edit.
3574
4081
  */
3575
4082
 
3576
- export { ChangesControllerDirective, ConnectionControllerDirective, ConnectionTemplateDirective, CustomDynamicNodeComponent, CustomNodeComponent, DragHandleDirective, EdgeLabelHtmlTemplateDirective, EdgeTemplateDirective, GroupNodeTemplateDirective, HandleComponent, HandleTemplateDirective, MiniMapComponent, NodeHtmlTemplateDirective, NodeToolbarComponent, NodeToolbarWrapperDirective, ResizableComponent, SelectableDirective, Vflow, VflowComponent, isComponentDynamicNode, isComponentStaticNode, isDefaultDynamicGroupNode, isDefaultDynamicNode, isDefaultStaticGroupNode, isDefaultStaticNode, isDynamicNode, isStaticNode, isTemplateDynamicGroupNode, isTemplateDynamicNode, isTemplateStaticGroupNode, isTemplateStaticNode, provideCustomNodeMocks };
4083
+ export { ChangesControllerDirective, ConnectionControllerDirective, ConnectionControllerMockDirective, ConnectionTemplateDirective, ConnectionTemplateMockDirective, CustomDynamicNodeComponent, CustomNodeComponent, DragHandleDirective, DragHandleMockDirective, EdgeLabelHtmlTemplateDirective, EdgeLabelHtmlTemplateMockDirective, EdgeTemplateDirective, EdgeTemplateMockDirective, GroupNodeTemplateDirective, GroupNodeTemplateMockDirective, HandleComponent, HandleMockComponent, HandleTemplateDirective, HandleTemplateMockDirective, MiniMapComponent, MiniMapMockComponent, NodeHtmlTemplateDirective, NodeHtmlTemplateMockDirective, NodeToolbarComponent, NodeToolbarMockComponent, NodeToolbarWrapperDirective, ResizableComponent, ResizableMockComponent, SelectableDirective, SelectableMockDirective, Vflow, VflowComponent, VflowMockComponent, VflowMocks, isComponentDynamicNode, isComponentStaticNode, isDefaultDynamicGroupNode, isDefaultDynamicNode, isDefaultStaticGroupNode, isDefaultStaticNode, isDynamicNode, isStaticNode, isTemplateDynamicGroupNode, isTemplateDynamicNode, isTemplateStaticGroupNode, isTemplateStaticNode, provideCustomNodeMocks };
3577
4084
  //# sourceMappingURL=ngx-vflow.mjs.map