ngx-vflow 0.15.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/README.md +8 -1
  2. package/esm2022/lib/vflow/components/background/background.component.mjs +75 -8
  3. package/esm2022/lib/vflow/components/connection/connection.component.mjs +67 -49
  4. package/esm2022/lib/vflow/components/custom-node-base/custom-node-base.component.mjs +32 -25
  5. package/esm2022/lib/vflow/components/default-node/default-node.component.mjs +9 -11
  6. package/esm2022/lib/vflow/components/defs/defs.component.mjs +9 -12
  7. package/esm2022/lib/vflow/components/edge/edge.component.mjs +21 -24
  8. package/esm2022/lib/vflow/components/edge-label/edge-label.component.mjs +26 -31
  9. package/esm2022/lib/vflow/components/node/node.component.mjs +54 -50
  10. package/esm2022/lib/vflow/components/vflow/vflow.component.mjs +95 -90
  11. package/esm2022/lib/vflow/decorators/run-in-injection-context.decorator.mjs +1 -1
  12. package/esm2022/lib/vflow/directives/changes-controller.directive.mjs +41 -125
  13. package/esm2022/lib/vflow/directives/connection-controller.directive.mjs +16 -16
  14. package/esm2022/lib/vflow/directives/drag-handle.directive.mjs +7 -6
  15. package/esm2022/lib/vflow/directives/flow-size-controller.directive.mjs +7 -6
  16. package/esm2022/lib/vflow/directives/handle-size-controller.directive.mjs +15 -12
  17. package/esm2022/lib/vflow/directives/map-context.directive.mjs +8 -5
  18. package/esm2022/lib/vflow/directives/pointer.directive.mjs +18 -19
  19. package/esm2022/lib/vflow/directives/reference.directive.mjs +6 -5
  20. package/esm2022/lib/vflow/directives/root-pointer.directive.mjs +8 -5
  21. package/esm2022/lib/vflow/directives/root-svg-context.directive.mjs +8 -5
  22. package/esm2022/lib/vflow/directives/selectable.directive.mjs +10 -7
  23. package/esm2022/lib/vflow/directives/space-point-context.directive.mjs +8 -5
  24. package/esm2022/lib/vflow/directives/template.directive.mjs +43 -25
  25. package/esm2022/lib/vflow/interfaces/component-node-event.interface.mjs +1 -1
  26. package/esm2022/lib/vflow/interfaces/edge.interface.mjs +1 -1
  27. package/esm2022/lib/vflow/interfaces/node.interface.mjs +1 -1
  28. package/esm2022/lib/vflow/interfaces/optimization.interface.mjs +1 -1
  29. package/esm2022/lib/vflow/math/edge-path/bezier-path.mjs +1 -1
  30. package/esm2022/lib/vflow/math/edge-path/smooth-step-path.mjs +170 -0
  31. package/esm2022/lib/vflow/models/connection.model.mjs +1 -1
  32. package/esm2022/lib/vflow/models/edge.model.mjs +6 -1
  33. package/esm2022/lib/vflow/models/handle.model.mjs +2 -2
  34. package/esm2022/lib/vflow/models/node.model.mjs +4 -10
  35. package/esm2022/lib/vflow/models/toolbar.model.mjs +1 -1
  36. package/esm2022/lib/vflow/public-components/custom-dynamic-node/custom-dynamic-node.component.mjs +16 -10
  37. package/esm2022/lib/vflow/public-components/custom-node/custom-node.component.mjs +15 -10
  38. package/esm2022/lib/vflow/public-components/handle/handle.component.mjs +52 -0
  39. package/esm2022/lib/vflow/public-components/minimap/minimap.component.mjs +42 -45
  40. package/esm2022/lib/vflow/public-components/node-toolbar/node-toolbar.component.mjs +24 -27
  41. package/esm2022/lib/vflow/public-components/resizable/resizable.component.mjs +60 -45
  42. package/esm2022/lib/vflow/services/component-event-bus.service.mjs +3 -3
  43. package/esm2022/lib/vflow/services/draggable.service.mjs +4 -4
  44. package/esm2022/lib/vflow/services/edge-changes.service.mjs +3 -3
  45. package/esm2022/lib/vflow/services/flow-entities.service.mjs +4 -4
  46. package/esm2022/lib/vflow/services/flow-settings.service.mjs +4 -10
  47. package/esm2022/lib/vflow/services/flow-status.service.mjs +4 -4
  48. package/esm2022/lib/vflow/services/handle.service.mjs +4 -4
  49. package/esm2022/lib/vflow/services/keyboard.service.mjs +5 -5
  50. package/esm2022/lib/vflow/services/node-accessor.service.mjs +3 -3
  51. package/esm2022/lib/vflow/services/node-changes.service.mjs +3 -3
  52. package/esm2022/lib/vflow/services/node-rendering.service.mjs +11 -4
  53. package/esm2022/lib/vflow/services/overlays.service.mjs +3 -3
  54. package/esm2022/lib/vflow/services/selection.service.mjs +4 -4
  55. package/esm2022/lib/vflow/services/viewport.service.mjs +3 -3
  56. package/esm2022/lib/vflow/types/background.type.mjs +1 -1
  57. package/esm2022/lib/vflow/utils/adjust-direction.mjs +1 -1
  58. package/esm2022/lib/vflow/utils/get-os.mjs +1 -1
  59. package/esm2022/lib/vflow/utils/is-group-node.mjs +4 -0
  60. package/esm2022/lib/vflow/utils/nodes.mjs +1 -1
  61. package/esm2022/lib/vflow/vflow.mjs +24 -0
  62. package/esm2022/public-api.mjs +4 -5
  63. package/fesm2022/ngx-vflow.mjs +1160 -1005
  64. package/fesm2022/ngx-vflow.mjs.map +1 -1
  65. package/lib/vflow/components/background/background.component.d.ts +14 -1
  66. package/lib/vflow/components/connection/connection.component.d.ts +3 -3
  67. package/lib/vflow/components/custom-node-base/custom-node-base.component.d.ts +4 -9
  68. package/lib/vflow/components/default-node/default-node.component.d.ts +2 -2
  69. package/lib/vflow/components/defs/defs.component.d.ts +2 -2
  70. package/lib/vflow/components/edge/edge.component.d.ts +7 -7
  71. package/lib/vflow/components/edge-label/edge-label.component.d.ts +9 -8
  72. package/lib/vflow/components/node/node.component.d.ts +5 -6
  73. package/lib/vflow/components/vflow/vflow.component.d.ts +19 -27
  74. package/lib/vflow/directives/changes-controller.directive.d.ts +29 -30
  75. package/lib/vflow/directives/connection-controller.directive.d.ts +1 -2
  76. package/lib/vflow/directives/drag-handle.directive.d.ts +1 -1
  77. package/lib/vflow/directives/flow-size-controller.directive.d.ts +1 -1
  78. package/lib/vflow/directives/handle-size-controller.directive.d.ts +2 -2
  79. package/lib/vflow/directives/map-context.directive.d.ts +1 -1
  80. package/lib/vflow/directives/pointer.directive.d.ts +9 -6
  81. package/lib/vflow/directives/reference.directive.d.ts +1 -1
  82. package/lib/vflow/directives/root-pointer.directive.d.ts +1 -1
  83. package/lib/vflow/directives/root-svg-context.directive.d.ts +1 -1
  84. package/lib/vflow/directives/selectable.directive.d.ts +1 -1
  85. package/lib/vflow/directives/space-point-context.directive.d.ts +1 -1
  86. package/lib/vflow/directives/template.directive.d.ts +6 -6
  87. package/lib/vflow/interfaces/component-node-event.interface.d.ts +3 -3
  88. package/lib/vflow/interfaces/edge.interface.d.ts +1 -1
  89. package/lib/vflow/interfaces/node.interface.d.ts +14 -14
  90. package/lib/vflow/interfaces/optimization.interface.d.ts +7 -1
  91. package/lib/vflow/math/edge-path/smooth-step-path.d.ts +5 -0
  92. package/lib/vflow/models/edge.model.d.ts +1 -17
  93. package/lib/vflow/models/handle.model.d.ts +4 -4
  94. package/lib/vflow/models/node.model.d.ts +2 -5
  95. package/lib/vflow/public-components/custom-dynamic-node/custom-dynamic-node.component.d.ts +3 -3
  96. package/lib/vflow/public-components/custom-node/custom-node.component.d.ts +3 -3
  97. package/lib/vflow/{components → public-components}/handle/handle.component.d.ts +5 -5
  98. package/lib/vflow/public-components/minimap/minimap.component.d.ts +8 -10
  99. package/lib/vflow/public-components/node-toolbar/node-toolbar.component.d.ts +6 -5
  100. package/lib/vflow/public-components/resizable/resizable.component.d.ts +5 -4
  101. package/lib/vflow/services/flow-settings.service.d.ts +0 -7
  102. package/lib/vflow/services/node-rendering.service.d.ts +2 -0
  103. package/lib/vflow/types/background.type.d.ts +24 -1
  104. package/lib/vflow/utils/is-group-node.d.ts +2 -0
  105. package/lib/vflow/utils/reference-keeper.d.ts +1 -1
  106. package/lib/vflow/vflow.d.ts +9 -0
  107. package/package.json +3 -3
  108. package/public-api.d.ts +2 -3
  109. package/esm2022/lib/vflow/components/handle/handle.component.mjs +0 -49
  110. package/esm2022/lib/vflow/interfaces/handle-positions.interface.mjs +0 -2
  111. package/esm2022/lib/vflow/vflow.module.mjs +0 -121
  112. package/lib/vflow/interfaces/handle-positions.interface.d.ts +0 -5
  113. package/lib/vflow/vflow.module.d.ts +0 -30
@@ -1,13 +1,12 @@
1
- import * as i1 from '@angular/common';
2
- import { NgIf, NgFor, NgTemplateOutlet, NgComponentOutlet, KeyValuePipe } from '@angular/common';
3
1
  import * as i0 from '@angular/core';
4
- import { signal, computed, Injectable, inject, ElementRef, Directive, effect, untracked, TemplateRef, EventEmitter, Output, DestroyRef, Input, runInInjectionContext, Component, Injector, ChangeDetectionStrategy, HostListener, ViewChild, NgZone, ContentChild, NgModule } from '@angular/core';
2
+ import { signal, computed, Injectable, inject, ElementRef, Directive, effect, untracked, TemplateRef, output, DestroyRef, EventEmitter, OutputEmitterRef, input, viewChild, Component, ChangeDetectionStrategy, Injector, runInInjectionContext, HostListener, NgZone, contentChild, Input, forwardRef } from '@angular/core';
5
3
  import { select } from 'd3-selection';
6
4
  import { zoomIdentity, zoom } from 'd3-zoom';
7
- import { switchMap, merge, fromEvent, tap, Subject, observeOn, animationFrameScheduler, skip, map, pairwise, filter, distinctUntilChanged, asyncScheduler, zip, share, Observable, startWith, of } from 'rxjs';
8
- import { toObservable, takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
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';
9
7
  import { drag } from 'd3-drag';
10
8
  import { __decorate } from 'tslib';
9
+ import { NgTemplateOutlet, NgComponentOutlet, KeyValuePipe } from '@angular/common';
11
10
 
12
11
  function getNodesBounds(nodes) {
13
12
  if (nodes.length === 0) {
@@ -129,10 +128,10 @@ class FlowEntitiesService {
129
128
  getDetachedEdges() {
130
129
  return this.edges().filter(e => e.detached());
131
130
  }
132
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowEntitiesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
133
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowEntitiesService }); }
131
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowEntitiesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
132
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowEntitiesService }); }
134
133
  }
135
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowEntitiesService, decorators: [{
134
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowEntitiesService, decorators: [{
136
135
  type: Injectable
137
136
  }] });
138
137
 
@@ -154,12 +153,6 @@ function clamp(value, min = 0, max = 1) {
154
153
  class FlowSettingsService {
155
154
  constructor() {
156
155
  this.entitiesSelectable = signal(true);
157
- /**
158
- * Global setting with handle positions. Nodes derive this value
159
- *
160
- * @deprecated
161
- */
162
- this.handlePositions = signal({ source: 'right', target: 'left' });
163
156
  /**
164
157
  * @see {VflowComponent.view}
165
158
  */
@@ -176,10 +169,10 @@ class FlowSettingsService {
176
169
  this.maxZoom = signal(3);
177
170
  this.background = signal({ type: 'solid', color: '#fff' });
178
171
  }
179
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowSettingsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
180
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowSettingsService }); }
172
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowSettingsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
173
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowSettingsService }); }
181
174
  }
182
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowSettingsService, decorators: [{
175
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowSettingsService, decorators: [{
183
176
  type: Injectable
184
177
  }] });
185
178
 
@@ -225,10 +218,10 @@ class ViewportService {
225
218
  .map(nodeId => this.entitiesService.nodes().find(({ node }) => node.id === nodeId))
226
219
  .filter((node) => !!node);
227
220
  }
228
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ViewportService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
229
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ViewportService }); }
221
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ViewportService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
222
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ViewportService }); }
230
223
  }
231
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ViewportService, decorators: [{
224
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ViewportService, decorators: [{
232
225
  type: Injectable
233
226
  }] });
234
227
 
@@ -240,13 +233,14 @@ class RootSvgReferenceDirective {
240
233
  constructor() {
241
234
  this.element = inject(ElementRef).nativeElement;
242
235
  }
243
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RootSvgReferenceDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
244
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: RootSvgReferenceDirective, selector: "svg[rootSvgRef]", ngImport: i0 }); }
236
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RootSvgReferenceDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
237
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: RootSvgReferenceDirective, isStandalone: true, selector: "svg[rootSvgRef]", ngImport: i0 }); }
245
238
  }
246
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RootSvgReferenceDirective, decorators: [{
239
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RootSvgReferenceDirective, decorators: [{
247
240
  type: Directive,
248
241
  args: [{
249
- selector: 'svg[rootSvgRef]'
242
+ standalone: true,
243
+ selector: 'svg[rootSvgRef]',
250
244
  }]
251
245
  }] });
252
246
 
@@ -307,12 +301,12 @@ class KeyboardService {
307
301
  isActiveAction(action) {
308
302
  return this.actionsActive[action];
309
303
  }
310
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: KeyboardService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
311
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: KeyboardService }); }
304
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: KeyboardService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
305
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: KeyboardService }); }
312
306
  }
313
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: KeyboardService, decorators: [{
307
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: KeyboardService, decorators: [{
314
308
  type: Injectable
315
- }], ctorParameters: function () { return []; } });
309
+ }], ctorParameters: () => [] });
316
310
 
317
311
  class SelectionService {
318
312
  constructor() {
@@ -353,10 +347,10 @@ class SelectionService {
353
347
  entity.selected.set(true);
354
348
  }
355
349
  }
356
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SelectionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
357
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SelectionService }); }
350
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
351
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectionService }); }
358
352
  }
359
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SelectionService, decorators: [{
353
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectionService, decorators: [{
360
354
  type: Injectable
361
355
  }] });
362
356
 
@@ -437,12 +431,15 @@ class MapContextDirective {
437
431
  .call(this.zoomBehavior)
438
432
  .on('dblclick.zoom', null);
439
433
  }
440
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MapContextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
441
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: MapContextDirective, selector: "g[mapContext]", ngImport: i0 }); }
434
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MapContextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
435
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: MapContextDirective, isStandalone: true, selector: "g[mapContext]", ngImport: i0 }); }
442
436
  }
443
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MapContextDirective, decorators: [{
437
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MapContextDirective, decorators: [{
444
438
  type: Directive,
445
- args: [{ selector: 'g[mapContext]' }]
439
+ args: [{
440
+ standalone: true,
441
+ selector: 'g[mapContext]',
442
+ }]
446
443
  }] });
447
444
  const mapTransformToViewportState = (transform) => ({ zoom: transform.k, x: transform.x, y: transform.y });
448
445
  const evTarget = (anyEvent) => {
@@ -530,10 +527,10 @@ class DraggableService {
530
527
  // we only can move current node if it's not selected
531
528
  : [model];
532
529
  }
533
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DraggableService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
534
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DraggableService }); }
530
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DraggableService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
531
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DraggableService }); }
535
532
  }
536
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DraggableService, decorators: [{
533
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DraggableService, decorators: [{
537
534
  type: Injectable
538
535
  }] });
539
536
  function moveNode(model, point) {
@@ -552,67 +549,85 @@ class EdgeTemplateDirective {
552
549
  constructor() {
553
550
  this.templateRef = inject(TemplateRef);
554
551
  }
555
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EdgeTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
556
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: EdgeTemplateDirective, selector: "ng-template[edge]", ngImport: i0 }); }
552
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
553
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: EdgeTemplateDirective, isStandalone: true, selector: "ng-template[edge]", ngImport: i0 }); }
557
554
  }
558
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EdgeTemplateDirective, decorators: [{
555
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeTemplateDirective, decorators: [{
559
556
  type: Directive,
560
- args: [{ selector: 'ng-template[edge]' }]
557
+ args: [{
558
+ standalone: true,
559
+ selector: 'ng-template[edge]',
560
+ }]
561
561
  }] });
562
562
  class ConnectionTemplateDirective {
563
563
  constructor() {
564
564
  this.templateRef = inject(TemplateRef);
565
565
  }
566
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ConnectionTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
567
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ConnectionTemplateDirective, selector: "ng-template[connection]", ngImport: i0 }); }
566
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConnectionTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
567
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: ConnectionTemplateDirective, isStandalone: true, selector: "ng-template[connection]", ngImport: i0 }); }
568
568
  }
569
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ConnectionTemplateDirective, decorators: [{
569
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConnectionTemplateDirective, decorators: [{
570
570
  type: Directive,
571
- args: [{ selector: 'ng-template[connection]' }]
571
+ args: [{
572
+ standalone: true,
573
+ selector: 'ng-template[connection]'
574
+ }]
572
575
  }] });
573
576
  class EdgeLabelHtmlTemplateDirective {
574
577
  constructor() {
575
578
  this.templateRef = inject(TemplateRef);
576
579
  }
577
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EdgeLabelHtmlTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
578
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: EdgeLabelHtmlTemplateDirective, selector: "ng-template[edgeLabelHtml]", ngImport: i0 }); }
580
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeLabelHtmlTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
581
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: EdgeLabelHtmlTemplateDirective, isStandalone: true, selector: "ng-template[edgeLabelHtml]", ngImport: i0 }); }
579
582
  }
580
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EdgeLabelHtmlTemplateDirective, decorators: [{
583
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeLabelHtmlTemplateDirective, decorators: [{
581
584
  type: Directive,
582
- args: [{ selector: 'ng-template[edgeLabelHtml]' }]
585
+ args: [{
586
+ standalone: true,
587
+ selector: 'ng-template[edgeLabelHtml]'
588
+ }]
583
589
  }] });
584
590
  class NodeHtmlTemplateDirective {
585
591
  constructor() {
586
592
  this.templateRef = inject(TemplateRef);
587
593
  }
588
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeHtmlTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
589
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: NodeHtmlTemplateDirective, selector: "ng-template[nodeHtml]", ngImport: i0 }); }
594
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeHtmlTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
595
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: NodeHtmlTemplateDirective, isStandalone: true, selector: "ng-template[nodeHtml]", ngImport: i0 }); }
590
596
  }
591
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeHtmlTemplateDirective, decorators: [{
597
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeHtmlTemplateDirective, decorators: [{
592
598
  type: Directive,
593
- args: [{ selector: 'ng-template[nodeHtml]' }]
599
+ args: [{
600
+ standalone: true,
601
+ selector: 'ng-template[nodeHtml]'
602
+ }]
594
603
  }] });
595
604
  class GroupNodeTemplateDirective {
596
605
  constructor() {
597
606
  this.templateRef = inject(TemplateRef);
598
607
  }
599
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: GroupNodeTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
600
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: GroupNodeTemplateDirective, selector: "ng-template[groupNode]", ngImport: i0 }); }
608
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: GroupNodeTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
609
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: GroupNodeTemplateDirective, isStandalone: true, selector: "ng-template[groupNode]", ngImport: i0 }); }
601
610
  }
602
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: GroupNodeTemplateDirective, decorators: [{
611
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: GroupNodeTemplateDirective, decorators: [{
603
612
  type: Directive,
604
- args: [{ selector: 'ng-template[groupNode]' }]
613
+ args: [{
614
+ standalone: true,
615
+ selector: 'ng-template[groupNode]'
616
+ }]
605
617
  }] });
606
618
  class HandleTemplateDirective {
607
619
  constructor() {
608
620
  this.templateRef = inject(TemplateRef);
609
621
  }
610
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
611
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: HandleTemplateDirective, selector: "ng-template[handle]", ngImport: i0 }); }
622
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
623
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: HandleTemplateDirective, isStandalone: true, selector: "ng-template[handle]", ngImport: i0 }); }
612
624
  }
613
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleTemplateDirective, decorators: [{
625
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleTemplateDirective, decorators: [{
614
626
  type: Directive,
615
- args: [{ selector: 'ng-template[handle]' }]
627
+ args: [{
628
+ standalone: true,
629
+ selector: 'ng-template[handle]'
630
+ }]
616
631
  }] });
617
632
 
618
633
  function addNodesToEdges(nodes, edges) {
@@ -642,10 +657,10 @@ class FlowStatusService {
642
657
  setConnectionEndStatus(source, target, sourceHandle, targetHandle) {
643
658
  this.status.set({ state: 'connection-end', payload: { source, target, sourceHandle, targetHandle } });
644
659
  }
645
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowStatusService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
646
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowStatusService }); }
660
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowStatusService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
661
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowStatusService }); }
647
662
  }
648
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowStatusService, decorators: [{
663
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowStatusService, decorators: [{
649
664
  type: Injectable
650
665
  }] });
651
666
  /**
@@ -703,7 +718,7 @@ class ConnectionControllerDirective {
703
718
  * Also it's important to note, that this event only fires when connection is valid by validator function in `ConnectionSettings`,
704
719
  * by default without passing the validator every connection concidered valid.
705
720
  */
706
- this.onConnect = new EventEmitter();
721
+ this.onConnect = output();
707
722
  this.statusService = inject(FlowStatusService);
708
723
  this.flowEntitiesService = inject(FlowEntitiesService);
709
724
  this.connectEffect = effect(() => {
@@ -718,7 +733,7 @@ class ConnectionControllerDirective {
718
733
  source: status.payload.source,
719
734
  sourceHandle: status.payload.sourceHandle,
720
735
  target: status.payload.target,
721
- targetHandle: status.payload.targetHandle
736
+ targetHandle: status.payload.targetHandle,
722
737
  });
723
738
  source = adjusted.source;
724
739
  target = adjusted.target;
@@ -731,8 +746,10 @@ class ConnectionControllerDirective {
731
746
  const targetHandleId = targetHandle.rawHandle.id;
732
747
  const connectionModel = this.flowEntitiesService.connection();
733
748
  const connection = {
734
- source: sourceId, target: targetId,
735
- sourceHandle: sourceHandleId, targetHandle: targetHandleId
749
+ source: sourceId,
750
+ target: targetId,
751
+ sourceHandle: sourceHandleId,
752
+ targetHandle: targetHandleId,
736
753
  };
737
754
  if (connectionModel.validator(connection)) {
738
755
  this.onConnect.emit(connection);
@@ -757,7 +774,7 @@ class ConnectionControllerDirective {
757
774
  source: status.payload.source,
758
775
  sourceHandle: status.payload.sourceHandle,
759
776
  target: handle.parentNode,
760
- targetHandle: handle
777
+ targetHandle: handle,
761
778
  });
762
779
  source = adjusted.source;
763
780
  target = adjusted.target;
@@ -768,7 +785,7 @@ class ConnectionControllerDirective {
768
785
  source: source.node.id,
769
786
  target: target.node.id,
770
787
  sourceHandle: sourceHandle.rawHandle.id,
771
- targetHandle: targetHandle.rawHandle.id
788
+ targetHandle: targetHandle.rawHandle.id,
772
789
  });
773
790
  // TODO: check how react flow handles highlight of handle
774
791
  // if direction changes
@@ -800,18 +817,16 @@ class ConnectionControllerDirective {
800
817
  () => this.statusService.setIdleStatus());
801
818
  }
802
819
  }
803
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ConnectionControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
804
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ConnectionControllerDirective, isStandalone: true, selector: "[connectionController]", outputs: { onConnect: "onConnect" }, ngImport: i0 }); }
820
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConnectionControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
821
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: ConnectionControllerDirective, isStandalone: true, selector: "[connectionController]", outputs: { onConnect: "onConnect" }, ngImport: i0 }); }
805
822
  }
806
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ConnectionControllerDirective, decorators: [{
823
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConnectionControllerDirective, decorators: [{
807
824
  type: Directive,
808
825
  args: [{
809
826
  selector: '[connectionController]',
810
- standalone: true
827
+ standalone: true,
811
828
  }]
812
- }], propDecorators: { onConnect: [{
813
- type: Output
814
- }] } });
829
+ }] });
815
830
 
816
831
  class ComponentEventBusService {
817
832
  constructor() {
@@ -821,89 +836,120 @@ class ComponentEventBusService {
821
836
  pushEvent(event) {
822
837
  this._event$.next(event);
823
838
  }
824
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ComponentEventBusService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
825
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ComponentEventBusService }); }
839
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ComponentEventBusService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
840
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ComponentEventBusService }); }
841
+ }
842
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ComponentEventBusService, decorators: [{
843
+ type: Injectable
844
+ }] });
845
+
846
+ /**
847
+ * Service to fix cyclic dependency between node and resizable component
848
+ */
849
+ class NodeAccessorService {
850
+ constructor() {
851
+ this.model = signal(null);
852
+ }
853
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeAccessorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
854
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeAccessorService }); }
826
855
  }
827
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ComponentEventBusService, decorators: [{
856
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeAccessorService, decorators: [{
828
857
  type: Injectable
829
858
  }] });
830
859
 
831
860
  class CustomNodeBaseComponent {
832
861
  constructor() {
833
862
  this.eventBus = inject(ComponentEventBusService);
863
+ this.nodeService = inject(NodeAccessorService);
834
864
  this.destroyRef = inject(DestroyRef);
835
865
  /**
836
866
  * Signal with selected state of node
837
867
  */
838
- this.selected = signal(false);
868
+ this.selected = this.nodeService.model().selected;
839
869
  this.data = signal(undefined);
840
870
  }
841
- set _selected(value) {
842
- this.selected.set(value);
843
- }
844
871
  ngOnInit() {
845
- this.trackEvents()
846
- .pipe(takeUntilDestroyed(this.destroyRef))
847
- .subscribe();
872
+ this.trackEvents().pipe(takeUntilDestroyed(this.destroyRef)).subscribe();
848
873
  }
849
874
  trackEvents() {
850
875
  const props = Object.getOwnPropertyNames(this);
851
- const emitters = new Map();
876
+ const emittersOrRefs = new Map();
852
877
  for (const prop of props) {
853
878
  const field = this[prop];
854
879
  if (field instanceof EventEmitter) {
855
- emitters.set(field, prop);
880
+ emittersOrRefs.set(field, prop);
881
+ }
882
+ if (field instanceof OutputEmitterRef) {
883
+ emittersOrRefs.set(outputRefToObservable(field), prop);
856
884
  }
857
885
  }
858
- return merge(...Array.from(emitters.keys()).map(emitter => emitter.pipe(tap((event) => {
886
+ return merge(...Array.from(emittersOrRefs.keys()).map((emitter) => emitter.pipe(tap((event) => {
859
887
  this.eventBus.pushEvent({
860
- nodeId: this.node.id,
861
- eventName: emitters.get(emitter),
862
- eventPayload: event
888
+ nodeId: this.nodeService.model()?.node.id ?? '',
889
+ eventName: emittersOrRefs.get(emitter),
890
+ eventPayload: event,
863
891
  });
864
892
  }))));
865
893
  }
866
- ;
867
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CustomNodeBaseComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
868
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: CustomNodeBaseComponent, inputs: { _selected: "_selected" }, ngImport: i0 }); }
894
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CustomNodeBaseComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
895
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: CustomNodeBaseComponent, ngImport: i0 }); }
869
896
  }
870
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CustomNodeBaseComponent, decorators: [{
897
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CustomNodeBaseComponent, decorators: [{
871
898
  type: Directive
872
- }], propDecorators: { _selected: [{
873
- type: Input
874
- }] } });
899
+ }] });
900
+ function outputRefToObservable(ref) {
901
+ return new Observable((subscriber) => {
902
+ const subscription = ref.subscribe((value) => {
903
+ subscriber.next(value);
904
+ });
905
+ return () => {
906
+ subscription.unsubscribe();
907
+ };
908
+ });
909
+ }
875
910
 
876
911
  class CustomNodeComponent extends CustomNodeBaseComponent {
912
+ constructor() {
913
+ super(...arguments);
914
+ /**
915
+ * Reference to node bound to this component
916
+ */
917
+ this.node = input.required();
918
+ }
877
919
  ngOnInit() {
878
- if (this.node.data) {
879
- this.data.set(this.node.data);
920
+ if (this.node().data) {
921
+ this.data.set(this.node().data);
880
922
  }
881
923
  super.ngOnInit();
882
924
  }
883
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CustomNodeComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
884
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: CustomNodeComponent, inputs: { node: "node" }, usesInheritance: true, ngImport: i0 }); }
925
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CustomNodeComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
926
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "17.3.12", type: CustomNodeComponent, inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0 }); }
885
927
  }
886
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CustomNodeComponent, decorators: [{
928
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CustomNodeComponent, decorators: [{
887
929
  type: Directive
888
- }], propDecorators: { node: [{
889
- type: Input
890
- }] } });
930
+ }] });
891
931
 
892
932
  class CustomDynamicNodeComponent extends CustomNodeBaseComponent {
933
+ constructor() {
934
+ super(...arguments);
935
+ /**
936
+ * Reference to node bound to this component
937
+ */
938
+ this.node = input.required();
939
+ }
893
940
  ngOnInit() {
894
- if (this.node.data) {
895
- this.data = this.node.data;
941
+ const data = this.node().data;
942
+ if (data) {
943
+ this.data = data;
896
944
  }
897
945
  super.ngOnInit();
898
946
  }
899
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CustomDynamicNodeComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
900
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: CustomDynamicNodeComponent, inputs: { node: "node" }, usesInheritance: true, ngImport: i0 }); }
947
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CustomDynamicNodeComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
948
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "17.3.12", type: CustomDynamicNodeComponent, inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0 }); }
901
949
  }
902
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CustomDynamicNodeComponent, decorators: [{
950
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CustomDynamicNodeComponent, decorators: [{
903
951
  type: Directive
904
- }], propDecorators: { node: [{
905
- type: Input
906
- }] } });
952
+ }] });
907
953
 
908
954
  function isStaticNode(node) {
909
955
  return typeof node.point !== 'function';
@@ -977,9 +1023,6 @@ class NodeModel {
977
1023
  return { x, y };
978
1024
  });
979
1025
  this.pointTransform = computed(() => `translate(${this.globalPoint().x}, ${this.globalPoint().y})`);
980
- // Now source and handle positions derived from parent flow
981
- this.sourcePosition = computed(() => this.flowSettingsService.handlePositions().source);
982
- this.targetPosition = computed(() => this.flowSettingsService.handlePositions().target);
983
1026
  this.handles = signal([]);
984
1027
  this.handles$ = toObservable(this.handles);
985
1028
  this.draggable = signal(true);
@@ -992,12 +1035,9 @@ class NodeModel {
992
1035
  // Default node specific thing
993
1036
  this.text = this.createTextSignal();
994
1037
  // Component node specific thing
995
- this.componentTypeInputs = computed(() => {
996
- return {
997
- node: this.node,
998
- _selected: this.selected()
999
- };
1000
- });
1038
+ this.componentTypeInputs = {
1039
+ node: this.node,
1040
+ };
1001
1041
  this.parent = computed(() => this.entitiesService.nodes().find(n => n.node.id === this.parentId()) ?? null);
1002
1042
  this.children = computed(() => this.entitiesService.nodes().filter(n => n.parentId() === this.node.id));
1003
1043
  this.color = signal(NodeModel.defaultColor);
@@ -1213,6 +1253,176 @@ function getPointOnBezier(sourcePoint, targetPoint, sourceControl, targetControl
1213
1253
  return getPointOnLineByRatio(getPointOnLineByRatio(fromSourceToFirstControl, fromFirstControlToSecond, ratio), getPointOnLineByRatio(fromFirstControlToSecond, fromSecondControlToTarget, ratio), ratio);
1214
1254
  }
1215
1255
 
1256
+ const handleDirections = {
1257
+ left: { x: -1, y: 0 },
1258
+ right: { x: 1, y: 0 },
1259
+ top: { x: 0, y: -1 },
1260
+ bottom: { x: 0, y: 1 },
1261
+ };
1262
+ function getEdgeCenter(source, target) {
1263
+ const xOffset = Math.abs(target.x - source.x) / 2;
1264
+ const centerX = target.x < source.x ? target.x + xOffset : target.x - xOffset;
1265
+ const yOffset = Math.abs(target.y - source.y) / 2;
1266
+ const centerY = target.y < source.y ? target.y + yOffset : target.y - yOffset;
1267
+ return [centerX, centerY, xOffset, yOffset];
1268
+ }
1269
+ const getDirection = ({ source, sourcePosition = 'bottom', target, }) => {
1270
+ if (sourcePosition === 'left' || sourcePosition === 'right') {
1271
+ return source.x < target.x ? { x: 1, y: 0 } : { x: -1, y: 0 };
1272
+ }
1273
+ return source.y < target.y ? { x: 0, y: 1 } : { x: 0, y: -1 };
1274
+ };
1275
+ const distance = (a, b) => Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));
1276
+ // ith this function we try to mimic a orthogonal edge routing behaviour
1277
+ // It's not as good as a real orthogonal edge routing but it's faster and good enough as a default for step and smooth step edges
1278
+ function getPoints({ source, sourcePosition = 'bottom', target, targetPosition = 'top', offset, }) {
1279
+ const sourceDir = handleDirections[sourcePosition];
1280
+ const targetDir = handleDirections[targetPosition];
1281
+ const sourceGapped = { x: source.x + sourceDir.x * offset, y: source.y + sourceDir.y * offset };
1282
+ const targetGapped = { x: target.x + targetDir.x * offset, y: target.y + targetDir.y * offset };
1283
+ const dir = getDirection({
1284
+ source: sourceGapped,
1285
+ sourcePosition,
1286
+ target: targetGapped,
1287
+ });
1288
+ const dirAccessor = dir.x !== 0 ? 'x' : 'y';
1289
+ const currDir = dir[dirAccessor];
1290
+ let points = [];
1291
+ let centerX, centerY;
1292
+ const sourceGapOffset = { x: 0, y: 0 };
1293
+ const targetGapOffset = { x: 0, y: 0 };
1294
+ const [defaultCenterX, defaultCenterY] = getEdgeCenter(source, target);
1295
+ // opposite handle positions, default case
1296
+ if (sourceDir[dirAccessor] * targetDir[dirAccessor] === -1) {
1297
+ centerX = defaultCenterX;
1298
+ centerY = defaultCenterY;
1299
+ // --->
1300
+ // |
1301
+ // >---
1302
+ const verticalSplit = [
1303
+ { x: centerX, y: sourceGapped.y },
1304
+ { x: centerX, y: targetGapped.y },
1305
+ ];
1306
+ // |
1307
+ // ---
1308
+ // |
1309
+ const horizontalSplit = [
1310
+ { x: sourceGapped.x, y: centerY },
1311
+ { x: targetGapped.x, y: centerY },
1312
+ ];
1313
+ if (sourceDir[dirAccessor] === currDir) {
1314
+ points = dirAccessor === 'x' ? verticalSplit : horizontalSplit;
1315
+ }
1316
+ else {
1317
+ points = dirAccessor === 'x' ? horizontalSplit : verticalSplit;
1318
+ }
1319
+ }
1320
+ else {
1321
+ // sourceTarget means we take x from source and y from target, targetSource is the opposite
1322
+ const sourceTarget = [{ x: sourceGapped.x, y: targetGapped.y }];
1323
+ const targetSource = [{ x: targetGapped.x, y: sourceGapped.y }];
1324
+ // this handles edges with same handle positions
1325
+ if (dirAccessor === 'x') {
1326
+ points = sourceDir.x === currDir ? targetSource : sourceTarget;
1327
+ }
1328
+ else {
1329
+ points = sourceDir.y === currDir ? sourceTarget : targetSource;
1330
+ }
1331
+ if (sourcePosition === targetPosition) {
1332
+ const diff = Math.abs(source[dirAccessor] - target[dirAccessor]);
1333
+ // if an edge goes from right to right for example (sourcePosition === targetPosition) and the distance between source.x and target.x is less than the offset, the added point and the gapped source/target will overlap. This leads to a weird edge path. To avoid this we add a gapOffset to the source/target
1334
+ if (diff <= offset) {
1335
+ const gapOffset = Math.min(offset - 1, offset - diff);
1336
+ if (sourceDir[dirAccessor] === currDir) {
1337
+ sourceGapOffset[dirAccessor] = (sourceGapped[dirAccessor] > source[dirAccessor] ? -1 : 1) * gapOffset;
1338
+ }
1339
+ else {
1340
+ targetGapOffset[dirAccessor] = (targetGapped[dirAccessor] > target[dirAccessor] ? -1 : 1) * gapOffset;
1341
+ }
1342
+ }
1343
+ }
1344
+ // these are conditions for handling mixed handle positions like Right -> Bottom for example
1345
+ if (sourcePosition !== targetPosition) {
1346
+ const dirAccessorOpposite = dirAccessor === 'x' ? 'y' : 'x';
1347
+ const isSameDir = sourceDir[dirAccessor] === targetDir[dirAccessorOpposite];
1348
+ const sourceGtTargetOppo = sourceGapped[dirAccessorOpposite] > targetGapped[dirAccessorOpposite];
1349
+ const sourceLtTargetOppo = sourceGapped[dirAccessorOpposite] < targetGapped[dirAccessorOpposite];
1350
+ const flipSourceTarget = (sourceDir[dirAccessor] === 1 && ((!isSameDir && sourceGtTargetOppo) || (isSameDir && sourceLtTargetOppo))) ||
1351
+ (sourceDir[dirAccessor] !== 1 && ((!isSameDir && sourceLtTargetOppo) || (isSameDir && sourceGtTargetOppo)));
1352
+ if (flipSourceTarget) {
1353
+ points = dirAccessor === 'x' ? sourceTarget : targetSource;
1354
+ }
1355
+ }
1356
+ const sourceGapPoint = { x: sourceGapped.x + sourceGapOffset.x, y: sourceGapped.y + sourceGapOffset.y };
1357
+ const targetGapPoint = { x: targetGapped.x + targetGapOffset.x, y: targetGapped.y + targetGapOffset.y };
1358
+ const maxXDistance = Math.max(Math.abs(sourceGapPoint.x - points[0].x), Math.abs(targetGapPoint.x - points[0].x));
1359
+ const maxYDistance = Math.max(Math.abs(sourceGapPoint.y - points[0].y), Math.abs(targetGapPoint.y - points[0].y));
1360
+ // we want to place the label on the longest segment of the edge
1361
+ if (maxXDistance >= maxYDistance) {
1362
+ centerX = (sourceGapPoint.x + targetGapPoint.x) / 2;
1363
+ centerY = points[0].y;
1364
+ }
1365
+ else {
1366
+ centerX = points[0].x;
1367
+ centerY = (sourceGapPoint.y + targetGapPoint.y) / 2;
1368
+ }
1369
+ }
1370
+ const pathPoints = [
1371
+ source,
1372
+ { x: sourceGapped.x + sourceGapOffset.x, y: sourceGapped.y + sourceGapOffset.y },
1373
+ ...points,
1374
+ { x: targetGapped.x + targetGapOffset.x, y: targetGapped.y + targetGapOffset.y },
1375
+ target,
1376
+ ];
1377
+ return [pathPoints, centerX, centerY];
1378
+ }
1379
+ function getBend(a, b, c, size) {
1380
+ const bendSize = Math.min(distance(a, b) / 2, distance(b, c) / 2, size);
1381
+ const { x, y } = b;
1382
+ // no bend
1383
+ if ((a.x === x && x === c.x) || (a.y === y && y === c.y)) {
1384
+ return `L${x} ${y}`;
1385
+ }
1386
+ // first segment is horizontal
1387
+ if (a.y === y) {
1388
+ const xDir = a.x < c.x ? -1 : 1;
1389
+ const yDir = a.y < c.y ? 1 : -1;
1390
+ return `L ${x + bendSize * xDir},${y}Q ${x},${y} ${x},${y + bendSize * yDir}`;
1391
+ }
1392
+ const xDir = a.x < c.x ? 1 : -1;
1393
+ const yDir = a.y < c.y ? -1 : 1;
1394
+ return `L ${x},${y + bendSize * yDir}Q ${x},${y} ${x + bendSize * xDir},${y}`;
1395
+ }
1396
+ function smoothStepPath(source, target, sourcePosition, targetPosition, borderRadius = 5) {
1397
+ const [points, labelX, labelY] = getPoints({
1398
+ source,
1399
+ sourcePosition,
1400
+ target,
1401
+ targetPosition,
1402
+ offset: 20
1403
+ });
1404
+ const path = points.reduce((res, p, i) => {
1405
+ let segment = '';
1406
+ if (i > 0 && i < points.length - 1) {
1407
+ segment = getBend(points[i - 1], p, points[i + 1], borderRadius);
1408
+ }
1409
+ else {
1410
+ segment = `${i === 0 ? 'M' : 'L'}${p.x} ${p.y}`;
1411
+ }
1412
+ res += segment;
1413
+ return res;
1414
+ }, '');
1415
+ return {
1416
+ path,
1417
+ points: {
1418
+ // TODO start and end points temporary unavailable for this path
1419
+ start: { x: labelX, y: labelY },
1420
+ center: { x: labelX, y: labelY },
1421
+ end: { x: labelX, y: labelY },
1422
+ }
1423
+ };
1424
+ }
1425
+
1216
1426
  class EdgeModel {
1217
1427
  constructor(edge) {
1218
1428
  this.edge = edge;
@@ -1282,6 +1492,10 @@ class EdgeModel {
1282
1492
  return straightPath(source.pointAbsolute(), target.pointAbsolute(), this.usingPoints);
1283
1493
  case 'bezier':
1284
1494
  return bezierPath(source.pointAbsolute(), target.pointAbsolute(), source.rawHandle.position, target.rawHandle.position, this.usingPoints);
1495
+ case 'smooth-step':
1496
+ return smoothStepPath(source.pointAbsolute(), target.pointAbsolute(), source.rawHandle.position, target.rawHandle.position);
1497
+ case 'step':
1498
+ return smoothStepPath(source.pointAbsolute(), target.pointAbsolute(), source.rawHandle.position, target.rawHandle.position, 0);
1285
1499
  }
1286
1500
  });
1287
1501
  this.edgeLabels = {};
@@ -1359,10 +1573,10 @@ class NodesChangeService {
1359
1573
  // you can't get valid list of detached edges
1360
1574
  observeOn(asyncScheduler, DELAY_FOR_SCHEDULER));
1361
1575
  }
1362
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodesChangeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1363
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodesChangeService }); }
1576
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodesChangeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1577
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodesChangeService }); }
1364
1578
  }
1365
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodesChangeService, decorators: [{
1579
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodesChangeService, decorators: [{
1366
1580
  type: Injectable
1367
1581
  }] });
1368
1582
 
@@ -1403,10 +1617,10 @@ class EdgeChangesService {
1403
1617
  // right after [nodes] input change
1404
1618
  observeOn(asyncScheduler));
1405
1619
  }
1406
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EdgeChangesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1407
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EdgeChangesService }); }
1620
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeChangesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1621
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeChangesService }); }
1408
1622
  }
1409
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EdgeChangesService, decorators: [{
1623
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeChangesService, decorators: [{
1410
1624
  type: Injectable
1411
1625
  }] });
1412
1626
 
@@ -1417,146 +1631,65 @@ class ChangesControllerDirective {
1417
1631
  /**
1418
1632
  * Watch nodes change
1419
1633
  */
1420
- this.onNodesChange = this.nodesChangeService.changes$;
1421
- this.onNodesChangePosition = this.nodeChangesOfType('position');
1422
- this.onNodesChangePositionSignle = this.singleChange(this.nodeChangesOfType('position'));
1423
- this.onNodesChangePositionMany = this.manyChanges(this.nodeChangesOfType('position'));
1424
- this.onNodesChangeSize = this.nodeChangesOfType('size');
1425
- this.onNodesChangeSizeSingle = this.singleChange(this.nodeChangesOfType('size'));
1426
- this.onNodesChangeSizeMany = this.manyChanges(this.nodeChangesOfType('size'));
1427
- this.onNodesChangeAdd = this.nodeChangesOfType('add');
1428
- this.onNodesChangeAddSingle = this.singleChange(this.nodeChangesOfType('add'));
1429
- this.onNodesChangeAddMany = this.manyChanges(this.nodeChangesOfType('add'));
1430
- this.onNodesChangeRemove = this.nodeChangesOfType('remove');
1431
- this.onNodesChangeRemoveSingle = this.singleChange(this.nodeChangesOfType('remove'));
1432
- this.onNodesChangeRemoveMany = this.manyChanges(this.nodeChangesOfType('remove'));
1433
- this.onNodesChangeSelect = this.nodeChangesOfType('select');
1434
- this.onNodesChangeSelectSingle = this.singleChange(this.nodeChangesOfType('select'));
1435
- this.onNodesChangeSelectMany = this.manyChanges(this.nodeChangesOfType('select'));
1634
+ this.onNodesChange = outputFromObservable(this.nodesChangeService.changes$);
1635
+ this.onNodesChangePosition = outputFromObservable(this.nodeChangesOfType('position'), { alias: 'onNodesChange.position' });
1636
+ this.onNodesChangePositionSignle = outputFromObservable(this.singleChange(this.nodeChangesOfType('position')), { alias: 'onNodesChange.position.single' });
1637
+ this.onNodesChangePositionMany = outputFromObservable(this.manyChanges(this.nodeChangesOfType('position')), { alias: 'onNodesChange.position.many' });
1638
+ this.onNodesChangeSize = outputFromObservable(this.nodeChangesOfType('size'), { alias: 'onNodesChange.size' });
1639
+ this.onNodesChangeSizeSingle = outputFromObservable(this.singleChange(this.nodeChangesOfType('size')), { alias: 'onNodesChange.size.single' });
1640
+ this.onNodesChangeSizeMany = outputFromObservable(this.manyChanges(this.nodeChangesOfType('size')), { alias: 'onNodesChange.size.many' });
1641
+ this.onNodesChangeAdd = outputFromObservable(this.nodeChangesOfType('add'), { alias: 'onNodesChange.add' });
1642
+ this.onNodesChangeAddSingle = outputFromObservable(this.singleChange(this.nodeChangesOfType('add')), { alias: 'onNodesChange.add.single' });
1643
+ this.onNodesChangeAddMany = outputFromObservable(this.manyChanges(this.nodeChangesOfType('add')), { alias: 'onNodesChange.add.many' });
1644
+ this.onNodesChangeRemove = outputFromObservable(this.nodeChangesOfType('remove'), { alias: 'onNodesChange.remove' });
1645
+ this.onNodesChangeRemoveSingle = outputFromObservable(this.singleChange(this.nodeChangesOfType('remove')), { alias: 'onNodesChange.remove.single' });
1646
+ this.onNodesChangeRemoveMany = outputFromObservable(this.manyChanges(this.nodeChangesOfType('remove')), { alias: 'onNodesChange.remove.many' });
1647
+ this.onNodesChangeSelect = outputFromObservable(this.nodeChangesOfType('select'), { alias: 'onNodesChange.select' });
1648
+ this.onNodesChangeSelectSingle = outputFromObservable(this.singleChange(this.nodeChangesOfType('select')), { alias: 'onNodesChange.select.single' });
1649
+ this.onNodesChangeSelectMany = outputFromObservable(this.manyChanges(this.nodeChangesOfType('select')), { alias: 'onNodesChange.select.many' });
1436
1650
  /**
1437
1651
  * Watch edges change
1438
1652
  */
1439
- this.onEdgesChange = this.edgesChangeService.changes$;
1440
- this.onNodesChangeDetached = this.edgeChangesOfType('detached');
1441
- this.onNodesChangeDetachedSingle = this.singleChange(this.edgeChangesOfType('detached'));
1442
- this.onNodesChangeDetachedMany = this.manyChanges(this.edgeChangesOfType('detached'));
1443
- this.onEdgesChangeAdd = this.edgeChangesOfType('add');
1444
- this.onEdgeChangeAddSingle = this.singleChange(this.edgeChangesOfType('add'));
1445
- this.onEdgeChangeAddMany = this.manyChanges(this.edgeChangesOfType('add'));
1446
- this.onEdgeChangeRemove = this.edgeChangesOfType('remove');
1447
- this.onEdgeChangeRemoveSingle = this.singleChange(this.edgeChangesOfType('remove'));
1448
- this.onEdgeChangeRemoveMany = this.manyChanges(this.edgeChangesOfType('remove'));
1449
- this.onEdgeChangeSelect = this.edgeChangesOfType('select');
1450
- this.onEdgeChangeSelectSingle = this.singleChange(this.edgeChangesOfType('select'));
1451
- this.onEdgeChangeSelectMany = this.manyChanges(this.edgeChangesOfType('select'));
1653
+ this.onEdgesChange = outputFromObservable(this.edgesChangeService.changes$);
1654
+ this.onNodesChangeDetached = outputFromObservable(this.edgeChangesOfType('detached'), { alias: 'onEdgesChange.detached' });
1655
+ this.onNodesChangeDetachedSingle = outputFromObservable(this.singleChange(this.edgeChangesOfType('detached')), { alias: 'onEdgesChange.detached.single' });
1656
+ this.onNodesChangeDetachedMany = outputFromObservable(this.manyChanges(this.edgeChangesOfType('detached')), { alias: 'onEdgesChange.detached.many' });
1657
+ this.onEdgesChangeAdd = outputFromObservable(this.edgeChangesOfType('add'), { alias: 'onEdgesChange.add' });
1658
+ this.onEdgeChangeAddSingle = outputFromObservable(this.singleChange(this.edgeChangesOfType('add')), { alias: 'onEdgesChange.add.single' });
1659
+ this.onEdgeChangeAddMany = outputFromObservable(this.manyChanges(this.edgeChangesOfType('add')), { alias: 'onEdgesChange.add.many' });
1660
+ this.onEdgeChangeRemove = outputFromObservable(this.edgeChangesOfType('remove'), { alias: 'onEdgesChange.remove' });
1661
+ this.onEdgeChangeRemoveSingle = outputFromObservable(this.singleChange(this.edgeChangesOfType('remove')), { alias: 'onEdgesChange.remove.single' });
1662
+ this.onEdgeChangeRemoveMany = outputFromObservable(this.manyChanges(this.edgeChangesOfType('remove')), { alias: 'onEdgesChange.remove.many' });
1663
+ this.onEdgeChangeSelect = outputFromObservable(this.edgeChangesOfType('select'), { alias: 'onEdgesChange.select' });
1664
+ this.onEdgeChangeSelectSingle = outputFromObservable(this.singleChange(this.edgeChangesOfType('select')), { alias: 'onEdgesChange.select.single' });
1665
+ this.onEdgeChangeSelectMany = outputFromObservable(this.manyChanges(this.edgeChangesOfType('select')), { alias: 'onEdgesChange.select.many' });
1452
1666
  }
1453
1667
  nodeChangesOfType(type) {
1454
- return this.nodesChangeService.changes$.pipe(map(changes => changes.filter((c) => c.type === type)), filter(changes => !!changes.length));
1668
+ return this.nodesChangeService.changes$.pipe(map((changes) => changes.filter((c) => c.type === type)), filter((changes) => !!changes.length));
1455
1669
  }
1456
1670
  edgeChangesOfType(type) {
1457
- return this.edgesChangeService.changes$.pipe(map(changes => changes.filter((c) => c.type === type)), filter(changes => !!changes.length));
1671
+ return this.edgesChangeService.changes$.pipe(map((changes) => changes.filter((c) => c.type === type)), filter((changes) => !!changes.length));
1458
1672
  }
1459
1673
  singleChange(changes$) {
1460
- return changes$.pipe(filter(changes => changes.length === 1), map(([first]) => first));
1674
+ return changes$.pipe(filter((changes) => changes.length === 1), map(([first]) => first));
1461
1675
  }
1462
1676
  manyChanges(changes$) {
1463
- return changes$.pipe(filter(changes => changes.length > 1));
1677
+ return changes$.pipe(filter((changes) => changes.length > 1));
1464
1678
  }
1465
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ChangesControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1466
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ChangesControllerDirective, isStandalone: true, selector: "[changesController]", outputs: { onNodesChange: "onNodesChange", onNodesChangePosition: "onNodesChange.position", onNodesChangePositionSignle: "onNodesChange.position.single", onNodesChangePositionMany: "onNodesChange.position.many", onNodesChangeSize: "onNodesChange.size", onNodesChangeSizeSingle: "onNodesChange.size.single", onNodesChangeSizeMany: "onNodesChange.size.many", onNodesChangeAdd: "onNodesChange.add", onNodesChangeAddSingle: "onNodesChange.add.single", onNodesChangeAddMany: "onNodesChange.add.many", onNodesChangeRemove: "onNodesChange.remove", onNodesChangeRemoveSingle: "onNodesChange.remove.single", onNodesChangeRemoveMany: "onNodesChange.remove.many", onNodesChangeSelect: "onNodesChange.select", onNodesChangeSelectSingle: "onNodesChange.select.single", onNodesChangeSelectMany: "onNodesChange.select.many", onEdgesChange: "onEdgesChange", onNodesChangeDetached: "onEdgesChange.detached", onNodesChangeDetachedSingle: "onEdgesChange.detached.single", onNodesChangeDetachedMany: "onEdgesChange.detached.many", onEdgesChangeAdd: "onEdgesChange.add", onEdgeChangeAddSingle: "onEdgesChange.add.single", onEdgeChangeAddMany: "onEdgesChange.add.many", onEdgeChangeRemove: "onEdgesChange.remove", onEdgeChangeRemoveSingle: "onEdgesChange.remove.single", onEdgeChangeRemoveMany: "onEdgesChange.remove.many", onEdgeChangeSelect: "onEdgesChange.select", onEdgeChangeSelectSingle: "onEdgesChange.select.single", onEdgeChangeSelectMany: "onEdgesChange.select.many" }, ngImport: i0 }); }
1679
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChangesControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1680
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: ChangesControllerDirective, isStandalone: true, selector: "[changesController]", outputs: { onNodesChange: "onNodesChange", onNodesChangePosition: "onNodesChange.position", onNodesChangePositionSignle: "onNodesChange.position.single", onNodesChangePositionMany: "onNodesChange.position.many", onNodesChangeSize: "onNodesChange.size", onNodesChangeSizeSingle: "onNodesChange.size.single", onNodesChangeSizeMany: "onNodesChange.size.many", onNodesChangeAdd: "onNodesChange.add", onNodesChangeAddSingle: "onNodesChange.add.single", onNodesChangeAddMany: "onNodesChange.add.many", onNodesChangeRemove: "onNodesChange.remove", onNodesChangeRemoveSingle: "onNodesChange.remove.single", onNodesChangeRemoveMany: "onNodesChange.remove.many", onNodesChangeSelect: "onNodesChange.select", onNodesChangeSelectSingle: "onNodesChange.select.single", onNodesChangeSelectMany: "onNodesChange.select.many", onEdgesChange: "onEdgesChange", onNodesChangeDetached: "onEdgesChange.detached", onNodesChangeDetachedSingle: "onEdgesChange.detached.single", onNodesChangeDetachedMany: "onEdgesChange.detached.many", onEdgesChangeAdd: "onEdgesChange.add", onEdgeChangeAddSingle: "onEdgesChange.add.single", onEdgeChangeAddMany: "onEdgesChange.add.many", onEdgeChangeRemove: "onEdgesChange.remove", onEdgeChangeRemoveSingle: "onEdgesChange.remove.single", onEdgeChangeRemoveMany: "onEdgesChange.remove.many", onEdgeChangeSelect: "onEdgesChange.select", onEdgeChangeSelectSingle: "onEdgesChange.select.single", onEdgeChangeSelectMany: "onEdgesChange.select.many" }, ngImport: i0 }); }
1467
1681
  }
1468
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ChangesControllerDirective, decorators: [{
1682
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChangesControllerDirective, decorators: [{
1469
1683
  type: Directive,
1470
1684
  args: [{
1471
1685
  selector: '[changesController]',
1472
- standalone: true
1686
+ standalone: true,
1473
1687
  }]
1474
- }], propDecorators: { onNodesChange: [{
1475
- type: Output
1476
- }], onNodesChangePosition: [{
1477
- type: Output,
1478
- args: ['onNodesChange.position']
1479
- }], onNodesChangePositionSignle: [{
1480
- type: Output,
1481
- args: ['onNodesChange.position.single']
1482
- }], onNodesChangePositionMany: [{
1483
- type: Output,
1484
- args: ['onNodesChange.position.many']
1485
- }], onNodesChangeSize: [{
1486
- type: Output,
1487
- args: ['onNodesChange.size']
1488
- }], onNodesChangeSizeSingle: [{
1489
- type: Output,
1490
- args: ['onNodesChange.size.single']
1491
- }], onNodesChangeSizeMany: [{
1492
- type: Output,
1493
- args: ['onNodesChange.size.many']
1494
- }], onNodesChangeAdd: [{
1495
- type: Output,
1496
- args: ['onNodesChange.add']
1497
- }], onNodesChangeAddSingle: [{
1498
- type: Output,
1499
- args: ['onNodesChange.add.single']
1500
- }], onNodesChangeAddMany: [{
1501
- type: Output,
1502
- args: ['onNodesChange.add.many']
1503
- }], onNodesChangeRemove: [{
1504
- type: Output,
1505
- args: ['onNodesChange.remove']
1506
- }], onNodesChangeRemoveSingle: [{
1507
- type: Output,
1508
- args: ['onNodesChange.remove.single']
1509
- }], onNodesChangeRemoveMany: [{
1510
- type: Output,
1511
- args: ['onNodesChange.remove.many']
1512
- }], onNodesChangeSelect: [{
1513
- type: Output,
1514
- args: ['onNodesChange.select']
1515
- }], onNodesChangeSelectSingle: [{
1516
- type: Output,
1517
- args: ['onNodesChange.select.single']
1518
- }], onNodesChangeSelectMany: [{
1519
- type: Output,
1520
- args: ['onNodesChange.select.many']
1521
- }], onEdgesChange: [{
1522
- type: Output
1523
- }], onNodesChangeDetached: [{
1524
- type: Output,
1525
- args: ['onEdgesChange.detached']
1526
- }], onNodesChangeDetachedSingle: [{
1527
- type: Output,
1528
- args: ['onEdgesChange.detached.single']
1529
- }], onNodesChangeDetachedMany: [{
1530
- type: Output,
1531
- args: ['onEdgesChange.detached.many']
1532
- }], onEdgesChangeAdd: [{
1533
- type: Output,
1534
- args: ['onEdgesChange.add']
1535
- }], onEdgeChangeAddSingle: [{
1536
- type: Output,
1537
- args: ['onEdgesChange.add.single']
1538
- }], onEdgeChangeAddMany: [{
1539
- type: Output,
1540
- args: ['onEdgesChange.add.many']
1541
- }], onEdgeChangeRemove: [{
1542
- type: Output,
1543
- args: ['onEdgesChange.remove']
1544
- }], onEdgeChangeRemoveSingle: [{
1545
- type: Output,
1546
- args: ['onEdgesChange.remove.single']
1547
- }], onEdgeChangeRemoveMany: [{
1548
- type: Output,
1549
- args: ['onEdgesChange.remove.many']
1550
- }], onEdgeChangeSelect: [{
1551
- type: Output,
1552
- args: ['onEdgesChange.select']
1553
- }], onEdgeChangeSelectSingle: [{
1554
- type: Output,
1555
- args: ['onEdgesChange.select.single']
1556
- }], onEdgeChangeSelectMany: [{
1557
- type: Output,
1558
- args: ['onEdgesChange.select.many']
1559
- }] } });
1688
+ }] });
1689
+
1690
+ function isGroupNode(node) {
1691
+ return node.node.type === 'default-group' || node.node.type === 'template-group';
1692
+ }
1560
1693
 
1561
1694
  class NodeRenderingService {
1562
1695
  constructor() {
@@ -1565,6 +1698,12 @@ class NodeRenderingService {
1565
1698
  return this.flowEntitiesService.nodes()
1566
1699
  .sort((aNode, bNode) => aNode.renderOrder() - bNode.renderOrder());
1567
1700
  });
1701
+ this.groups = computed(() => {
1702
+ return this.nodes().filter(n => isGroupNode(n));
1703
+ });
1704
+ this.nonGroups = computed(() => {
1705
+ return this.nodes().filter(n => !isGroupNode(n));
1706
+ });
1568
1707
  this.maxOrder = computed(() => {
1569
1708
  return Math.max(...this.flowEntitiesService.nodes().map((n) => n.renderOrder()));
1570
1709
  });
@@ -1579,10 +1718,10 @@ class NodeRenderingService {
1579
1718
  .filter(n => n.parent() === node)
1580
1719
  .forEach(n => this.pullNode(n));
1581
1720
  }
1582
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeRenderingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1583
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeRenderingService }); }
1721
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeRenderingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1722
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeRenderingService }); }
1584
1723
  }
1585
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeRenderingService, decorators: [{
1724
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeRenderingService, decorators: [{
1586
1725
  type: Injectable
1587
1726
  }] });
1588
1727
 
@@ -1634,12 +1773,15 @@ class RootPointerDirective {
1634
1773
  setInitialTouch(event) {
1635
1774
  this.initialTouch$.next(event);
1636
1775
  }
1637
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RootPointerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1638
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: RootPointerDirective, selector: "svg[rootPointer]", ngImport: i0 }); }
1776
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RootPointerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1777
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: RootPointerDirective, isStandalone: true, selector: "svg[rootPointer]", ngImport: i0 }); }
1639
1778
  }
1640
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RootPointerDirective, decorators: [{
1779
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RootPointerDirective, decorators: [{
1641
1780
  type: Directive,
1642
- args: [{ selector: 'svg[rootPointer]' }]
1781
+ args: [{
1782
+ standalone: true,
1783
+ selector: 'svg[rootPointer]',
1784
+ }]
1643
1785
  }] });
1644
1786
 
1645
1787
  class SpacePointContextDirective {
@@ -1668,12 +1810,15 @@ class SpacePointContextDirective {
1668
1810
  point.y = documentPoint.y;
1669
1811
  return point.matrixTransform(this.host.getScreenCTM().inverse());
1670
1812
  }
1671
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SpacePointContextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1672
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: SpacePointContextDirective, selector: "g[spacePointContext]", ngImport: i0 }); }
1813
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SpacePointContextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1814
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: SpacePointContextDirective, isStandalone: true, selector: "g[spacePointContext]", ngImport: i0 }); }
1673
1815
  }
1674
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SpacePointContextDirective, decorators: [{
1816
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SpacePointContextDirective, decorators: [{
1675
1817
  type: Directive,
1676
- args: [{ selector: 'g[spacePointContext]' }]
1818
+ args: [{
1819
+ standalone: true,
1820
+ selector: 'g[spacePointContext]',
1821
+ }]
1677
1822
  }] });
1678
1823
 
1679
1824
  function transformBackground(background) {
@@ -1710,8 +1855,8 @@ class OverlaysService {
1710
1855
  removeToolbar(toolbar) {
1711
1856
  this.toolbars.update((toolbars) => toolbars.filter(t => t !== toolbar));
1712
1857
  }
1713
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: OverlaysService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1714
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: OverlaysService }); }
1858
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: OverlaysService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1859
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: OverlaysService }); }
1715
1860
  }
1716
1861
  __decorate([
1717
1862
  Microtask
@@ -1719,10 +1864,105 @@ __decorate([
1719
1864
  __decorate([
1720
1865
  Microtask
1721
1866
  ], OverlaysService.prototype, "removeToolbar", null);
1722
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: OverlaysService, decorators: [{
1867
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: OverlaysService, decorators: [{
1723
1868
  type: Injectable
1724
1869
  }], propDecorators: { addToolbar: [], removeToolbar: [] } });
1725
1870
 
1871
+ class EdgeLabelComponent {
1872
+ constructor() {
1873
+ // TODO: too many inputs
1874
+ this.model = input.required();
1875
+ this.edgeModel = input.required();
1876
+ this.point = input({ x: 0, y: 0 });
1877
+ this.htmlTemplate = input();
1878
+ this.edgeLabelWrapperRef = viewChild.required('edgeLabelWrapper');
1879
+ /**
1880
+ * Centered point of label
1881
+ *
1882
+ * TODO: maybe put it into EdgeLabelModel
1883
+ */
1884
+ this.edgeLabelPoint = computed(() => {
1885
+ const point = this.point();
1886
+ const { width, height } = this.model().size();
1887
+ return {
1888
+ x: point.x - width / 2,
1889
+ y: point.y - height / 2,
1890
+ };
1891
+ });
1892
+ }
1893
+ ngAfterViewInit() {
1894
+ // this is a fix for visual artifact in chrome that for some reason adresses only for edge label.
1895
+ // the bug reproduces if edgeLabelWrapperRef size fully matched the size of parent foreignObject
1896
+ const MAGIC_VALUE_TO_FIX_GLITCH_IN_CHROME = 2;
1897
+ const width = this.edgeLabelWrapperRef().nativeElement.clientWidth +
1898
+ MAGIC_VALUE_TO_FIX_GLITCH_IN_CHROME;
1899
+ const height = this.edgeLabelWrapperRef().nativeElement.clientHeight +
1900
+ MAGIC_VALUE_TO_FIX_GLITCH_IN_CHROME;
1901
+ this.model().size.set({ width, height });
1902
+ }
1903
+ getLabelContext() {
1904
+ return {
1905
+ $implicit: {
1906
+ edge: this.edgeModel().edge,
1907
+ label: this.model().edgeLabel,
1908
+ },
1909
+ };
1910
+ }
1911
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeLabelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1912
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: EdgeLabelComponent, isStandalone: true, selector: "g[edgeLabel]", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, edgeModel: { classPropertyName: "edgeModel", publicName: "edgeModel", isSignal: true, isRequired: true, transformFunction: null }, point: { classPropertyName: "point", publicName: "point", isSignal: true, isRequired: false, transformFunction: null }, htmlTemplate: { classPropertyName: "htmlTemplate", publicName: "htmlTemplate", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "edgeLabelWrapperRef", first: true, predicate: ["edgeLabelWrapper"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (model().edgeLabel.type === \"html-template\" && htmlTemplate()) {\n @if (htmlTemplate(); as htmlTemplate) {\n <svg:foreignObject\n [attr.x]=\"edgeLabelPoint().x\"\n [attr.y]=\"edgeLabelPoint().y\"\n [attr.width]=\"model().size().width\"\n [attr.height]=\"model().size().height\"\n >\n <div #edgeLabelWrapper class=\"edge-label-wrapper\">\n <ng-container\n *ngTemplateOutlet=\"htmlTemplate; context: getLabelContext()\"\n />\n </div>\n </svg:foreignObject>\n }\n}\n", styles: [".edge-label-wrapper{width:max-content;margin-top:1px;margin-left:1px}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1913
+ }
1914
+ __decorate([
1915
+ Microtask
1916
+ ], EdgeLabelComponent.prototype, "ngAfterViewInit", null);
1917
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeLabelComponent, decorators: [{
1918
+ type: Component,
1919
+ args: [{ standalone: true, selector: 'g[edgeLabel]', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgTemplateOutlet], template: "@if (model().edgeLabel.type === \"html-template\" && htmlTemplate()) {\n @if (htmlTemplate(); as htmlTemplate) {\n <svg:foreignObject\n [attr.x]=\"edgeLabelPoint().x\"\n [attr.y]=\"edgeLabelPoint().y\"\n [attr.width]=\"model().size().width\"\n [attr.height]=\"model().size().height\"\n >\n <div #edgeLabelWrapper class=\"edge-label-wrapper\">\n <ng-container\n *ngTemplateOutlet=\"htmlTemplate; context: getLabelContext()\"\n />\n </div>\n </svg:foreignObject>\n }\n}\n", styles: [".edge-label-wrapper{width:max-content;margin-top:1px;margin-left:1px}\n"] }]
1920
+ }], propDecorators: { ngAfterViewInit: [] } });
1921
+
1922
+ class EdgeComponent {
1923
+ constructor() {
1924
+ this.injector = inject(Injector);
1925
+ this.selectionService = inject(SelectionService);
1926
+ this.flowSettingsService = inject(FlowSettingsService);
1927
+ this.model = input.required();
1928
+ this.edgeTemplate = input();
1929
+ this.edgeLabelHtmlTemplate = input();
1930
+ this.markerStartUrl = computed(() => {
1931
+ const marker = this.model().edge.markers?.start;
1932
+ return marker ? `url(#${hashCode(JSON.stringify(marker))})` : '';
1933
+ });
1934
+ this.markerEndUrl = computed(() => {
1935
+ const marker = this.model().edge.markers?.end;
1936
+ return marker ? `url(#${hashCode(JSON.stringify(marker))})` : '';
1937
+ });
1938
+ }
1939
+ ngOnInit() {
1940
+ this.edgeContext = {
1941
+ $implicit: {
1942
+ // TODO: check if edge could change
1943
+ edge: this.model().edge,
1944
+ path: computed(() => this.model().path().path),
1945
+ markerStart: this.markerStartUrl,
1946
+ markerEnd: this.markerEndUrl,
1947
+ selected: this.model().selected.asReadonly(),
1948
+ },
1949
+ };
1950
+ }
1951
+ onEdgeMouseDown() {
1952
+ if (this.flowSettingsService.entitiesSelectable()) {
1953
+ this.selectionService.select(this.model());
1954
+ }
1955
+ }
1956
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1957
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: EdgeComponent, isStandalone: true, selector: "g[edge]", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, edgeTemplate: { classPropertyName: "edgeTemplate", publicName: "edgeTemplate", isSignal: true, isRequired: false, transformFunction: null }, edgeLabelHtmlTemplate: { classPropertyName: "edgeLabelHtmlTemplate", publicName: "edgeLabelHtmlTemplate", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "selectable" }, ngImport: i0, template: "@if (model().type === \"default\") {\n <svg:path\n (mousedown)=\"onEdgeMouseDown()\"\n [attr.d]=\"model().path().path\"\n [attr.marker-start]=\"markerStartUrl()\"\n [attr.marker-end]=\"markerEndUrl()\"\n class=\"edge\"\n [class.edge_selected]=\"model().selected()\"\n />\n}\n\n@if (model().type === \"template\" && edgeTemplate()) {\n @if (edgeTemplate(); as edgeTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"edgeTemplate\"\n [ngTemplateOutletContext]=\"edgeContext\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n }\n}\n\n@if (model().edgeLabels.start; as label) {\n <svg:g\n edgeLabel\n [model]=\"label\"\n [point]=\"model().path().points.start\"\n [edgeModel]=\"model()\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate()\"\n />\n}\n\n@if (model().edgeLabels.center; as label) {\n <svg:g\n edgeLabel\n [model]=\"label\"\n [point]=\"model().path().points.center\"\n [edgeModel]=\"model()\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate()\"\n />\n}\n\n@if (model().edgeLabels.end; as label) {\n <svg:g\n edgeLabel\n [model]=\"label\"\n [point]=\"model().path().points.end\"\n [edgeModel]=\"model()\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate()\"\n />\n}\n", styles: [".edge{fill:none;stroke-width:2;stroke:#b1b1b7}.edge_selected{stroke-width:2.5;stroke:#0f4c75}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: EdgeLabelComponent, selector: "g[edgeLabel]", inputs: ["model", "edgeModel", "point", "htmlTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1958
+ }
1959
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeComponent, decorators: [{
1960
+ type: Component,
1961
+ args: [{ standalone: true, selector: 'g[edge]', changeDetection: ChangeDetectionStrategy.OnPush, host: {
1962
+ class: 'selectable',
1963
+ }, imports: [NgTemplateOutlet, EdgeLabelComponent], template: "@if (model().type === \"default\") {\n <svg:path\n (mousedown)=\"onEdgeMouseDown()\"\n [attr.d]=\"model().path().path\"\n [attr.marker-start]=\"markerStartUrl()\"\n [attr.marker-end]=\"markerEndUrl()\"\n class=\"edge\"\n [class.edge_selected]=\"model().selected()\"\n />\n}\n\n@if (model().type === \"template\" && edgeTemplate()) {\n @if (edgeTemplate(); as edgeTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"edgeTemplate\"\n [ngTemplateOutletContext]=\"edgeContext\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n }\n}\n\n@if (model().edgeLabels.start; as label) {\n <svg:g\n edgeLabel\n [model]=\"label\"\n [point]=\"model().path().points.start\"\n [edgeModel]=\"model()\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate()\"\n />\n}\n\n@if (model().edgeLabels.center; as label) {\n <svg:g\n edgeLabel\n [model]=\"label\"\n [point]=\"model().path().points.center\"\n [edgeModel]=\"model()\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate()\"\n />\n}\n\n@if (model().edgeLabels.end; as label) {\n <svg:g\n edgeLabel\n [model]=\"label\"\n [point]=\"model().path().points.end\"\n [edgeModel]=\"model()\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate()\"\n />\n}\n", styles: [".edge{fill:none;stroke-width:2;stroke:#b1b1b7}.edge_selected{stroke-width:2.5;stroke:#0f4c75}\n"] }]
1964
+ }] });
1965
+
1726
1966
  class HandleService {
1727
1967
  constructor() {
1728
1968
  this.node = signal(null);
@@ -1739,13 +1979,13 @@ class HandleService {
1739
1979
  node.handles.update(handles => handles.filter(handle => handle !== handleToDestoy));
1740
1980
  }
1741
1981
  }
1742
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1743
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleService }); }
1982
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1983
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleService }); }
1744
1984
  }
1745
1985
  __decorate([
1746
1986
  Microtask // TODO fixes rendering of handle for group node
1747
1987
  ], HandleService.prototype, "createHandle", null);
1748
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleService, decorators: [{
1988
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleService, decorators: [{
1749
1989
  type: Injectable
1750
1990
  }], propDecorators: { createHandle: [] } });
1751
1991
 
@@ -1776,176 +2016,71 @@ const implementsWithInjector = (instance) => {
1776
2016
  return 'injector' in instance && 'get' in instance.injector;
1777
2017
  };
1778
2018
 
1779
- /**
1780
- * Service to fix cyclic dependency between node and resizable component
1781
- */
1782
- class NodeAccessorService {
2019
+ class HandleSizeControllerDirective {
1783
2020
  constructor() {
1784
- this.model = signal(null);
2021
+ this.handleModel = input.required({
2022
+ alias: 'handleSizeController',
2023
+ });
2024
+ this.handleWrapper = inject(ElementRef);
2025
+ }
2026
+ ngAfterViewInit() {
2027
+ const element = this.handleWrapper.nativeElement;
2028
+ const rect = element.getBBox();
2029
+ const stroke = getChildStrokeWidth(element);
2030
+ this.handleModel().size.set({
2031
+ width: rect.width + stroke,
2032
+ height: rect.height + stroke,
2033
+ });
1785
2034
  }
1786
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeAccessorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1787
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeAccessorService }); }
2035
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleSizeControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2036
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "17.3.12", type: HandleSizeControllerDirective, isStandalone: true, selector: "[handleSizeController]", inputs: { handleModel: { classPropertyName: "handleModel", publicName: "handleSizeController", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
1788
2037
  }
1789
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeAccessorService, decorators: [{
1790
- type: Injectable
2038
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleSizeControllerDirective, decorators: [{
2039
+ type: Directive,
2040
+ args: [{
2041
+ standalone: true,
2042
+ selector: '[handleSizeController]',
2043
+ }]
1791
2044
  }] });
2045
+ function getChildStrokeWidth(element) {
2046
+ const child = element.firstElementChild;
2047
+ if (child) {
2048
+ const stroke = getComputedStyle(child).strokeWidth;
2049
+ const strokeAsNumber = Number(stroke.replace('px', ''));
2050
+ if (isNaN(strokeAsNumber)) {
2051
+ return 0;
2052
+ }
2053
+ return strokeAsNumber;
2054
+ }
2055
+ return 0;
2056
+ }
1792
2057
 
1793
2058
  class DefaultNodeComponent {
1794
2059
  constructor() {
1795
- this.selected = false;
2060
+ this.selected = input(false);
1796
2061
  }
1797
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DefaultNodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1798
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DefaultNodeComponent, selector: "default-node", inputs: { selected: "selected" }, host: { properties: { "class.selected": "selected" } }, ngImport: i0, template: "<ng-content />\n", styles: [":host{border:1.5px solid #1b262c;border-radius:5px;display:flex;align-items:center;justify-content:center;color:#000;background-color:#fff}:host(.selected){border-width:2px}\n"] }); }
2062
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DefaultNodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2063
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: DefaultNodeComponent, isStandalone: true, selector: "default-node", inputs: { selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.selected": "selected()" } }, ngImport: i0, template: "<ng-content />\n", styles: [":host{border:1.5px solid #1b262c;border-radius:5px;display:flex;align-items:center;justify-content:center;color:#000;background-color:#fff}:host(.selected){border-width:2px}\n"] }); }
1799
2064
  }
1800
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DefaultNodeComponent, decorators: [{
2065
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DefaultNodeComponent, decorators: [{
1801
2066
  type: Component,
1802
- args: [{ selector: 'default-node', host: {
1803
- '[class.selected]': 'selected'
2067
+ args: [{ standalone: true, selector: 'default-node', host: {
2068
+ '[class.selected]': 'selected()',
1804
2069
  }, template: "<ng-content />\n", styles: [":host{border:1.5px solid #1b262c;border-radius:5px;display:flex;align-items:center;justify-content:center;color:#000;background-color:#fff}:host(.selected){border-width:2px}\n"] }]
1805
- }], propDecorators: { selected: [{
1806
- type: Input
1807
- }] } });
2070
+ }] });
1808
2071
 
1809
- class HandleModel {
1810
- constructor(rawHandle, parentNode) {
1811
- this.rawHandle = rawHandle;
1812
- this.parentNode = parentNode;
1813
- this.strokeWidth = 2;
2072
+ class PointerDirective {
2073
+ constructor() {
2074
+ this.hostElement = inject(ElementRef).nativeElement;
2075
+ this.pointerMovementDirective = inject(RootPointerDirective);
2076
+ this.pointerOver = output();
2077
+ this.pointerOut = output();
1814
2078
  /**
1815
- * Pre-computed size for default handle, changed dynamically
1816
- * for custom handles
2079
+ * @todo the Angular may somehow ignore the event.
2080
+ * reproduced here: https://www.ngx-vflow.org/workshops/layout/vizdom-layout
1817
2081
  */
1818
- this.size = signal({
1819
- width: 10 + (2 * this.strokeWidth),
1820
- height: 10 + (2 * this.strokeWidth)
1821
- });
1822
- this.offset = computed(() => {
1823
- switch (this.rawHandle.position) {
1824
- case 'left': return {
1825
- x: 0,
1826
- y: this.parentPosition().y + (this.parentSize().height / 2)
1827
- };
1828
- case 'right': return {
1829
- x: this.parentNode.size().width,
1830
- y: this.parentPosition().y + (this.parentSize().height / 2)
1831
- };
1832
- case 'top': return {
1833
- x: this.parentPosition().x + (this.parentSize().width / 2),
1834
- y: 0
1835
- };
1836
- case 'bottom': return {
1837
- x: this.parentPosition().x + this.parentSize().width / 2,
1838
- y: this.parentNode.size().height
1839
- };
1840
- }
1841
- });
1842
- this.sizeOffset = computed(() => {
1843
- switch (this.rawHandle.position) {
1844
- case 'left': return { x: -(this.size().width / 2), y: 0 };
1845
- case 'right': return { x: this.size().width / 2, y: 0 };
1846
- case 'top': return { x: 0, y: -(this.size().height / 2) };
1847
- case 'bottom': return { x: 0, y: this.size().height / 2 };
1848
- }
1849
- });
1850
- this.pointAbsolute = computed(() => {
1851
- return {
1852
- x: this.parentNode.globalPoint().x + this.offset().x + this.sizeOffset().x,
1853
- y: this.parentNode.globalPoint().y + this.offset().y + this.sizeOffset().y,
1854
- };
1855
- });
1856
- this.state = signal('idle');
1857
- this.updateParentSizeAndPosition$ = new Subject();
1858
- this.parentSize = toSignal(this.updateParentSizeAndPosition$.pipe(map(() => this.getParentSize())), {
1859
- initialValue: { width: 0, height: 0 }
1860
- });
1861
- this.parentPosition = toSignal(this.updateParentSizeAndPosition$.pipe(map(() => ({
1862
- x: this.parentReference instanceof HTMLElement
1863
- ? this.parentReference.offsetLeft
1864
- : 0,
1865
- y: this.parentReference instanceof HTMLElement
1866
- ? this.parentReference.offsetTop
1867
- : 0 // for now just 0 for group nodes
1868
- }))), {
1869
- initialValue: { x: 0, y: 0 }
1870
- });
1871
- this.parentReference = this.rawHandle.parentReference;
1872
- this.template = this.rawHandle.template;
1873
- this.templateContext = {
1874
- $implicit: {
1875
- point: this.offset,
1876
- state: this.state,
1877
- node: this.parentNode.node
1878
- }
1879
- };
1880
- }
1881
- updateParent() {
1882
- this.updateParentSizeAndPosition$.next();
1883
- }
1884
- getParentSize() {
1885
- if (this.parentReference instanceof HTMLElement) {
1886
- return {
1887
- width: this.parentReference.offsetWidth,
1888
- height: this.parentReference.offsetHeight
1889
- };
1890
- }
1891
- else if (this.parentReference instanceof SVGGraphicsElement) {
1892
- return this.parentReference.getBBox();
1893
- }
1894
- return { width: 0, height: 0 };
1895
- }
1896
- }
1897
-
1898
- class HandleComponent {
1899
- constructor() {
1900
- this.injector = inject(Injector);
1901
- this.handleService = inject(HandleService);
1902
- this.element = inject(ElementRef).nativeElement;
1903
- this.destroyRef = inject(DestroyRef);
1904
- }
1905
- ngOnInit() {
1906
- const node = this.handleService.node();
1907
- if (node) {
1908
- this.model = new HandleModel({
1909
- position: this.position,
1910
- type: this.type,
1911
- id: this.id,
1912
- parentReference: this.element.parentElement,
1913
- template: this.template
1914
- }, node);
1915
- this.handleService.createHandle(this.model);
1916
- requestAnimationFrame(() => this.model.updateParent());
1917
- this.destroyRef.onDestroy(() => this.handleService.destroyHandle(this.model));
1918
- }
1919
- }
1920
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1921
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: HandleComponent, selector: "handle", inputs: { position: "position", type: "type", id: "id", template: "template" }, ngImport: i0, template: "", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1922
- }
1923
- __decorate([
1924
- InjectionContext
1925
- ], HandleComponent.prototype, "ngOnInit", null);
1926
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleComponent, decorators: [{
1927
- type: Component,
1928
- args: [{ selector: 'handle', changeDetection: ChangeDetectionStrategy.OnPush, template: "" }]
1929
- }], propDecorators: { position: [{
1930
- type: Input,
1931
- args: [{ required: true }]
1932
- }], type: [{
1933
- type: Input,
1934
- args: [{ required: true }]
1935
- }], id: [{
1936
- type: Input
1937
- }], template: [{
1938
- type: Input
1939
- }], ngOnInit: [] } });
1940
-
1941
- class PointerDirective {
1942
- constructor() {
1943
- this.hostElement = inject(ElementRef).nativeElement;
1944
- this.pointerMovementDirective = inject(RootPointerDirective);
1945
- this.pointerOver = new EventEmitter();
1946
- this.pointerOut = new EventEmitter();
1947
- this.pointerStart = new EventEmitter();
1948
- this.pointerEnd = new EventEmitter();
2082
+ this.pointerStart = output();
2083
+ this.pointerEnd = output();
1949
2084
  this.wasPointerOver = false;
1950
2085
  // TODO check if i could avoid global touch end
1951
2086
  this.touchEnd = this.pointerMovementDirective.touchEnd$
@@ -1986,21 +2121,16 @@ class PointerDirective {
1986
2121
  this.wasPointerOver = false;
1987
2122
  }
1988
2123
  }
1989
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PointerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1990
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: PointerDirective, selector: "[pointerStart], [pointerEnd], [pointerOver], [pointerOut]", outputs: { pointerOver: "pointerOver", pointerOut: "pointerOut", pointerStart: "pointerStart", pointerEnd: "pointerEnd" }, host: { listeners: { "mousedown": "onPointerStart($event)", "touchstart": "onPointerStart($event)", "mouseup": "onPointerEnd($event)", "mouseover": "onMouseOver($event)", "mouseout": "onMouseOut($event)" } }, ngImport: i0 }); }
2124
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PointerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2125
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: PointerDirective, isStandalone: true, selector: "[pointerStart], [pointerEnd], [pointerOver], [pointerOut]", outputs: { pointerOver: "pointerOver", pointerOut: "pointerOut", pointerStart: "pointerStart", pointerEnd: "pointerEnd" }, host: { listeners: { "mousedown": "onPointerStart($event)", "touchstart": "onPointerStart($event)", "mouseup": "onPointerEnd($event)", "mouseover": "onMouseOver($event)", "mouseout": "onMouseOut($event)" } }, ngImport: i0 }); }
1991
2126
  }
1992
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PointerDirective, decorators: [{
2127
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PointerDirective, decorators: [{
1993
2128
  type: Directive,
1994
- args: [{ selector: '[pointerStart], [pointerEnd], [pointerOver], [pointerOut]' }]
1995
- }], propDecorators: { pointerOver: [{
1996
- type: Output
1997
- }], pointerOut: [{
1998
- type: Output
1999
- }], pointerStart: [{
2000
- type: Output
2001
- }], pointerEnd: [{
2002
- type: Output
2003
- }], onPointerStart: [{
2129
+ args: [{
2130
+ standalone: true,
2131
+ selector: '[pointerStart], [pointerEnd], [pointerOver], [pointerOut]',
2132
+ }]
2133
+ }], propDecorators: { onPointerStart: [{
2004
2134
  type: HostListener,
2005
2135
  args: ['mousedown', ['$event']]
2006
2136
  }, {
@@ -2018,14 +2148,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
2018
2148
  }] } });
2019
2149
 
2020
2150
  class ResizableComponent {
2151
+ get model() {
2152
+ return this.nodeAccessor.model();
2153
+ }
2021
2154
  constructor() {
2022
2155
  this.nodeAccessor = inject(NodeAccessorService);
2023
2156
  this.rootPointer = inject(RootPointerDirective);
2024
2157
  this.viewportService = inject(ViewportService);
2025
2158
  this.spacePointContext = inject(SpacePointContextDirective);
2026
2159
  this.hostRef = inject(ElementRef);
2027
- this.resizerColor = '#2e414c';
2028
- this.gap = 1.5;
2160
+ this.resizable = input();
2161
+ this.resizerColor = input('#2e414c');
2162
+ this.gap = input(1.5);
2163
+ this.resizer = viewChild.required('resizer');
2029
2164
  this.lineGap = 3;
2030
2165
  this.handleSize = 6;
2031
2166
  this.resizeSide = null;
@@ -2039,24 +2174,24 @@ class ResizableComponent {
2039
2174
  this.endResizeOnGlobalMouseUp = this.rootPointer.documentPointerEnd$
2040
2175
  .pipe(tap(() => this.endResize()), takeUntilDestroyed())
2041
2176
  .subscribe();
2042
- }
2043
- set resizable(value) {
2044
- if (typeof value === 'boolean') {
2045
- this.model.resizable.set(value);
2046
- }
2047
- else {
2048
- this.model.resizable.set(true);
2049
- }
2050
- }
2051
- get model() {
2052
- return this.nodeAccessor.model();
2177
+ effect(() => {
2178
+ const resizable = this.resizable();
2179
+ if (typeof resizable === 'boolean') {
2180
+ this.model.resizable.set(resizable);
2181
+ }
2182
+ else {
2183
+ this.model.resizable.set(true);
2184
+ }
2185
+ }, { allowSignalWrites: true });
2053
2186
  }
2054
2187
  ngOnInit() {
2055
- this.model.resizerTemplate.set(this.resizer);
2188
+ this.model.resizerTemplate.set(this.resizer());
2056
2189
  }
2057
2190
  ngAfterViewInit() {
2058
- this.minWidth = +getComputedStyle(this.hostRef.nativeElement).minWidth.replace('px', '') || 0;
2059
- this.minHeight = +getComputedStyle(this.hostRef.nativeElement).minHeight.replace('px', '') || 0;
2191
+ this.minWidth =
2192
+ +getComputedStyle(this.hostRef.nativeElement).minWidth.replace('px', '') || 0;
2193
+ this.minHeight =
2194
+ +getComputedStyle(this.hostRef.nativeElement).minHeight.replace('px', '') || 0;
2060
2195
  }
2061
2196
  startResize(side, event) {
2062
2197
  event.stopPropagation();
@@ -2077,13 +2212,15 @@ class ResizableComponent {
2077
2212
  this.resizeSide = null;
2078
2213
  this.model.resizing.set(false);
2079
2214
  }
2080
- isResizeConstrained({ x, y, movementX, movementY }) {
2215
+ isResizeConstrained({ x, y, movementX, movementY, }) {
2081
2216
  const flowPoint = this.spacePointContext.documentPointToFlowPoint({ x, y });
2082
2217
  if (this.resizeSide?.includes('right')) {
2083
- if (movementX > 0 && flowPoint.x < (this.model.point().x + this.model.size().width)) {
2218
+ if (movementX > 0 &&
2219
+ flowPoint.x < this.model.point().x + this.model.size().width) {
2084
2220
  return true;
2085
2221
  }
2086
- if (movementX < 0 && flowPoint.x > this.model.point().x + this.model.size().width) {
2222
+ if (movementX < 0 &&
2223
+ flowPoint.x > this.model.point().x + this.model.size().width) {
2087
2224
  return true;
2088
2225
  }
2089
2226
  }
@@ -2096,10 +2233,12 @@ class ResizableComponent {
2096
2233
  }
2097
2234
  }
2098
2235
  if (this.resizeSide?.includes('bottom')) {
2099
- if (movementY > 0 && flowPoint.y < (this.model.point().y + this.model.size().height)) {
2236
+ if (movementY > 0 &&
2237
+ flowPoint.y < this.model.point().y + this.model.size().height) {
2100
2238
  return true;
2101
2239
  }
2102
- if (movementY < 0 && flowPoint.y > this.model.point().y + this.model.size().height) {
2240
+ if (movementY < 0 &&
2241
+ flowPoint.y > this.model.point().y + this.model.size().height) {
2103
2242
  return true;
2104
2243
  }
2105
2244
  }
@@ -2113,29 +2252,20 @@ class ResizableComponent {
2113
2252
  }
2114
2253
  return false;
2115
2254
  }
2116
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ResizableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2117
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ResizableComponent, selector: "[resizable]", inputs: { resizable: "resizable", resizerColor: "resizerColor", gap: "gap" }, viewQueries: [{ propertyName: "resizer", first: true, predicate: ["resizer"], descendants: true, static: true }], ngImport: i0, template: "<ng-template #resizer>\n <svg:g>\n <!-- top line -->\n <svg:line\n class=\"top\"\n [attr.x1]=\"lineGap\"\n [attr.y1]=\"-gap\"\n [attr.x2]=\"model.size().width - lineGap\"\n [attr.y2]=\"-gap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('top', $event)\"\n />\n <!-- Left line -->\n <svg:line\n class=\"left\"\n [attr.x1]=\"-gap\"\n [attr.y1]=\"lineGap\"\n [attr.x2]=\"-gap\"\n [attr.y2]=\"model.size().height - lineGap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('left', $event)\"\n />\n <!-- Bottom line -->\n <svg:line\n class=\"bottom\"\n [attr.x1]=\"lineGap\"\n [attr.y1]=\"model.size().height + gap\"\n [attr.x2]=\"model.size().width - lineGap\"\n [attr.y2]=\"model.size().height + gap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('bottom', $event)\"\n />\n <!-- Right line -->\n <svg:line\n class=\"right\"\n [attr.x1]=\"model.size().width + gap\"\n [attr.y1]=\"lineGap\"\n [attr.x2]=\"model.size().width + gap\"\n [attr.y2]=\"model.size().height - lineGap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('right', $event)\"\n />\n\n <!-- Top Left -->\n <svg:rect\n class=\"top-left\"\n [attr.x]=\"-(handleSize / 2) - gap\"\n [attr.y]=\"-(handleSize / 2) - gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('top-left', $event)\"\n />\n\n <!-- Top right -->\n <svg:rect\n class=\"top-right\"\n [attr.x]=\"model.size().width - (handleSize / 2) + gap\"\n [attr.y]=\"-(handleSize / 2) - gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('top-right', $event)\"\n />\n\n <!-- Bottom left -->\n <svg:rect\n class=\"bottom-left\"\n [attr.x]=\"-(handleSize / 2) - gap\"\n [attr.y]=\"model.size().height - (handleSize / 2) + gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('bottom-left', $event)\"\n />\n\n <!-- Bottom right -->\n <svg:rect\n class=\"bottom-right\"\n [attr.x]=\"model.size().width - (handleSize / 2) + gap\"\n [attr.y]=\"model.size().height - (handleSize / 2) + gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('bottom-right', $event)\"\n />\n </svg:g>\n</ng-template>\n\n<ng-content />\n", styles: [".top{cursor:n-resize}.left{cursor:w-resize}.right{cursor:e-resize}.bottom{cursor:s-resize}.top-left{cursor:nw-resize}.top-right{cursor:ne-resize}.bottom-left{cursor:sw-resize}.bottom-right{cursor:se-resize}\n"], dependencies: [{ kind: "directive", type: PointerDirective, selector: "[pointerStart], [pointerEnd], [pointerOver], [pointerOut]", outputs: ["pointerOver", "pointerOut", "pointerStart", "pointerEnd"] }] }); }
2255
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ResizableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2256
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "17.3.12", type: ResizableComponent, 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 } }, viewQueries: [{ propertyName: "resizer", first: true, predicate: ["resizer"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-template #resizer>\n <svg:g>\n <!-- top line -->\n <svg:line\n class=\"top\"\n [attr.x1]=\"lineGap\"\n [attr.y1]=\"-gap()\"\n [attr.x2]=\"model.size().width - lineGap\"\n [attr.y2]=\"-gap()\"\n [attr.stroke]=\"resizerColor()\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('top', $event)\"\n />\n <!-- Left line -->\n <svg:line\n class=\"left\"\n [attr.x1]=\"-gap()\"\n [attr.y1]=\"lineGap\"\n [attr.x2]=\"-gap()\"\n [attr.y2]=\"model.size().height - lineGap\"\n [attr.stroke]=\"resizerColor()\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('left', $event)\"\n />\n <!-- Bottom line -->\n <svg:line\n class=\"bottom\"\n [attr.x1]=\"lineGap\"\n [attr.y1]=\"model.size().height + gap()\"\n [attr.x2]=\"model.size().width - lineGap\"\n [attr.y2]=\"model.size().height + gap()\"\n [attr.stroke]=\"resizerColor()\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('bottom', $event)\"\n />\n <!-- Right line -->\n <svg:line\n class=\"right\"\n [attr.x1]=\"model.size().width + gap()\"\n [attr.y1]=\"lineGap\"\n [attr.x2]=\"model.size().width + gap()\"\n [attr.y2]=\"model.size().height - lineGap\"\n [attr.stroke]=\"resizerColor()\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('right', $event)\"\n />\n\n <!-- Top Left -->\n <svg:rect\n class=\"top-left\"\n [attr.x]=\"-(handleSize / 2) - gap()\"\n [attr.y]=\"-(handleSize / 2) - gap()\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor()\"\n (pointerStart)=\"startResize('top-left', $event)\"\n />\n\n <!-- Top right -->\n <svg:rect\n class=\"top-right\"\n [attr.x]=\"model.size().width - handleSize / 2 + gap()\"\n [attr.y]=\"-(handleSize / 2) - gap()\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor()\"\n (pointerStart)=\"startResize('top-right', $event)\"\n />\n\n <!-- Bottom left -->\n <svg:rect\n class=\"bottom-left\"\n [attr.x]=\"-(handleSize / 2) - gap()\"\n [attr.y]=\"model.size().height - handleSize / 2 + gap()\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor()\"\n (pointerStart)=\"startResize('bottom-left', $event)\"\n />\n\n <!-- Bottom right -->\n <svg:rect\n class=\"bottom-right\"\n [attr.x]=\"model.size().width - handleSize / 2 + gap()\"\n [attr.y]=\"model.size().height - handleSize / 2 + gap()\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor()\"\n (pointerStart)=\"startResize('bottom-right', $event)\"\n />\n </svg:g>\n</ng-template>\n\n<ng-content />\n", styles: [".top{cursor:n-resize}.left{cursor:w-resize}.right{cursor:e-resize}.bottom{cursor:s-resize}.top-left{cursor:nw-resize}.top-right{cursor:ne-resize}.bottom-left{cursor:sw-resize}.bottom-right{cursor:se-resize}\n"], dependencies: [{ kind: "directive", type: PointerDirective, selector: "[pointerStart], [pointerEnd], [pointerOver], [pointerOut]", outputs: ["pointerOver", "pointerOut", "pointerStart", "pointerEnd"] }] }); }
2118
2257
  }
2119
2258
  __decorate([
2120
2259
  Microtask
2121
2260
  ], ResizableComponent.prototype, "ngAfterViewInit", null);
2122
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ResizableComponent, decorators: [{
2261
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ResizableComponent, decorators: [{
2123
2262
  type: Component,
2124
- args: [{ selector: '[resizable]', template: "<ng-template #resizer>\n <svg:g>\n <!-- top line -->\n <svg:line\n class=\"top\"\n [attr.x1]=\"lineGap\"\n [attr.y1]=\"-gap\"\n [attr.x2]=\"model.size().width - lineGap\"\n [attr.y2]=\"-gap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('top', $event)\"\n />\n <!-- Left line -->\n <svg:line\n class=\"left\"\n [attr.x1]=\"-gap\"\n [attr.y1]=\"lineGap\"\n [attr.x2]=\"-gap\"\n [attr.y2]=\"model.size().height - lineGap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('left', $event)\"\n />\n <!-- Bottom line -->\n <svg:line\n class=\"bottom\"\n [attr.x1]=\"lineGap\"\n [attr.y1]=\"model.size().height + gap\"\n [attr.x2]=\"model.size().width - lineGap\"\n [attr.y2]=\"model.size().height + gap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('bottom', $event)\"\n />\n <!-- Right line -->\n <svg:line\n class=\"right\"\n [attr.x1]=\"model.size().width + gap\"\n [attr.y1]=\"lineGap\"\n [attr.x2]=\"model.size().width + gap\"\n [attr.y2]=\"model.size().height - lineGap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('right', $event)\"\n />\n\n <!-- Top Left -->\n <svg:rect\n class=\"top-left\"\n [attr.x]=\"-(handleSize / 2) - gap\"\n [attr.y]=\"-(handleSize / 2) - gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('top-left', $event)\"\n />\n\n <!-- Top right -->\n <svg:rect\n class=\"top-right\"\n [attr.x]=\"model.size().width - (handleSize / 2) + gap\"\n [attr.y]=\"-(handleSize / 2) - gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('top-right', $event)\"\n />\n\n <!-- Bottom left -->\n <svg:rect\n class=\"bottom-left\"\n [attr.x]=\"-(handleSize / 2) - gap\"\n [attr.y]=\"model.size().height - (handleSize / 2) + gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('bottom-left', $event)\"\n />\n\n <!-- Bottom right -->\n <svg:rect\n class=\"bottom-right\"\n [attr.x]=\"model.size().width - (handleSize / 2) + gap\"\n [attr.y]=\"model.size().height - (handleSize / 2) + gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('bottom-right', $event)\"\n />\n </svg:g>\n</ng-template>\n\n<ng-content />\n", styles: [".top{cursor:n-resize}.left{cursor:w-resize}.right{cursor:e-resize}.bottom{cursor:s-resize}.top-left{cursor:nw-resize}.top-right{cursor:ne-resize}.bottom-left{cursor:sw-resize}.bottom-right{cursor:se-resize}\n"] }]
2125
- }], propDecorators: { resizable: [{
2126
- type: Input
2127
- }], resizerColor: [{
2128
- type: Input
2129
- }], gap: [{
2130
- type: Input
2131
- }], resizer: [{
2132
- type: ViewChild,
2133
- args: ['resizer', { static: true }]
2134
- }], ngAfterViewInit: [] } });
2263
+ args: [{ standalone: true, selector: '[resizable]', imports: [PointerDirective], template: "<ng-template #resizer>\n <svg:g>\n <!-- top line -->\n <svg:line\n class=\"top\"\n [attr.x1]=\"lineGap\"\n [attr.y1]=\"-gap()\"\n [attr.x2]=\"model.size().width - lineGap\"\n [attr.y2]=\"-gap()\"\n [attr.stroke]=\"resizerColor()\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('top', $event)\"\n />\n <!-- Left line -->\n <svg:line\n class=\"left\"\n [attr.x1]=\"-gap()\"\n [attr.y1]=\"lineGap\"\n [attr.x2]=\"-gap()\"\n [attr.y2]=\"model.size().height - lineGap\"\n [attr.stroke]=\"resizerColor()\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('left', $event)\"\n />\n <!-- Bottom line -->\n <svg:line\n class=\"bottom\"\n [attr.x1]=\"lineGap\"\n [attr.y1]=\"model.size().height + gap()\"\n [attr.x2]=\"model.size().width - lineGap\"\n [attr.y2]=\"model.size().height + gap()\"\n [attr.stroke]=\"resizerColor()\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('bottom', $event)\"\n />\n <!-- Right line -->\n <svg:line\n class=\"right\"\n [attr.x1]=\"model.size().width + gap()\"\n [attr.y1]=\"lineGap\"\n [attr.x2]=\"model.size().width + gap()\"\n [attr.y2]=\"model.size().height - lineGap\"\n [attr.stroke]=\"resizerColor()\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('right', $event)\"\n />\n\n <!-- Top Left -->\n <svg:rect\n class=\"top-left\"\n [attr.x]=\"-(handleSize / 2) - gap()\"\n [attr.y]=\"-(handleSize / 2) - gap()\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor()\"\n (pointerStart)=\"startResize('top-left', $event)\"\n />\n\n <!-- Top right -->\n <svg:rect\n class=\"top-right\"\n [attr.x]=\"model.size().width - handleSize / 2 + gap()\"\n [attr.y]=\"-(handleSize / 2) - gap()\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor()\"\n (pointerStart)=\"startResize('top-right', $event)\"\n />\n\n <!-- Bottom left -->\n <svg:rect\n class=\"bottom-left\"\n [attr.x]=\"-(handleSize / 2) - gap()\"\n [attr.y]=\"model.size().height - handleSize / 2 + gap()\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor()\"\n (pointerStart)=\"startResize('bottom-left', $event)\"\n />\n\n <!-- Bottom right -->\n <svg:rect\n class=\"bottom-right\"\n [attr.x]=\"model.size().width - handleSize / 2 + gap()\"\n [attr.y]=\"model.size().height - handleSize / 2 + gap()\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor()\"\n (pointerStart)=\"startResize('bottom-right', $event)\"\n />\n </svg:g>\n</ng-template>\n\n<ng-content />\n", styles: [".top{cursor:n-resize}.left{cursor:w-resize}.right{cursor:e-resize}.bottom{cursor:s-resize}.top-left{cursor:nw-resize}.top-right{cursor:ne-resize}.bottom-left{cursor:sw-resize}.bottom-right{cursor:se-resize}\n"] }]
2264
+ }], ctorParameters: () => [], propDecorators: { ngAfterViewInit: [] } });
2135
2265
  function calcOffset(movementX, movementY, zoom) {
2136
2266
  return {
2137
2267
  offsetX: round(movementX / zoom),
2138
- offsetY: round(movementY / zoom)
2268
+ offsetY: round(movementY / zoom),
2139
2269
  };
2140
2270
  }
2141
2271
  function applyResize(side, model, offset) {
@@ -2153,11 +2283,26 @@ function applyResize(side, model, offset) {
2153
2283
  case 'bottom':
2154
2284
  return { x, y, width, height: height + offsetY };
2155
2285
  case 'top-left':
2156
- return { x: x + offsetX, y: y + offsetY, width: width - offsetX, height: height - offsetY };
2286
+ return {
2287
+ x: x + offsetX,
2288
+ y: y + offsetY,
2289
+ width: width - offsetX,
2290
+ height: height - offsetY,
2291
+ };
2157
2292
  case 'top-right':
2158
- return { x, y: y + offsetY, width: width + offsetX, height: height - offsetY };
2293
+ return {
2294
+ x,
2295
+ y: y + offsetY,
2296
+ width: width + offsetX,
2297
+ height: height - offsetY,
2298
+ };
2159
2299
  case 'bottom-left':
2160
- return { x: x + offsetX, y, width: width - offsetX, height: height + offsetY };
2300
+ return {
2301
+ x: x + offsetX,
2302
+ y,
2303
+ width: width - offsetX,
2304
+ height: height + offsetY,
2305
+ };
2161
2306
  case 'bottom-right':
2162
2307
  return { x, y, width: width + offsetX, height: height + offsetY };
2163
2308
  }
@@ -2191,7 +2336,7 @@ function constrainRect(rect, model, side, minWidth, minHeight) {
2191
2336
  // 4. Apply child node constraints (if children exist)
2192
2337
  if (bounds) {
2193
2338
  if (side.includes('left')) {
2194
- x = Math.min(x, (model.point().x + model.size().width) - (bounds.x + bounds.width));
2339
+ x = Math.min(x, model.point().x + model.size().width - (bounds.x + bounds.width));
2195
2340
  width = Math.max(width, bounds.x + bounds.width);
2196
2341
  }
2197
2342
  if (side.includes('right')) {
@@ -2201,7 +2346,7 @@ function constrainRect(rect, model, side, minWidth, minHeight) {
2201
2346
  height = Math.max(height, bounds.y + bounds.height);
2202
2347
  }
2203
2348
  if (side.includes('top')) {
2204
- y = Math.min(y, (model.point().y + model.size().height) - (bounds.y + bounds.height));
2349
+ y = Math.min(y, model.point().y + model.size().height - (bounds.y + bounds.height));
2205
2350
  height = Math.max(height, bounds.y + bounds.height);
2206
2351
  }
2207
2352
  }
@@ -2209,45 +2354,144 @@ function constrainRect(rect, model, side, minWidth, minHeight) {
2209
2354
  x,
2210
2355
  y,
2211
2356
  width,
2212
- height
2357
+ height,
2213
2358
  };
2214
2359
  }
2215
2360
 
2216
- class HandleSizeControllerDirective {
2217
- constructor() {
2218
- this.handleWrapper = inject(ElementRef);
2219
- }
2220
- ngAfterViewInit() {
2221
- const element = this.handleWrapper.nativeElement;
2222
- const rect = element.getBBox();
2223
- const stroke = getChildStrokeWidth(element);
2224
- this.handleModel.size.set({
2225
- width: rect.width + stroke,
2226
- height: rect.height + stroke
2361
+ class HandleModel {
2362
+ constructor(rawHandle, parentNode) {
2363
+ this.rawHandle = rawHandle;
2364
+ this.parentNode = parentNode;
2365
+ this.strokeWidth = 2;
2366
+ /**
2367
+ * Pre-computed size for default handle, changed dynamically
2368
+ * for custom handles
2369
+ */
2370
+ this.size = signal({
2371
+ width: 10 + (2 * this.strokeWidth),
2372
+ height: 10 + (2 * this.strokeWidth)
2227
2373
  });
2374
+ this.offset = computed(() => {
2375
+ switch (this.rawHandle.position) {
2376
+ case 'left': return {
2377
+ x: 0,
2378
+ y: this.parentPosition().y + (this.parentSize().height / 2)
2379
+ };
2380
+ case 'right': return {
2381
+ x: this.parentNode.size().width,
2382
+ y: this.parentPosition().y + (this.parentSize().height / 2)
2383
+ };
2384
+ case 'top': return {
2385
+ x: this.parentPosition().x + (this.parentSize().width / 2),
2386
+ y: 0
2387
+ };
2388
+ case 'bottom': return {
2389
+ x: this.parentPosition().x + this.parentSize().width / 2,
2390
+ y: this.parentNode.size().height
2391
+ };
2392
+ }
2393
+ });
2394
+ this.sizeOffset = computed(() => {
2395
+ switch (this.rawHandle.position) {
2396
+ case 'left': return { x: -(this.size().width / 2), y: 0 };
2397
+ case 'right': return { x: this.size().width / 2, y: 0 };
2398
+ case 'top': return { x: 0, y: -(this.size().height / 2) };
2399
+ case 'bottom': return { x: 0, y: this.size().height / 2 };
2400
+ }
2401
+ });
2402
+ this.pointAbsolute = computed(() => {
2403
+ return {
2404
+ x: this.parentNode.globalPoint().x + this.offset().x + this.sizeOffset().x,
2405
+ y: this.parentNode.globalPoint().y + this.offset().y + this.sizeOffset().y,
2406
+ };
2407
+ });
2408
+ this.state = signal('idle');
2409
+ this.updateParentSizeAndPosition$ = new Subject();
2410
+ this.parentSize = toSignal(this.updateParentSizeAndPosition$.pipe(map(() => this.getParentSize())), {
2411
+ initialValue: { width: 0, height: 0 }
2412
+ });
2413
+ this.parentPosition = toSignal(this.updateParentSizeAndPosition$.pipe(map(() => ({
2414
+ x: this.parentReference instanceof HTMLElement
2415
+ ? this.parentReference.offsetLeft
2416
+ : 0, // for now just 0 for group nodes
2417
+ y: this.parentReference instanceof HTMLElement
2418
+ ? this.parentReference.offsetTop
2419
+ : 0 // for now just 0 for group nodes
2420
+ }))), {
2421
+ initialValue: { x: 0, y: 0 }
2422
+ });
2423
+ this.parentReference = this.rawHandle.parentReference;
2424
+ this.template = this.rawHandle.template;
2425
+ this.templateContext = {
2426
+ $implicit: {
2427
+ point: this.offset,
2428
+ state: this.state,
2429
+ node: this.parentNode.node
2430
+ }
2431
+ };
2432
+ }
2433
+ updateParent() {
2434
+ this.updateParentSizeAndPosition$.next();
2435
+ }
2436
+ getParentSize() {
2437
+ if (this.parentReference instanceof HTMLElement) {
2438
+ return {
2439
+ width: this.parentReference.offsetWidth,
2440
+ height: this.parentReference.offsetHeight
2441
+ };
2442
+ }
2443
+ else if (this.parentReference instanceof SVGGraphicsElement) {
2444
+ return this.parentReference.getBBox();
2445
+ }
2446
+ return { width: 0, height: 0 };
2228
2447
  }
2229
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleSizeControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2230
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: { handleModel: ["handleSizeController", "handleModel"] }, ngImport: i0 }); }
2231
2448
  }
2232
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleSizeControllerDirective, decorators: [{
2233
- type: Directive,
2234
- args: [{ selector: '[handleSizeController]' }]
2235
- }], propDecorators: { handleModel: [{
2236
- type: Input,
2237
- args: [{ required: true, alias: 'handleSizeController' }]
2238
- }] } });
2239
- function getChildStrokeWidth(element) {
2240
- const child = element.firstElementChild;
2241
- if (child) {
2242
- const stroke = getComputedStyle(child).strokeWidth;
2243
- const strokeAsNumber = Number(stroke.replace('px', ''));
2244
- if (isNaN(strokeAsNumber)) {
2245
- return 0;
2449
+
2450
+ class HandleComponent {
2451
+ constructor() {
2452
+ this.injector = inject(Injector);
2453
+ this.handleService = inject(HandleService);
2454
+ this.element = inject(ElementRef).nativeElement;
2455
+ this.destroyRef = inject(DestroyRef);
2456
+ /**
2457
+ * At what side of node this component should be placed
2458
+ */
2459
+ this.position = input.required();
2460
+ /**
2461
+ * Source or target
2462
+ */
2463
+ this.type = input.required();
2464
+ /**
2465
+ * Should be used if node has more than one source/target
2466
+ */
2467
+ this.id = input();
2468
+ this.template = input();
2469
+ }
2470
+ ngOnInit() {
2471
+ const node = this.handleService.node();
2472
+ if (node) {
2473
+ this.model = new HandleModel({
2474
+ position: this.position(),
2475
+ type: this.type(),
2476
+ id: this.id(),
2477
+ parentReference: this.element.parentElement,
2478
+ template: this.template(),
2479
+ }, node);
2480
+ this.handleService.createHandle(this.model);
2481
+ requestAnimationFrame(() => this.model.updateParent());
2482
+ this.destroyRef.onDestroy(() => this.handleService.destroyHandle(this.model));
2246
2483
  }
2247
- return strokeAsNumber;
2248
2484
  }
2249
- return 0;
2485
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2486
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: HandleComponent, isStandalone: true, selector: "handle", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: true, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: true, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, template: { classPropertyName: "template", publicName: "template", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2250
2487
  }
2488
+ __decorate([
2489
+ InjectionContext
2490
+ ], HandleComponent.prototype, "ngOnInit", null);
2491
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleComponent, decorators: [{
2492
+ type: Component,
2493
+ args: [{ standalone: true, selector: 'handle', changeDetection: ChangeDetectionStrategy.OnPush, template: "" }]
2494
+ }], propDecorators: { ngOnInit: [] } });
2251
2495
 
2252
2496
  class NodeComponent {
2253
2497
  constructor() {
@@ -2263,40 +2507,47 @@ class NodeComponent {
2263
2507
  this.nodeAccessor = inject(NodeAccessorService);
2264
2508
  this.overlaysService = inject(OverlaysService);
2265
2509
  this.zone = inject(NgZone);
2510
+ this.nodeModel = input.required();
2511
+ this.nodeTemplate = input();
2512
+ this.groupNodeTemplate = input();
2513
+ this.htmlWrapperRef = viewChild.required('htmlWrapper');
2266
2514
  this.showMagnet = computed(() => this.flowStatusService.status().state === 'connection-start' ||
2267
2515
  this.flowStatusService.status().state === 'connection-validation');
2268
- this.styleWidth = computed(() => `${this.nodeModel.size().width}px`);
2269
- this.styleHeight = computed(() => `${this.nodeModel.size().height}px`);
2270
- this.toolbar = computed(() => this.overlaysService.nodeToolbars().get(this.nodeModel));
2516
+ this.styleWidth = computed(() => `${this.nodeModel().size().width}px`);
2517
+ this.styleHeight = computed(() => `${this.nodeModel().size().height}px`);
2518
+ this.toolbar = computed(() => this.overlaysService.nodeToolbars().get(this.nodeModel()));
2271
2519
  }
2272
2520
  ngOnInit() {
2273
- this.nodeAccessor.model.set(this.nodeModel);
2274
- this.handleService.node.set(this.nodeModel);
2521
+ this.nodeAccessor.model.set(this.nodeModel());
2522
+ this.handleService.node.set(this.nodeModel());
2275
2523
  effect(() => {
2276
- if (this.nodeModel.draggable()) {
2277
- this.draggableService.enable(this.hostRef.nativeElement, this.nodeModel);
2524
+ if (this.nodeModel().draggable()) {
2525
+ this.draggableService.enable(this.hostRef.nativeElement, this.nodeModel());
2278
2526
  }
2279
2527
  else {
2280
2528
  this.draggableService.disable(this.hostRef.nativeElement);
2281
2529
  }
2282
2530
  });
2283
- this.nodeModel.handles$
2284
- .pipe(switchMap((handles) => resizable(handles.map(h => h.parentReference), this.zone)
2285
- .pipe(map(() => handles))), tap((handles) => {
2531
+ this.nodeModel()
2532
+ .handles$.pipe(switchMap((handles) => resizable(handles.map((h) => h.parentReference), this.zone).pipe(map(() => handles))), tap((handles) => {
2286
2533
  // TODO (performance) inspect how to avoid calls of this when flow initially rendered
2287
- handles.forEach(h => h.updateParent());
2534
+ handles.forEach((h) => h.updateParent());
2288
2535
  }), takeUntilDestroyed())
2289
2536
  .subscribe();
2290
2537
  }
2291
2538
  ngAfterViewInit() {
2292
- this.nodeModel.linkDefaultNodeSizeWithModelSize();
2293
- if (this.nodeModel.node.type === 'html-template' || this.nodeModel.isComponentType) {
2294
- resizable([this.htmlWrapperRef.nativeElement], this.zone)
2295
- .pipe(startWith(null), tap(() => this.nodeModel.handles().forEach(h => h.updateParent())), filter(() => !this.nodeModel.resizing()), tap(() => {
2296
- const width = this.htmlWrapperRef.nativeElement.clientWidth;
2297
- const height = this.htmlWrapperRef.nativeElement.clientHeight;
2298
- this.nodeModel.size.set({ width, height });
2299
- }), takeUntilDestroyed()).subscribe();
2539
+ this.nodeModel().linkDefaultNodeSizeWithModelSize();
2540
+ if (this.nodeModel().node.type === 'html-template' ||
2541
+ this.nodeModel().isComponentType) {
2542
+ resizable([this.htmlWrapperRef().nativeElement], this.zone)
2543
+ .pipe(startWith(null), tap(() => this.nodeModel()
2544
+ .handles()
2545
+ .forEach((h) => h.updateParent())), filter(() => !this.nodeModel().resizing()), tap(() => {
2546
+ const width = this.htmlWrapperRef().nativeElement.clientWidth;
2547
+ const height = this.htmlWrapperRef().nativeElement.clientHeight;
2548
+ this.nodeModel().size.set({ width, height });
2549
+ }), takeUntilDestroyed())
2550
+ .subscribe();
2300
2551
  }
2301
2552
  }
2302
2553
  ngOnDestroy() {
@@ -2317,15 +2568,15 @@ class NodeComponent {
2317
2568
  this.connectionController.endConnection(handle);
2318
2569
  }
2319
2570
  pullNode() {
2320
- this.nodeRenderingService.pullNode(this.nodeModel);
2571
+ this.nodeRenderingService.pullNode(this.nodeModel());
2321
2572
  }
2322
2573
  selectNode() {
2323
2574
  if (this.flowSettingsService.entitiesSelectable()) {
2324
- this.selectionService.select(this.nodeModel);
2575
+ this.selectionService.select(this.nodeModel());
2325
2576
  }
2326
2577
  }
2327
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2328
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: NodeComponent, selector: "g[node]", inputs: { nodeModel: "nodeModel", nodeTemplate: "nodeTemplate", groupNodeTemplate: "groupNodeTemplate" }, host: { classAttribute: "vflow-node" }, providers: [HandleService, NodeAccessorService], viewQueries: [{ propertyName: "nodeContentRef", first: true, predicate: ["nodeContent"], descendants: true }, { propertyName: "htmlWrapperRef", first: true, predicate: ["htmlWrapper"], descendants: true }], ngImport: i0, template: "<!-- Default node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'default'\"\n class=\"selectable\"\n #nodeContent\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (pointerStart)=\"pullNode(); selectNode()\"\n>\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 >\n <div [outerHTML]=\"nodeModel.text()\"></div>\n\n <handle type=\"source\" [position]=\"nodeModel.sourcePosition()\" />\n <handle type=\"target\" [position]=\"nodeModel.targetPosition()\" />\n </default-node>\n</svg:foreignObject>\n\n<!-- Template node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'html-template' && nodeTemplate\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (pointerStart)=\"pullNode()\"\n>\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Component node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.isComponentType\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (pointerStart)=\"pullNode()\"\n>\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngComponentOutlet]=\"$any(nodeModel.node.type)\"\n [ngComponentOutletInputs]=\"nodeModel.componentTypeInputs()\"\n [ngComponentOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Default group node -->\n<svg:rect\n *ngIf=\"nodeModel.node.type === 'default-group'\"\n [resizable]=\"nodeModel.resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"nodeModel.color()\"\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [class.default-group-node_selected]=\"nodeModel.selected()\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n [style.stroke]=\"nodeModel.color()\"\n [style.fill]=\"nodeModel.color()\"\n (pointerStart)=\"pullNode(); selectNode()\"\n/>\n\n<!-- Template group node -->\n<svg:g\n *ngIf=\"nodeModel.node.type === 'template-group' && groupNodeTemplate\"\n class=\"selectable\"\n (pointerStart)=\"pullNode()\"\n>\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected, width: nodeModel.width, height: nodeModel.height } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n</svg:g>\n\n<!-- Resizer -->\n<ng-container *ngIf=\"nodeModel.resizerTemplate() as template\">\n <ng-container *ngIf=\"nodeModel.resizable()\">\n <ng-template [ngTemplateOutlet]=\"template\" />\n </ng-container>\n</ng-container>\n\n<!-- Handles -->\n<ng-container *ngFor=\"let handle of nodeModel.handles()\">\n <svg:circle\n *ngIf=\"!handle.template\"\n class=\"default-handle\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n r=\"5\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n />\n\n <svg:g\n *ngIf=\"handle.template\"\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n >\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n\n <svg:circle\n *ngIf=\"showMagnet()\"\n class=\"magnet\"\n [attr.r]=\"nodeModel.magnetRadius\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n (pointerEnd)=\"endConnection(handle); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\"\n />\n</ng-container>\n\n<!-- Toolbar -->\n<svg:foreignObject\n *ngIf=\"toolbar() as toolbar\"\n [attr.width]=\"toolbar.size().width\"\n [attr.height]=\"toolbar.size().height\"\n [attr.transform]=\"toolbar.transform()\"\n>\n <ng-container [ngTemplateOutlet]=\"toolbar.template()\" />\n</svg:foreignObject>\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: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "component", type: DefaultNodeComponent, selector: "default-node", inputs: ["selected"] }, { kind: "component", type: HandleComponent, selector: "handle", inputs: ["position", "type", "id", "template"] }, { kind: "component", type: ResizableComponent, selector: "[resizable]", inputs: ["resizable", "resizerColor", "gap"] }, { kind: "directive", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: ["handleSizeController"] }, { kind: "directive", type: PointerDirective, selector: "[pointerStart], [pointerEnd], [pointerOver], [pointerOut]", outputs: ["pointerOver", "pointerOut", "pointerStart", "pointerEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2578
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2579
+ 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 @defer {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"nodeModel().size().width\"\n [attr.height]=\"nodeModel().size().height\"\n (pointerStart)=\"pullNode(); selectNode()\"\n >\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 >\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\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 >\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{\n $implicit: { node: nodeModel().node, selected: nodeModel().selected },\n }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\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 >\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngComponentOutlet]=\"$any(nodeModel().node.type)\"\n [ngComponentOutletInputs]=\"nodeModel().componentTypeInputs\"\n [ngComponentOutletInjector]=\"injector\"\n />\n </div>\n </svg:foreignObject>\n}\n\n<!-- Default group node -->\n@if (nodeModel().node.type === \"default-group\") {\n @defer {\n <svg:rect\n [resizable]=\"nodeModel().resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"nodeModel().color()\"\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [class.default-group-node_selected]=\"nodeModel().selected()\"\n [attr.width]=\"nodeModel().size().width\"\n [attr.height]=\"nodeModel().size().height\"\n [style.stroke]=\"nodeModel().color()\"\n [style.fill]=\"nodeModel().color()\"\n (pointerStart)=\"pullNode(); selectNode()\"\n />\n }\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 />\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 [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n r=\"5\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n />\n }\n\n @if (handle.template) {\n <svg:g\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n >\n <ng-container\n *ngTemplateOutlet=\"handle.template; context: handle.templateContext\"\n />\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(handle); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\"\n />\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 >\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: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "directive", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: ["handleSizeController"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2329
2580
  }
2330
2581
  __decorate([
2331
2582
  InjectionContext
@@ -2333,130 +2584,25 @@ __decorate([
2333
2584
  __decorate([
2334
2585
  InjectionContext
2335
2586
  ], NodeComponent.prototype, "ngAfterViewInit", null);
2336
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeComponent, decorators: [{
2587
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeComponent, decorators: [{
2337
2588
  type: Component,
2338
- args: [{ selector: 'g[node]', changeDetection: ChangeDetectionStrategy.OnPush, providers: [HandleService, NodeAccessorService], host: {
2339
- 'class': 'vflow-node',
2340
- }, template: "<!-- Default node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'default'\"\n class=\"selectable\"\n #nodeContent\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (pointerStart)=\"pullNode(); selectNode()\"\n>\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 >\n <div [outerHTML]=\"nodeModel.text()\"></div>\n\n <handle type=\"source\" [position]=\"nodeModel.sourcePosition()\" />\n <handle type=\"target\" [position]=\"nodeModel.targetPosition()\" />\n </default-node>\n</svg:foreignObject>\n\n<!-- Template node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'html-template' && nodeTemplate\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (pointerStart)=\"pullNode()\"\n>\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Component node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.isComponentType\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (pointerStart)=\"pullNode()\"\n>\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngComponentOutlet]=\"$any(nodeModel.node.type)\"\n [ngComponentOutletInputs]=\"nodeModel.componentTypeInputs()\"\n [ngComponentOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Default group node -->\n<svg:rect\n *ngIf=\"nodeModel.node.type === 'default-group'\"\n [resizable]=\"nodeModel.resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"nodeModel.color()\"\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [class.default-group-node_selected]=\"nodeModel.selected()\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n [style.stroke]=\"nodeModel.color()\"\n [style.fill]=\"nodeModel.color()\"\n (pointerStart)=\"pullNode(); selectNode()\"\n/>\n\n<!-- Template group node -->\n<svg:g\n *ngIf=\"nodeModel.node.type === 'template-group' && groupNodeTemplate\"\n class=\"selectable\"\n (pointerStart)=\"pullNode()\"\n>\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected, width: nodeModel.width, height: nodeModel.height } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n</svg:g>\n\n<!-- Resizer -->\n<ng-container *ngIf=\"nodeModel.resizerTemplate() as template\">\n <ng-container *ngIf=\"nodeModel.resizable()\">\n <ng-template [ngTemplateOutlet]=\"template\" />\n </ng-container>\n</ng-container>\n\n<!-- Handles -->\n<ng-container *ngFor=\"let handle of nodeModel.handles()\">\n <svg:circle\n *ngIf=\"!handle.template\"\n class=\"default-handle\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n r=\"5\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n />\n\n <svg:g\n *ngIf=\"handle.template\"\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n >\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n\n <svg:circle\n *ngIf=\"showMagnet()\"\n class=\"magnet\"\n [attr.r]=\"nodeModel.magnetRadius\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n (pointerEnd)=\"endConnection(handle); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\"\n />\n</ng-container>\n\n<!-- Toolbar -->\n<svg:foreignObject\n *ngIf=\"toolbar() as toolbar\"\n [attr.width]=\"toolbar.size().width\"\n [attr.height]=\"toolbar.size().height\"\n [attr.transform]=\"toolbar.transform()\"\n>\n <ng-container [ngTemplateOutlet]=\"toolbar.template()\" />\n</svg:foreignObject>\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"] }]
2341
- }], propDecorators: { nodeModel: [{
2342
- type: Input
2343
- }], nodeTemplate: [{
2344
- type: Input
2345
- }], groupNodeTemplate: [{
2346
- type: Input
2347
- }], nodeContentRef: [{
2348
- type: ViewChild,
2349
- args: ['nodeContent']
2350
- }], htmlWrapperRef: [{
2351
- type: ViewChild,
2352
- args: ['htmlWrapper']
2353
- }], ngOnInit: [], ngAfterViewInit: [] } });
2354
-
2355
- class EdgeLabelComponent {
2356
- constructor() {
2357
- /**
2358
- * Centered point of label
2359
- *
2360
- * TODO: maybe put it into EdgeLabelModel
2361
- */
2362
- this.edgeLabelPoint = computed(() => {
2363
- const point = this.pointSignal();
2364
- const { width, height } = this.model.size();
2365
- return {
2366
- x: point.x - (width / 2),
2367
- y: point.y - (height / 2)
2368
- };
2369
- });
2370
- this.pointSignal = signal({ x: 0, y: 0 });
2371
- }
2372
- set point(point) { this.pointSignal.set(point); }
2373
- ngAfterViewInit() {
2374
- // this is a fix for visual artifact in chrome that for some reason adresses only for edge label.
2375
- // the bug reproduces if edgeLabelWrapperRef size fully matched the size of parent foreignObject
2376
- const MAGIC_VALUE_TO_FIX_GLITCH_IN_CHROME = 2;
2377
- const width = this.edgeLabelWrapperRef.nativeElement.clientWidth + MAGIC_VALUE_TO_FIX_GLITCH_IN_CHROME;
2378
- const height = this.edgeLabelWrapperRef.nativeElement.clientHeight + MAGIC_VALUE_TO_FIX_GLITCH_IN_CHROME;
2379
- this.model.size.set({ width, height });
2380
- }
2381
- getLabelContext() {
2382
- return {
2383
- $implicit: {
2384
- edge: this.edgeModel.edge,
2385
- label: this.model.edgeLabel
2386
- }
2387
- };
2388
- }
2389
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EdgeLabelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2390
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: EdgeLabelComponent, selector: "g[edgeLabel]", inputs: { model: "model", edgeModel: "edgeModel", point: "point", htmlTemplate: "htmlTemplate" }, viewQueries: [{ propertyName: "edgeLabelWrapperRef", first: true, predicate: ["edgeLabelWrapper"], descendants: true }], ngImport: i0, template: "<svg:foreignObject\n [attr.x]=\"edgeLabelPoint().x\"\n [attr.y]=\"edgeLabelPoint().y\"\n [attr.width]=\"model.size().width\"\n [attr.height]=\"model.size().height\"\n *ngIf=\"model.edgeLabel.type === 'html-template' && htmlTemplate\"\n>\n <div #edgeLabelWrapper class=\"edge-label-wrapper\">\n <ng-container\n *ngTemplateOutlet=\"htmlTemplate; context: getLabelContext()\"\n />\n </div>\n</svg:foreignObject>\n", styles: [".edge-label-wrapper{width:max-content;margin-top:1px;margin-left:1px}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2391
- }
2392
- __decorate([
2393
- Microtask
2394
- ], EdgeLabelComponent.prototype, "ngAfterViewInit", null);
2395
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EdgeLabelComponent, decorators: [{
2396
- type: Component,
2397
- args: [{ selector: 'g[edgeLabel]', changeDetection: ChangeDetectionStrategy.OnPush, template: "<svg:foreignObject\n [attr.x]=\"edgeLabelPoint().x\"\n [attr.y]=\"edgeLabelPoint().y\"\n [attr.width]=\"model.size().width\"\n [attr.height]=\"model.size().height\"\n *ngIf=\"model.edgeLabel.type === 'html-template' && htmlTemplate\"\n>\n <div #edgeLabelWrapper class=\"edge-label-wrapper\">\n <ng-container\n *ngTemplateOutlet=\"htmlTemplate; context: getLabelContext()\"\n />\n </div>\n</svg:foreignObject>\n", styles: [".edge-label-wrapper{width:max-content;margin-top:1px;margin-left:1px}\n"] }]
2398
- }], propDecorators: { model: [{
2399
- type: Input
2400
- }], edgeModel: [{
2401
- type: Input
2402
- }], point: [{
2403
- type: Input
2404
- }], htmlTemplate: [{
2405
- type: Input
2406
- }], edgeLabelWrapperRef: [{
2407
- type: ViewChild,
2408
- args: ['edgeLabelWrapper']
2409
- }], ngAfterViewInit: [] } });
2410
-
2411
- class EdgeComponent {
2412
- constructor() {
2413
- this.injector = inject(Injector);
2414
- this.selectionService = inject(SelectionService);
2415
- this.flowSettingsService = inject(FlowSettingsService);
2416
- this.markerStartUrl = computed(() => {
2417
- const marker = this.model.edge.markers?.start;
2418
- return marker ? `url(#${hashCode(JSON.stringify(marker))})` : '';
2419
- });
2420
- this.markerEndUrl = computed(() => {
2421
- const marker = this.model.edge.markers?.end;
2422
- return marker ? `url(#${hashCode(JSON.stringify(marker))})` : '';
2423
- });
2424
- }
2425
- ngOnInit() {
2426
- this.edgeContext = {
2427
- $implicit: {
2428
- // TODO: check if edge could change
2429
- edge: this.model.edge,
2430
- path: computed(() => this.model.path().path),
2431
- markerStart: this.markerStartUrl,
2432
- markerEnd: this.markerEndUrl,
2433
- selected: this.model.selected.asReadonly()
2434
- }
2435
- };
2436
- }
2437
- onEdgeMouseDown() {
2438
- if (this.flowSettingsService.entitiesSelectable()) {
2439
- this.selectionService.select(this.model);
2440
- }
2441
- }
2442
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EdgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2443
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: EdgeComponent, selector: "g[edge]", inputs: { model: "model", edgeTemplate: "edgeTemplate", edgeLabelHtmlTemplate: "edgeLabelHtmlTemplate" }, host: { classAttribute: "selectable" }, ngImport: i0, template: "<svg:path\n *ngIf=\"model.type === 'default'\"\n (mousedown)=\"onEdgeMouseDown()\"\n [attr.d]=\"model.path().path\"\n [attr.marker-start]=\"markerStartUrl()\"\n [attr.marker-end]=\"markerEndUrl()\"\n class=\"edge\"\n [class.edge_selected]=\"model.selected()\"\n/>\n\n<ng-container *ngIf=\"model.type === 'template' && edgeTemplate\">\n <ng-container\n [ngTemplateOutlet]=\"edgeTemplate\"\n [ngTemplateOutletContext]=\"edgeContext\"\n [ngTemplateOutletInjector]=\"injector\"\n ></ng-container>\n</ng-container>\n\n<ng-container *ngIf=\"model.edgeLabels?.start as label\">\n <svg:g edgeLabel\n [model]=\"label\"\n [point]=\"model.path().points.start\"\n [edgeModel]=\"model\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate\"\n />\n</ng-container>\n\n<ng-container *ngIf=\"model.edgeLabels?.center as label\">\n <svg:g edgeLabel\n [model]=\"label\"\n [point]=\"model.path().points.center\"\n [edgeModel]=\"model\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate\"\n />\n</ng-container>\n\n<ng-container *ngIf=\"model.edgeLabels?.end as label\">\n <svg:g edgeLabel\n [model]=\"label\"\n [point]=\"model.path().points.end\"\n [edgeModel]=\"model\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate\"\n />\n</ng-container>\n", styles: [".edge{fill:none;stroke-width:2;stroke:#b1b1b7}.edge_selected{stroke-width:2.5;stroke:#0f4c75}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: EdgeLabelComponent, selector: "g[edgeLabel]", inputs: ["model", "edgeModel", "point", "htmlTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2444
- }
2445
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EdgeComponent, decorators: [{
2446
- type: Component,
2447
- args: [{ selector: 'g[edge]', changeDetection: ChangeDetectionStrategy.OnPush, host: {
2448
- 'class': 'selectable'
2449
- }, template: "<svg:path\n *ngIf=\"model.type === 'default'\"\n (mousedown)=\"onEdgeMouseDown()\"\n [attr.d]=\"model.path().path\"\n [attr.marker-start]=\"markerStartUrl()\"\n [attr.marker-end]=\"markerEndUrl()\"\n class=\"edge\"\n [class.edge_selected]=\"model.selected()\"\n/>\n\n<ng-container *ngIf=\"model.type === 'template' && edgeTemplate\">\n <ng-container\n [ngTemplateOutlet]=\"edgeTemplate\"\n [ngTemplateOutletContext]=\"edgeContext\"\n [ngTemplateOutletInjector]=\"injector\"\n ></ng-container>\n</ng-container>\n\n<ng-container *ngIf=\"model.edgeLabels?.start as label\">\n <svg:g edgeLabel\n [model]=\"label\"\n [point]=\"model.path().points.start\"\n [edgeModel]=\"model\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate\"\n />\n</ng-container>\n\n<ng-container *ngIf=\"model.edgeLabels?.center as label\">\n <svg:g edgeLabel\n [model]=\"label\"\n [point]=\"model.path().points.center\"\n [edgeModel]=\"model\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate\"\n />\n</ng-container>\n\n<ng-container *ngIf=\"model.edgeLabels?.end as label\">\n <svg:g edgeLabel\n [model]=\"label\"\n [point]=\"model.path().points.end\"\n [edgeModel]=\"model\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate\"\n />\n</ng-container>\n", styles: [".edge{fill:none;stroke-width:2;stroke:#b1b1b7}.edge_selected{stroke-width:2.5;stroke:#0f4c75}\n"] }]
2450
- }], propDecorators: { model: [{
2451
- type: Input
2452
- }], edgeTemplate: [{
2453
- type: Input
2454
- }], edgeLabelHtmlTemplate: [{
2455
- type: Input
2456
- }] } });
2589
+ args: [{ standalone: true, selector: 'g[node]', changeDetection: ChangeDetectionStrategy.OnPush, providers: [HandleService, NodeAccessorService], host: {
2590
+ class: 'vflow-node',
2591
+ }, imports: [
2592
+ PointerDirective,
2593
+ DefaultNodeComponent,
2594
+ HandleComponent,
2595
+ NgTemplateOutlet,
2596
+ NgComponentOutlet,
2597
+ ResizableComponent,
2598
+ HandleSizeControllerDirective,
2599
+ ], template: "<!-- Default node -->\n@if (nodeModel().node.type === \"default\") {\n @defer {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"nodeModel().size().width\"\n [attr.height]=\"nodeModel().size().height\"\n (pointerStart)=\"pullNode(); selectNode()\"\n >\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 >\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\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 >\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{\n $implicit: { node: nodeModel().node, selected: nodeModel().selected },\n }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\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 >\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngComponentOutlet]=\"$any(nodeModel().node.type)\"\n [ngComponentOutletInputs]=\"nodeModel().componentTypeInputs\"\n [ngComponentOutletInjector]=\"injector\"\n />\n </div>\n </svg:foreignObject>\n}\n\n<!-- Default group node -->\n@if (nodeModel().node.type === \"default-group\") {\n @defer {\n <svg:rect\n [resizable]=\"nodeModel().resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"nodeModel().color()\"\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [class.default-group-node_selected]=\"nodeModel().selected()\"\n [attr.width]=\"nodeModel().size().width\"\n [attr.height]=\"nodeModel().size().height\"\n [style.stroke]=\"nodeModel().color()\"\n [style.fill]=\"nodeModel().color()\"\n (pointerStart)=\"pullNode(); selectNode()\"\n />\n }\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 />\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 [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n r=\"5\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n />\n }\n\n @if (handle.template) {\n <svg:g\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n >\n <ng-container\n *ngTemplateOutlet=\"handle.template; context: handle.templateContext\"\n />\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(handle); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\"\n />\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 >\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"] }]
2600
+ }], propDecorators: { ngOnInit: [], ngAfterViewInit: [] } });
2457
2601
 
2458
2602
  class ConnectionComponent {
2459
2603
  constructor() {
2604
+ this.model = input.required();
2605
+ this.template = input();
2460
2606
  this.flowStatusService = inject(FlowStatusService);
2461
2607
  this.spacePointContext = inject(SpacePointContextDirective);
2462
2608
  this.path = computed(() => {
@@ -2467,9 +2613,15 @@ class ConnectionComponent {
2467
2613
  const sourcePosition = sourceHandle.rawHandle.position;
2468
2614
  const targetPoint = this.spacePointContext.svgCurrentSpacePoint();
2469
2615
  const targetPosition = getOppositePostion(sourceHandle.rawHandle.position);
2470
- switch (this.model.curve) {
2471
- case 'straight': return straightPath(sourcePoint, targetPoint).path;
2472
- case 'bezier': return bezierPath(sourcePoint, targetPoint, sourcePosition, targetPosition).path;
2616
+ switch (this.model().curve) {
2617
+ case 'straight':
2618
+ return straightPath(sourcePoint, targetPoint).path;
2619
+ case 'bezier':
2620
+ return bezierPath(sourcePoint, targetPoint, sourcePosition, targetPosition).path;
2621
+ case 'smooth-step':
2622
+ return smoothStepPath(sourcePoint, targetPoint, sourcePosition, targetPosition).path;
2623
+ case 'step':
2624
+ return smoothStepPath(sourcePoint, targetPoint, sourcePosition, targetPosition, 0).path;
2473
2625
  }
2474
2626
  }
2475
2627
  if (status.state === 'connection-validation') {
@@ -2484,15 +2636,21 @@ class ConnectionComponent {
2484
2636
  const targetPosition = status.payload.valid
2485
2637
  ? targetHandle.rawHandle.position
2486
2638
  : getOppositePostion(sourceHandle.rawHandle.position);
2487
- switch (this.model.curve) {
2488
- case 'straight': return straightPath(sourcePoint, targetPoint).path;
2489
- case 'bezier': return bezierPath(sourcePoint, targetPoint, sourcePosition, targetPosition).path;
2639
+ switch (this.model().curve) {
2640
+ case 'straight':
2641
+ return straightPath(sourcePoint, targetPoint).path;
2642
+ case 'bezier':
2643
+ return bezierPath(sourcePoint, targetPoint, sourcePosition, targetPosition).path;
2644
+ case 'smooth-step':
2645
+ return smoothStepPath(sourcePoint, targetPoint, sourcePosition, targetPosition).path;
2646
+ case 'step':
2647
+ return smoothStepPath(sourcePoint, targetPoint, sourcePosition, targetPosition, 0).path;
2490
2648
  }
2491
2649
  }
2492
2650
  return null;
2493
2651
  });
2494
2652
  this.markerUrl = computed(() => {
2495
- const marker = this.model.settings.marker;
2653
+ const marker = this.model().settings.marker;
2496
2654
  if (marker) {
2497
2655
  return `url(#${hashCode(JSON.stringify(marker))})`;
2498
2656
  }
@@ -2504,56 +2662,59 @@ class ConnectionComponent {
2504
2662
  return {
2505
2663
  $implicit: {
2506
2664
  path: this.path,
2507
- marker: this.markerUrl
2508
- }
2665
+ marker: this.markerUrl,
2666
+ },
2509
2667
  };
2510
2668
  }
2511
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ConnectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2512
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ConnectionComponent, selector: "g[connection]", inputs: { model: "model", template: "template" }, ngImport: i0, template: `
2513
- <ng-container *ngIf="model.type === 'default'">
2514
- <svg:path
2515
- *ngIf="path() as path"
2516
- [attr.d]="path"
2517
- [attr.marker-end]="markerUrl()"
2518
- [attr.stroke]="defaultColor"
2519
- fill="none"
2520
- stroke-width="2"
2521
- />
2522
- </ng-container>
2523
-
2524
- <ng-container *ngIf="model.type === 'template' && template">
2525
- <ng-container *ngTemplateOutlet="template; context: getContext()" />
2526
- </ng-container>
2527
- `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2528
- }
2529
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ConnectionComponent, decorators: [{
2669
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConnectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2670
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: ConnectionComponent, isStandalone: true, selector: "g[connection]", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, template: { classPropertyName: "template", publicName: "template", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
2671
+ @if (model().type === 'default') {
2672
+ @if (path(); as path) {
2673
+ <svg:path
2674
+ [attr.d]="path"
2675
+ [attr.marker-end]="markerUrl()"
2676
+ [attr.stroke]="defaultColor"
2677
+ fill="none"
2678
+ stroke-width="2"
2679
+ />
2680
+ }
2681
+ }
2682
+
2683
+ @if (model().type === 'template') {
2684
+ @if (template(); as template) {
2685
+ <ng-container *ngTemplateOutlet="template; context: getContext()" />
2686
+ }
2687
+ }
2688
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2689
+ }
2690
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ConnectionComponent, decorators: [{
2530
2691
  type: Component,
2531
2692
  args: [{
2693
+ standalone: true,
2532
2694
  selector: 'g[connection]',
2533
2695
  template: `
2534
- <ng-container *ngIf="model.type === 'default'">
2535
- <svg:path
2536
- *ngIf="path() as path"
2537
- [attr.d]="path"
2538
- [attr.marker-end]="markerUrl()"
2539
- [attr.stroke]="defaultColor"
2540
- fill="none"
2541
- stroke-width="2"
2542
- />
2543
- </ng-container>
2544
-
2545
- <ng-container *ngIf="model.type === 'template' && template">
2546
- <ng-container *ngTemplateOutlet="template; context: getContext()" />
2547
- </ng-container>
2696
+ @if (model().type === 'default') {
2697
+ @if (path(); as path) {
2698
+ <svg:path
2699
+ [attr.d]="path"
2700
+ [attr.marker-end]="markerUrl()"
2701
+ [attr.stroke]="defaultColor"
2702
+ fill="none"
2703
+ stroke-width="2"
2704
+ />
2705
+ }
2706
+ }
2707
+
2708
+ @if (model().type === 'template') {
2709
+ @if (template(); as template) {
2710
+ <ng-container *ngTemplateOutlet="template; context: getContext()" />
2711
+ }
2712
+ }
2548
2713
  `,
2549
- changeDetection: ChangeDetectionStrategy.OnPush
2714
+ changeDetection: ChangeDetectionStrategy.OnPush,
2715
+ imports: [NgTemplateOutlet],
2550
2716
  }]
2551
- }], propDecorators: { model: [{
2552
- type: Input,
2553
- args: [{ required: true }]
2554
- }], template: [{
2555
- type: Input
2556
- }] } });
2717
+ }] });
2557
2718
  function getOppositePostion(position) {
2558
2719
  switch (position) {
2559
2720
  case 'top':
@@ -2567,22 +2728,6 @@ function getOppositePostion(position) {
2567
2728
  }
2568
2729
  }
2569
2730
 
2570
- class DefsComponent {
2571
- constructor() {
2572
- this.markers = new Map();
2573
- this.defaultColor = 'rgb(177, 177, 183)';
2574
- }
2575
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DefsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2576
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DefsComponent, selector: "defs[flowDefs]", inputs: { markers: "markers" }, ngImport: i0, template: "<svg:marker\n *ngFor=\"let marker of markers | keyvalue\"\n [attr.id]=\"marker.key\"\n [attr.markerWidth]=\"marker.value.width ?? 16.5\"\n [attr.markerHeight]=\"marker.value.height ?? 16.5\"\n [attr.orient]=\"marker.value.orient ?? 'auto-start-reverse'\"\n viewBox=\"-10 -10 20 20\"\n [attr.markerUnits]=\"marker.value.markerUnits ?? 'userSpaceOnUse'\"\n refX=\"0\"\n refY=\"0\"\n>\n <polyline\n *ngIf=\"marker.value.type === 'arrow-closed' || !marker.value.type\"\n class=\"marker__arrow_closed\"\n [style.stroke]=\"marker.value.color ?? defaultColor\"\n [style.stroke-width]=\"marker.value.strokeWidth ?? 2\"\n [style.fill]=\"marker.value.color ?? defaultColor\"\n points=\"-5,-4 1,0 -5,4 -5,-4\"\n />\n\n <polyline\n *ngIf=\"marker.value.type === 'arrow'\"\n class=\"marker__arrow_default\"\n [style.stroke]=\"marker.value.color ?? defaultColor\"\n [style.stroke-width]=\"marker.value.strokeWidth ?? 2\"\n points=\"-5,-4 0,0 -5,4\"\n />\n</svg:marker>\n", styles: [".marker__arrow_default{stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;fill:none}.marker__arrow_closed{stroke-linecap:round;stroke-linejoin:round}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "pipe", type: i1.KeyValuePipe, name: "keyvalue" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2577
- }
2578
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DefsComponent, decorators: [{
2579
- type: Component,
2580
- args: [{ selector: 'defs[flowDefs]', changeDetection: ChangeDetectionStrategy.OnPush, template: "<svg:marker\n *ngFor=\"let marker of markers | keyvalue\"\n [attr.id]=\"marker.key\"\n [attr.markerWidth]=\"marker.value.width ?? 16.5\"\n [attr.markerHeight]=\"marker.value.height ?? 16.5\"\n [attr.orient]=\"marker.value.orient ?? 'auto-start-reverse'\"\n viewBox=\"-10 -10 20 20\"\n [attr.markerUnits]=\"marker.value.markerUnits ?? 'userSpaceOnUse'\"\n refX=\"0\"\n refY=\"0\"\n>\n <polyline\n *ngIf=\"marker.value.type === 'arrow-closed' || !marker.value.type\"\n class=\"marker__arrow_closed\"\n [style.stroke]=\"marker.value.color ?? defaultColor\"\n [style.stroke-width]=\"marker.value.strokeWidth ?? 2\"\n [style.fill]=\"marker.value.color ?? defaultColor\"\n points=\"-5,-4 1,0 -5,4 -5,-4\"\n />\n\n <polyline\n *ngIf=\"marker.value.type === 'arrow'\"\n class=\"marker__arrow_default\"\n [style.stroke]=\"marker.value.color ?? defaultColor\"\n [style.stroke-width]=\"marker.value.strokeWidth ?? 2\"\n points=\"-5,-4 0,0 -5,4\"\n />\n</svg:marker>\n", styles: [".marker__arrow_default{stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;fill:none}.marker__arrow_closed{stroke-linecap:round;stroke-linejoin:round}\n"] }]
2581
- }], propDecorators: { markers: [{
2582
- type: Input,
2583
- args: [{ required: true }]
2584
- }] } });
2585
-
2586
2731
  function id() {
2587
2732
  const randomLetter = String.fromCharCode(65 + Math.floor(Math.random() * 26));
2588
2733
  return randomLetter + Date.now();
@@ -2592,12 +2737,15 @@ const defaultBg = '#fff';
2592
2737
  const defaultGap = 20;
2593
2738
  const defaultDotSize = 2;
2594
2739
  const defaultDotColor = 'rgb(177, 177, 183)';
2740
+ const defaultImageScale = 0.1;
2741
+ const defaultRepeated = true;
2595
2742
  class BackgroundComponent {
2596
2743
  constructor() {
2597
2744
  this.viewportService = inject(ViewportService);
2598
2745
  this.rootSvg = inject(RootSvgReferenceDirective).element;
2599
2746
  this.settingsService = inject(FlowSettingsService);
2600
2747
  this.backgroundSignal = this.settingsService.background;
2748
+ // DOTS PATTERN
2601
2749
  this.scaledGap = computed(() => {
2602
2750
  const background = this.backgroundSignal();
2603
2751
  if (background.type === 'dots') {
@@ -2608,7 +2756,13 @@ class BackgroundComponent {
2608
2756
  });
2609
2757
  this.x = computed(() => this.viewportService.readableViewport().x % this.scaledGap());
2610
2758
  this.y = computed(() => this.viewportService.readableViewport().y % this.scaledGap());
2611
- this.patternColor = computed(() => this.backgroundSignal().color ?? defaultDotColor);
2759
+ this.patternColor = computed(() => {
2760
+ const bg = this.backgroundSignal();
2761
+ if (bg.type === 'dots') {
2762
+ return bg.color ?? defaultDotColor;
2763
+ }
2764
+ return defaultDotColor;
2765
+ });
2612
2766
  this.patternSize = computed(() => {
2613
2767
  const background = this.backgroundSignal();
2614
2768
  if (background.type === 'dots') {
@@ -2616,6 +2770,56 @@ class BackgroundComponent {
2616
2770
  }
2617
2771
  return 0;
2618
2772
  });
2773
+ // IMAGE PATTERN
2774
+ this.bgImageSrc = computed(() => {
2775
+ const background = this.backgroundSignal();
2776
+ return background.type === 'image' ? background.src : '';
2777
+ });
2778
+ this.imageSize = toSignal(toObservable(this.backgroundSignal).pipe(switchMap(() => createImage(this.bgImageSrc())), map((image) => ({ width: image.naturalWidth, height: image.naturalHeight }))), { initialValue: { width: 0, height: 0 } });
2779
+ this.scaledImageWidth = computed(() => {
2780
+ const background = this.backgroundSignal();
2781
+ if (background.type === 'image') {
2782
+ const zoom = background.fixed ? 1 : this.viewportService.readableViewport().zoom;
2783
+ return this.imageSize().width * zoom * (background.scale ?? defaultImageScale);
2784
+ }
2785
+ return 0;
2786
+ });
2787
+ this.scaledImageHeight = computed(() => {
2788
+ const background = this.backgroundSignal();
2789
+ if (background.type === 'image') {
2790
+ const zoom = background.fixed ? 1 : this.viewportService.readableViewport().zoom;
2791
+ return this.imageSize().height * zoom * (background.scale ?? defaultImageScale);
2792
+ }
2793
+ return 0;
2794
+ });
2795
+ this.imageX = computed(() => {
2796
+ const background = this.backgroundSignal();
2797
+ if (background.type === 'image') {
2798
+ if (!background.repeat) {
2799
+ return background.fixed ? 0 : this.viewportService.readableViewport().x;
2800
+ }
2801
+ return background.fixed
2802
+ ? 0
2803
+ : this.viewportService.readableViewport().x % this.scaledImageWidth();
2804
+ }
2805
+ return 0;
2806
+ });
2807
+ this.imageY = computed(() => {
2808
+ const background = this.backgroundSignal();
2809
+ if (background.type === 'image') {
2810
+ if (!background.repeat) {
2811
+ return background.fixed ? 0 : this.viewportService.readableViewport().y;
2812
+ }
2813
+ return background.fixed
2814
+ ? 0
2815
+ : this.viewportService.readableViewport().y % this.scaledImageHeight();
2816
+ }
2817
+ return 0;
2818
+ });
2819
+ this.repeated = computed(() => {
2820
+ const background = this.backgroundSignal();
2821
+ return background.type === 'image' && (background.repeat ?? defaultRepeated);
2822
+ });
2619
2823
  // Without ID there will be pattern collision for several flows on the page
2620
2824
  // Later pattern ID may be exposed to API
2621
2825
  this.patternId = id();
@@ -2630,39 +2834,33 @@ class BackgroundComponent {
2630
2834
  }
2631
2835
  });
2632
2836
  }
2633
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: BackgroundComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2634
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: BackgroundComponent, selector: "g[background]", ngImport: i0, template: "<ng-container *ngIf=\"backgroundSignal().type === 'dots'\">\n <svg:pattern\n [attr.id]=\"patternId\"\n [attr.x]=\"x()\"\n [attr.y]=\"y()\"\n [attr.width]=\"scaledGap()\"\n [attr.height]=\"scaledGap()\"\n patternUnits=\"userSpaceOnUse\"\n >\n <svg:circle\n [attr.cx]=\"patternSize()\"\n [attr.cy]=\"patternSize()\"\n [attr.r]=\"patternSize()\"\n [attr.fill]=\"patternColor()\"\n />\n </svg:pattern>\n\n <svg:rect\n x=\"0\"\n y=\"0\"\n width=\"100%\"\n height=\"100%\"\n [attr.fill]=\"patternUrl\"\n />\n</ng-container>\n", dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2837
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BackgroundComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2838
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: BackgroundComponent, isStandalone: true, selector: "g[background]", ngImport: i0, template: "@if (backgroundSignal().type === 'dots') {\n <svg:pattern\n [attr.id]=\"patternId\"\n [attr.x]=\"x()\"\n [attr.y]=\"y()\"\n [attr.width]=\"scaledGap()\"\n [attr.height]=\"scaledGap()\"\n patternUnits=\"userSpaceOnUse\"\n >\n <svg:circle\n [attr.cx]=\"patternSize()\"\n [attr.cy]=\"patternSize()\"\n [attr.r]=\"patternSize()\"\n [attr.fill]=\"patternColor()\"\n />\n </svg:pattern>\n\n <svg:rect\n x=\"0\"\n y=\"0\"\n width=\"100%\"\n height=\"100%\"\n [attr.fill]=\"patternUrl\"\n />\n}\n\n@if (backgroundSignal().type === 'image') {\n @if (repeated()) {\n <svg:pattern\n [attr.id]=\"patternId\"\n [attr.x]=\"imageX()\"\n [attr.y]=\"imageY()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\"\n patternUnits=\"userSpaceOnUse\"\n >\n <svg:image\n [attr.href]=\"bgImageSrc()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\"\n />\n </svg:pattern>\n\n <svg:rect\n x=\"0\"\n y=\"0\"\n width=\"100%\"\n height=\"100%\"\n [attr.fill]=\"patternUrl\"\n />\n }\n\n @if (!repeated()) {\n <svg:image\n [attr.x]=\"imageX()\"\n [attr.y]=\"imageY()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\"\n [attr.href]=\"bgImageSrc()\"\n />\n }\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2635
2839
  }
2636
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: BackgroundComponent, decorators: [{
2840
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BackgroundComponent, decorators: [{
2637
2841
  type: Component,
2638
- args: [{ selector: 'g[background]', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"backgroundSignal().type === 'dots'\">\n <svg:pattern\n [attr.id]=\"patternId\"\n [attr.x]=\"x()\"\n [attr.y]=\"y()\"\n [attr.width]=\"scaledGap()\"\n [attr.height]=\"scaledGap()\"\n patternUnits=\"userSpaceOnUse\"\n >\n <svg:circle\n [attr.cx]=\"patternSize()\"\n [attr.cy]=\"patternSize()\"\n [attr.r]=\"patternSize()\"\n [attr.fill]=\"patternColor()\"\n />\n </svg:pattern>\n\n <svg:rect\n x=\"0\"\n y=\"0\"\n width=\"100%\"\n height=\"100%\"\n [attr.fill]=\"patternUrl\"\n />\n</ng-container>\n" }]
2639
- }], ctorParameters: function () { return []; } });
2842
+ args: [{ standalone: true, selector: 'g[background]', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (backgroundSignal().type === 'dots') {\n <svg:pattern\n [attr.id]=\"patternId\"\n [attr.x]=\"x()\"\n [attr.y]=\"y()\"\n [attr.width]=\"scaledGap()\"\n [attr.height]=\"scaledGap()\"\n patternUnits=\"userSpaceOnUse\"\n >\n <svg:circle\n [attr.cx]=\"patternSize()\"\n [attr.cy]=\"patternSize()\"\n [attr.r]=\"patternSize()\"\n [attr.fill]=\"patternColor()\"\n />\n </svg:pattern>\n\n <svg:rect\n x=\"0\"\n y=\"0\"\n width=\"100%\"\n height=\"100%\"\n [attr.fill]=\"patternUrl\"\n />\n}\n\n@if (backgroundSignal().type === 'image') {\n @if (repeated()) {\n <svg:pattern\n [attr.id]=\"patternId\"\n [attr.x]=\"imageX()\"\n [attr.y]=\"imageY()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\"\n patternUnits=\"userSpaceOnUse\"\n >\n <svg:image\n [attr.href]=\"bgImageSrc()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\"\n />\n </svg:pattern>\n\n <svg:rect\n x=\"0\"\n y=\"0\"\n width=\"100%\"\n height=\"100%\"\n [attr.fill]=\"patternUrl\"\n />\n }\n\n @if (!repeated()) {\n <svg:image\n [attr.x]=\"imageX()\"\n [attr.y]=\"imageY()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\"\n [attr.href]=\"bgImageSrc()\"\n />\n }\n}\n" }]
2843
+ }], ctorParameters: () => [] });
2844
+ function createImage(url) {
2845
+ const image = new Image();
2846
+ image.src = url;
2847
+ return new Promise(resolve => {
2848
+ image.onload = () => resolve(image);
2849
+ });
2850
+ }
2640
2851
 
2641
- // TODO: too general purpose nane
2642
- class RootSvgContextDirective {
2852
+ class DefsComponent {
2643
2853
  constructor() {
2644
- this.flowStatusService = inject(FlowStatusService);
2645
- }
2646
- // TODO: check for multiple instances on page
2647
- resetConnection() {
2648
- const status = this.flowStatusService.status();
2649
- if (status.state === 'connection-start') {
2650
- this.flowStatusService.setIdleStatus();
2651
- }
2854
+ this.markers = input.required();
2855
+ this.defaultColor = 'rgb(177, 177, 183)';
2652
2856
  }
2653
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RootSvgContextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2654
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: RootSvgContextDirective, selector: "svg[rootSvgContext]", host: { listeners: { "document:mouseup": "resetConnection()", "document:touchend": "resetConnection()" } }, ngImport: i0 }); }
2857
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DefsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2858
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: DefsComponent, isStandalone: true, selector: "defs[flowDefs]", inputs: { markers: { classPropertyName: "markers", publicName: "markers", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@for (marker of markers() | keyvalue; track marker) {\n <svg:marker\n [attr.id]=\"marker.key\"\n [attr.markerWidth]=\"marker.value.width ?? 16.5\"\n [attr.markerHeight]=\"marker.value.height ?? 16.5\"\n [attr.orient]=\"marker.value.orient ?? 'auto-start-reverse'\"\n viewBox=\"-10 -10 20 20\"\n [attr.markerUnits]=\"marker.value.markerUnits ?? 'userSpaceOnUse'\"\n refX=\"0\"\n refY=\"0\"\n >\n @if (marker.value.type === \"arrow-closed\" || !marker.value.type) {\n <polyline\n class=\"marker__arrow_closed\"\n [style.stroke]=\"marker.value.color ?? defaultColor\"\n [style.stroke-width]=\"marker.value.strokeWidth ?? 2\"\n [style.fill]=\"marker.value.color ?? defaultColor\"\n points=\"-5,-4 1,0 -5,4 -5,-4\"\n />\n }\n\n @if (marker.value.type === \"arrow\") {\n <polyline\n class=\"marker__arrow_default\"\n [style.stroke]=\"marker.value.color ?? defaultColor\"\n [style.stroke-width]=\"marker.value.strokeWidth ?? 2\"\n points=\"-5,-4 0,0 -5,4\"\n />\n }\n </svg:marker>\n}\n", styles: [".marker__arrow_default{stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;fill:none}.marker__arrow_closed{stroke-linecap:round;stroke-linejoin:round}\n"], dependencies: [{ kind: "pipe", type: KeyValuePipe, name: "keyvalue" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2655
2859
  }
2656
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RootSvgContextDirective, decorators: [{
2657
- type: Directive,
2658
- args: [{ selector: 'svg[rootSvgContext]' }]
2659
- }], propDecorators: { resetConnection: [{
2660
- type: HostListener,
2661
- args: ['document:mouseup']
2662
- }, {
2663
- type: HostListener,
2664
- args: ['document:touchend']
2665
- }] } });
2860
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DefsComponent, decorators: [{
2861
+ type: Component,
2862
+ args: [{ standalone: true, selector: 'defs[flowDefs]', changeDetection: ChangeDetectionStrategy.OnPush, imports: [KeyValuePipe], template: "@for (marker of markers() | keyvalue; track marker) {\n <svg:marker\n [attr.id]=\"marker.key\"\n [attr.markerWidth]=\"marker.value.width ?? 16.5\"\n [attr.markerHeight]=\"marker.value.height ?? 16.5\"\n [attr.orient]=\"marker.value.orient ?? 'auto-start-reverse'\"\n viewBox=\"-10 -10 20 20\"\n [attr.markerUnits]=\"marker.value.markerUnits ?? 'userSpaceOnUse'\"\n refX=\"0\"\n refY=\"0\"\n >\n @if (marker.value.type === \"arrow-closed\" || !marker.value.type) {\n <polyline\n class=\"marker__arrow_closed\"\n [style.stroke]=\"marker.value.color ?? defaultColor\"\n [style.stroke-width]=\"marker.value.strokeWidth ?? 2\"\n [style.fill]=\"marker.value.color ?? defaultColor\"\n points=\"-5,-4 1,0 -5,4 -5,-4\"\n />\n }\n\n @if (marker.value.type === \"arrow\") {\n <polyline\n class=\"marker__arrow_default\"\n [style.stroke]=\"marker.value.color ?? defaultColor\"\n [style.stroke-width]=\"marker.value.strokeWidth ?? 2\"\n points=\"-5,-4 0,0 -5,4\"\n />\n }\n </svg:marker>\n}\n", styles: [".marker__arrow_default{stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;fill:none}.marker__arrow_closed{stroke-linecap:round;stroke-linejoin:round}\n"] }]
2863
+ }] });
2666
2864
 
2667
2865
  class FlowSizeControllerDirective {
2668
2866
  constructor() {
@@ -2681,23 +2879,53 @@ class FlowSizeControllerDirective {
2681
2879
  this.flowSettingsService.computedFlowHeight.set(entry.contentRect.height);
2682
2880
  }), takeUntilDestroyed()).subscribe();
2683
2881
  }
2684
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowSizeControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2685
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: FlowSizeControllerDirective, selector: "svg[flowSizeController]", host: { properties: { "attr.width": "flowWidth()", "attr.height": "flowHeight()" } }, ngImport: i0 }); }
2882
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowSizeControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2883
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: FlowSizeControllerDirective, isStandalone: true, selector: "svg[flowSizeController]", host: { properties: { "attr.width": "flowWidth()", "attr.height": "flowHeight()" } }, ngImport: i0 }); }
2686
2884
  }
2687
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowSizeControllerDirective, decorators: [{
2885
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowSizeControllerDirective, decorators: [{
2688
2886
  type: Directive,
2689
2887
  args: [{
2888
+ standalone: true,
2690
2889
  selector: 'svg[flowSizeController]',
2691
2890
  host: {
2692
2891
  '[attr.width]': 'flowWidth()',
2693
2892
  '[attr.height]': 'flowHeight()'
2694
- }
2893
+ },
2695
2894
  }]
2696
- }], ctorParameters: function () { return []; } });
2895
+ }], ctorParameters: () => [] });
2896
+
2897
+ // TODO: too general purpose nane
2898
+ class RootSvgContextDirective {
2899
+ constructor() {
2900
+ this.flowStatusService = inject(FlowStatusService);
2901
+ }
2902
+ // TODO: check for multiple instances on page
2903
+ resetConnection() {
2904
+ const status = this.flowStatusService.status();
2905
+ if (status.state === 'connection-start') {
2906
+ this.flowStatusService.setIdleStatus();
2907
+ }
2908
+ }
2909
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RootSvgContextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2910
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: RootSvgContextDirective, isStandalone: true, selector: "svg[rootSvgContext]", host: { listeners: { "document:mouseup": "resetConnection()", "document:touchend": "resetConnection()" } }, ngImport: i0 }); }
2911
+ }
2912
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RootSvgContextDirective, decorators: [{
2913
+ type: Directive,
2914
+ args: [{
2915
+ standalone: true,
2916
+ selector: 'svg[rootSvgContext]',
2917
+ }]
2918
+ }], propDecorators: { resetConnection: [{
2919
+ type: HostListener,
2920
+ args: ['document:mouseup']
2921
+ }, {
2922
+ type: HostListener,
2923
+ args: ['document:touchend']
2924
+ }] } });
2697
2925
 
2698
2926
  const connectionControllerHostDirective = {
2699
2927
  directive: ConnectionControllerDirective,
2700
- outputs: ['onConnect']
2928
+ outputs: ['onConnect'],
2701
2929
  };
2702
2930
  const changesControllerHostDirective = {
2703
2931
  directive: ChangesControllerDirective,
@@ -2731,7 +2959,7 @@ const changesControllerHostDirective = {
2731
2959
  'onEdgesChange.select',
2732
2960
  'onEdgesChange.select.single',
2733
2961
  'onEdgesChange.select.many',
2734
- ]
2962
+ ],
2735
2963
  };
2736
2964
  class VflowComponent {
2737
2965
  constructor() {
@@ -2745,10 +2973,12 @@ class VflowComponent {
2745
2973
  this.componentEventBusService = inject(ComponentEventBusService);
2746
2974
  this.keyboardService = inject(KeyboardService);
2747
2975
  this.injector = inject(Injector);
2748
- this.optimization = {
2749
- computeLayersOnInit: true
2750
- };
2976
+ this.optimization = input({
2977
+ detachedGroupsLayer: false,
2978
+ });
2751
2979
  this.nodeModels = computed(() => this.nodeRenderingService.nodes());
2980
+ this.groups = computed(() => this.nodeRenderingService.groups());
2981
+ this.nonGroups = computed(() => this.nodeRenderingService.nonGroups());
2752
2982
  this.edgeModels = computed(() => this.flowEntitiesService.validEdges());
2753
2983
  // #endregion
2754
2984
  // #region OUTPUTS
@@ -2757,7 +2987,18 @@ class VflowComponent {
2757
2987
  *
2758
2988
  * @experimental
2759
2989
  */
2760
- this.onComponentNodeEvent = this.componentEventBusService.event$; // TODO: research how to remove as any
2990
+ this.onComponentNodeEvent = outputFromObservable(this.componentEventBusService.event$); // TODO: research how to remove any
2991
+ // #endregion
2992
+ // #region TEMPLATES
2993
+ this.nodeTemplateDirective = contentChild(NodeHtmlTemplateDirective);
2994
+ this.groupNodeTemplateDirective = contentChild(GroupNodeTemplateDirective);
2995
+ this.edgeTemplateDirective = contentChild(EdgeTemplateDirective);
2996
+ this.edgeLabelHtmlDirective = contentChild(EdgeLabelHtmlTemplateDirective);
2997
+ this.connectionTemplateDirective = contentChild(ConnectionTemplateDirective);
2998
+ // #endregion
2999
+ // #region DIRECTIVES
3000
+ this.mapContext = viewChild(MapContextDirective);
3001
+ this.spacePointContext = viewChild.required(SpacePointContextDirective);
2761
3002
  // #endregion
2762
3003
  // #region SIGNAL_API
2763
3004
  /**
@@ -2767,18 +3008,21 @@ class VflowComponent {
2767
3008
  /**
2768
3009
  * Signal for reading nodes change
2769
3010
  */
2770
- this.nodesChange = toSignal(this.nodesChangeService.changes$, { initialValue: [] });
3011
+ this.nodesChange = toSignal(this.nodesChangeService.changes$, {
3012
+ initialValue: [],
3013
+ });
2771
3014
  /**
2772
3015
  * Signal to reading edges change
2773
3016
  */
2774
- this.edgesChange = toSignal(this.edgesChangeService.changes$, { initialValue: [] });
3017
+ this.edgesChange = toSignal(this.edgesChangeService.changes$, {
3018
+ initialValue: [],
3019
+ });
2775
3020
  // #endregion
2776
3021
  // #region RX_API
2777
3022
  /**
2778
3023
  * Observable with viewport change
2779
3024
  */
2780
- this.viewportChange$ = toObservable(this.viewportService.readableViewport)
2781
- .pipe(skip(1)); // skip default value that set by signal
3025
+ this.viewportChange$ = toObservable(this.viewportService.readableViewport).pipe(skip(1)); // skip default value that set by signal
2782
3026
  /**
2783
3027
  * Observable with nodes change
2784
3028
  */
@@ -2815,17 +3059,6 @@ class VflowComponent {
2815
3059
  set maxZoom(value) {
2816
3060
  this.flowSettingsService.maxZoom.set(value);
2817
3061
  }
2818
- /**
2819
- * Object that controls flow direction.
2820
- *
2821
- * For example, if you want to archieve right to left direction
2822
- * then you need to pass these positions { source: 'left', target: 'right' }
2823
- *
2824
- * @deprecated
2825
- */
2826
- set handlePositions(handlePositions) {
2827
- this.flowSettingsService.handlePositions.set(handlePositions);
2828
- }
2829
3062
  /**
2830
3063
  * Background for flow
2831
3064
  */
@@ -2846,8 +3079,12 @@ class VflowComponent {
2846
3079
  *
2847
3080
  * You need to pass `ConnectionSettings` in this input.
2848
3081
  */
2849
- set connection(connection) { this.flowEntitiesService.connection.set(connection); }
2850
- get connection() { return this.flowEntitiesService.connection(); }
3082
+ set connection(connection) {
3083
+ this.flowEntitiesService.connection.set(connection);
3084
+ }
3085
+ get connection() {
3086
+ return this.flowEntitiesService.connection();
3087
+ }
2851
3088
  // #endregion
2852
3089
  // #region MAIN_INPUTS
2853
3090
  /**
@@ -2878,7 +3115,11 @@ class VflowComponent {
2878
3115
  * @param viewport viewport state
2879
3116
  */
2880
3117
  viewportTo(viewport) {
2881
- this.viewportService.writableViewport.set({ changeType: 'absolute', state: viewport, duration: 0 });
3118
+ this.viewportService.writableViewport.set({
3119
+ changeType: 'absolute',
3120
+ state: viewport,
3121
+ duration: 0,
3122
+ });
2882
3123
  }
2883
3124
  /**
2884
3125
  * Change zoom
@@ -2886,7 +3127,11 @@ class VflowComponent {
2886
3127
  * @param zoom zoom value
2887
3128
  */
2888
3129
  zoomTo(zoom) {
2889
- this.viewportService.writableViewport.set({ changeType: 'absolute', state: { zoom }, duration: 0 });
3130
+ this.viewportService.writableViewport.set({
3131
+ changeType: 'absolute',
3132
+ state: { zoom },
3133
+ duration: 0,
3134
+ });
2890
3135
  }
2891
3136
  /**
2892
3137
  * Move to specified coordinate
@@ -2894,7 +3139,11 @@ class VflowComponent {
2894
3139
  * @param point point where to move
2895
3140
  */
2896
3141
  panTo(point) {
2897
- this.viewportService.writableViewport.set({ changeType: 'absolute', state: point, duration: 0 });
3142
+ this.viewportService.writableViewport.set({
3143
+ changeType: 'absolute',
3144
+ state: point,
3145
+ duration: 0,
3146
+ });
2898
3147
  }
2899
3148
  fitView(options) {
2900
3149
  this.viewportService.fitView(options);
@@ -2911,13 +3160,13 @@ class VflowComponent {
2911
3160
  * Sync method to get detached edges
2912
3161
  */
2913
3162
  getDetachedEdges() {
2914
- return this.flowEntitiesService.getDetachedEdges().map(e => e.edge);
3163
+ return this.flowEntitiesService.getDetachedEdges().map((e) => e.edge);
2915
3164
  }
2916
3165
  /**
2917
3166
  * Convert point received from document to point on the flow
2918
3167
  */
2919
3168
  documentPointToFlowPoint(point) {
2920
- return this.spacePointContext.documentPointToFlowPoint(point);
3169
+ return this.spacePointContext().documentPointToFlowPoint(point);
2921
3170
  }
2922
3171
  // #endregion
2923
3172
  trackNodes(idx, { node }) {
@@ -2927,19 +3176,17 @@ class VflowComponent {
2927
3176
  return edge;
2928
3177
  }
2929
3178
  setInitialNodesOrder() {
2930
- if (this.optimization.computeLayersOnInit) {
2931
- this.nodeModels().forEach(model => {
2932
- switch (model.node.type) {
2933
- case 'default-group':
2934
- case 'template-group': {
2935
- this.nodeRenderingService.pullNode(model);
2936
- }
3179
+ this.nodeModels().forEach((model) => {
3180
+ switch (model.node.type) {
3181
+ case 'default-group':
3182
+ case 'template-group': {
3183
+ this.nodeRenderingService.pullNode(model);
2937
3184
  }
2938
- });
2939
- }
3185
+ }
3186
+ });
2940
3187
  }
2941
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: VflowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2942
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "16.2.12", type: VflowComponent, selector: "vflow", inputs: { view: "view", minZoom: "minZoom", maxZoom: "maxZoom", handlePositions: "handlePositions", background: "background", optimization: "optimization", entitiesSelectable: "entitiesSelectable", keyboardShortcuts: "keyboardShortcuts", connection: ["connection", "connection", (settings) => new ConnectionModel(settings)], nodes: "nodes", edges: "edges" }, outputs: { onComponentNodeEvent: "onComponentNodeEvent" }, providers: [
3188
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: VflowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3189
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: VflowComponent, isStandalone: true, selector: "vflow", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: false, isRequired: false, transformFunction: null }, minZoom: { classPropertyName: "minZoom", publicName: "minZoom", isSignal: false, isRequired: false, transformFunction: null }, maxZoom: { classPropertyName: "maxZoom", publicName: "maxZoom", isSignal: false, isRequired: false, transformFunction: null }, background: { classPropertyName: "background", publicName: "background", isSignal: false, isRequired: false, transformFunction: null }, optimization: { classPropertyName: "optimization", publicName: "optimization", isSignal: true, isRequired: false, transformFunction: null }, entitiesSelectable: { classPropertyName: "entitiesSelectable", publicName: "entitiesSelectable", isSignal: false, isRequired: false, transformFunction: null }, keyboardShortcuts: { classPropertyName: "keyboardShortcuts", publicName: "keyboardShortcuts", isSignal: false, isRequired: false, transformFunction: null }, connection: { classPropertyName: "connection", publicName: "connection", isSignal: false, isRequired: false, transformFunction: (settings) => new ConnectionModel(settings) }, nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: false, isRequired: true, transformFunction: null }, edges: { classPropertyName: "edges", publicName: "edges", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { onComponentNodeEvent: "onComponentNodeEvent" }, providers: [
2943
3190
  DraggableService,
2944
3191
  ViewportService,
2945
3192
  FlowStatusService,
@@ -2951,12 +3198,12 @@ class VflowComponent {
2951
3198
  FlowSettingsService,
2952
3199
  ComponentEventBusService,
2953
3200
  KeyboardService,
2954
- OverlaysService
2955
- ], queries: [{ propertyName: "nodeTemplateDirective", first: true, predicate: NodeHtmlTemplateDirective, descendants: true }, { propertyName: "groupNodeTemplateDirective", first: true, predicate: GroupNodeTemplateDirective, descendants: true }, { propertyName: "edgeTemplateDirective", first: true, predicate: EdgeTemplateDirective, descendants: true }, { propertyName: "edgeLabelHtmlDirective", first: true, predicate: EdgeLabelHtmlTemplateDirective, descendants: true }, { propertyName: "connectionTemplateDirective", first: true, predicate: ConnectionTemplateDirective, descendants: true }], viewQueries: [{ propertyName: "mapContext", first: true, predicate: MapContextDirective, descendants: true }, { propertyName: "spacePointContext", first: true, predicate: SpacePointContextDirective, descendants: true }], hostDirectives: [{ directive: ConnectionControllerDirective, outputs: ["onConnect", "onConnect"] }, { directive: ChangesControllerDirective, outputs: ["onNodesChange", "onNodesChange", "onNodesChange.position", "onNodesChange.position", "onNodesChange.position.single", "onNodesChange.position.single", "onNodesChange.position.many", "onNodesChange.position.many", "onNodesChange.size", "onNodesChange.size", "onNodesChange.size.single", "onNodesChange.size.single", "onNodesChange.size.many", "onNodesChange.size.many", "onNodesChange.add", "onNodesChange.add", "onNodesChange.add.single", "onNodesChange.add.single", "onNodesChange.add.many", "onNodesChange.add.many", "onNodesChange.remove", "onNodesChange.remove", "onNodesChange.remove.single", "onNodesChange.remove.single", "onNodesChange.remove.many", "onNodesChange.remove.many", "onNodesChange.select", "onNodesChange.select", "onNodesChange.select.single", "onNodesChange.select.single", "onNodesChange.select.many", "onNodesChange.select.many", "onEdgesChange", "onEdgesChange", "onEdgesChange.detached", "onEdgesChange.detached", "onEdgesChange.detached.single", "onEdgesChange.detached.single", "onEdgesChange.detached.many", "onEdgesChange.detached.many", "onEdgesChange.add", "onEdgesChange.add", "onEdgesChange.add.single", "onEdgesChange.add.single", "onEdgesChange.add.many", "onEdgesChange.add.many", "onEdgesChange.remove", "onEdgesChange.remove", "onEdgesChange.remove.single", "onEdgesChange.remove.single", "onEdgesChange.remove.many", "onEdgesChange.remove.many", "onEdgesChange.select", "onEdgesChange.select", "onEdgesChange.select.single", "onEdgesChange.select.single", "onEdgesChange.select.many", "onEdgesChange.select.many"] }], ngImport: i0, template: "<svg:svg\n rootSvgRef\n rootSvgContext\n rootPointer\n flowSizeController\n class=\"root-svg\"\n #flow\n>\n <defs [markers]=\"markers()\" flowDefs />\n\n <g background />\n\n <svg:g\n mapContext\n spacePointContext\n >\n <!-- Connection -->\n <svg:g\n connection\n [model]=\"connection\"\n [template]=\"connectionTemplateDirective?.templateRef\"\n />\n\n <!-- Edges -->\n <svg:g\n *ngFor=\"let model of edgeModels(); trackBy: trackEdges\"\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective?.templateRef\"\n />\n\n <!-- Nodes -->\n <svg:g\n *ngFor=\"let model of nodeModels(); trackBy: trackNodes\"\n node\n [nodeModel]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective?.templateRef\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective?.templateRef\"\n [attr.transform]=\"model.pointTransform()\"\n />\n </svg:g>\n\n <!-- Minimap -->\n <ng-container *ngIf=\"minimap() as minimap\">\n <ng-container [ngTemplateOutlet]=\"minimap.template()\" />\n </ng-container>\n</svg:svg>\n\n", styles: [":host{display:block;width:100%;height:100%;-webkit-user-select:none;user-select:none}:host ::ng-deep *{box-sizing:border-box}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: NodeComponent, selector: "g[node]", inputs: ["nodeModel", "nodeTemplate", "groupNodeTemplate"] }, { kind: "component", type: EdgeComponent, selector: "g[edge]", inputs: ["model", "edgeTemplate", "edgeLabelHtmlTemplate"] }, { kind: "component", type: ConnectionComponent, selector: "g[connection]", inputs: ["model", "template"] }, { kind: "component", type: DefsComponent, selector: "defs[flowDefs]", inputs: ["markers"] }, { kind: "component", type: BackgroundComponent, selector: "g[background]" }, { kind: "directive", type: SpacePointContextDirective, selector: "g[spacePointContext]" }, { kind: "directive", type: MapContextDirective, selector: "g[mapContext]" }, { kind: "directive", type: RootSvgReferenceDirective, selector: "svg[rootSvgRef]" }, { kind: "directive", type: RootSvgContextDirective, selector: "svg[rootSvgContext]" }, { kind: "directive", type: RootPointerDirective, selector: "svg[rootPointer]" }, { kind: "directive", type: FlowSizeControllerDirective, selector: "svg[flowSizeController]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3201
+ OverlaysService,
3202
+ ], 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: ConnectionControllerDirective, outputs: ["onConnect", "onConnect"] }, { directive: ChangesControllerDirective, outputs: ["onNodesChange", "onNodesChange", "onNodesChange.position", "onNodesChange.position", "onNodesChange.position.single", "onNodesChange.position.single", "onNodesChange.position.many", "onNodesChange.position.many", "onNodesChange.size", "onNodesChange.size", "onNodesChange.size.single", "onNodesChange.size.single", "onNodesChange.size.many", "onNodesChange.size.many", "onNodesChange.add", "onNodesChange.add", "onNodesChange.add.single", "onNodesChange.add.single", "onNodesChange.add.many", "onNodesChange.add.many", "onNodesChange.remove", "onNodesChange.remove", "onNodesChange.remove.single", "onNodesChange.remove.single", "onNodesChange.remove.many", "onNodesChange.remove.many", "onNodesChange.select", "onNodesChange.select", "onNodesChange.select.single", "onNodesChange.select.single", "onNodesChange.select.many", "onNodesChange.select.many", "onEdgesChange", "onEdgesChange", "onEdgesChange.detached", "onEdgesChange.detached", "onEdgesChange.detached.single", "onEdgesChange.detached.single", "onEdgesChange.detached.many", "onEdgesChange.detached.many", "onEdgesChange.add", "onEdgesChange.add", "onEdgesChange.add.single", "onEdgesChange.add.single", "onEdgesChange.add.many", "onEdgesChange.add.many", "onEdgesChange.remove", "onEdgesChange.remove", "onEdgesChange.remove.single", "onEdgesChange.remove.single", "onEdgesChange.remove.many", "onEdgesChange.remove.many", "onEdgesChange.select", "onEdgesChange.select", "onEdgesChange.select.single", "onEdgesChange.select.single", "onEdgesChange.select.many", "onEdgesChange.select.many"] }], ngImport: i0, template: "<svg:svg\n rootSvgRef\n rootSvgContext\n rootPointer\n flowSizeController\n class=\"root-svg\"\n #flow\n>\n <defs [markers]=\"markers()\" flowDefs />\n\n <g background />\n\n <svg:g mapContext spacePointContext>\n <!-- Connection -->\n <svg:g\n connection\n [model]=\"connection\"\n [template]=\"connectionTemplateDirective()?.templateRef\"\n />\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 }\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 }\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\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 }\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 }\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 }); }
2956
3203
  }
2957
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: VflowComponent, decorators: [{
3204
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: VflowComponent, decorators: [{
2958
3205
  type: Component,
2959
- args: [{ selector: 'vflow', changeDetection: ChangeDetectionStrategy.OnPush, providers: [
3206
+ args: [{ standalone: true, selector: 'vflow', changeDetection: ChangeDetectionStrategy.OnPush, providers: [
2960
3207
  DraggableService,
2961
3208
  ViewportService,
2962
3209
  FlowStatusService,
@@ -2968,60 +3215,73 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
2968
3215
  FlowSettingsService,
2969
3216
  ComponentEventBusService,
2970
3217
  KeyboardService,
2971
- OverlaysService
3218
+ OverlaysService,
2972
3219
  ], hostDirectives: [
2973
3220
  connectionControllerHostDirective,
2974
- changesControllerHostDirective
2975
- ], template: "<svg:svg\n rootSvgRef\n rootSvgContext\n rootPointer\n flowSizeController\n class=\"root-svg\"\n #flow\n>\n <defs [markers]=\"markers()\" flowDefs />\n\n <g background />\n\n <svg:g\n mapContext\n spacePointContext\n >\n <!-- Connection -->\n <svg:g\n connection\n [model]=\"connection\"\n [template]=\"connectionTemplateDirective?.templateRef\"\n />\n\n <!-- Edges -->\n <svg:g\n *ngFor=\"let model of edgeModels(); trackBy: trackEdges\"\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective?.templateRef\"\n />\n\n <!-- Nodes -->\n <svg:g\n *ngFor=\"let model of nodeModels(); trackBy: trackNodes\"\n node\n [nodeModel]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective?.templateRef\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective?.templateRef\"\n [attr.transform]=\"model.pointTransform()\"\n />\n </svg:g>\n\n <!-- Minimap -->\n <ng-container *ngIf=\"minimap() as minimap\">\n <ng-container [ngTemplateOutlet]=\"minimap.template()\" />\n </ng-container>\n</svg:svg>\n\n", styles: [":host{display:block;width:100%;height:100%;-webkit-user-select:none;user-select:none}:host ::ng-deep *{box-sizing:border-box}\n"] }]
3221
+ changesControllerHostDirective,
3222
+ ], imports: [
3223
+ RootSvgReferenceDirective,
3224
+ RootSvgContextDirective,
3225
+ RootPointerDirective,
3226
+ FlowSizeControllerDirective,
3227
+ DefsComponent,
3228
+ BackgroundComponent,
3229
+ MapContextDirective,
3230
+ SpacePointContextDirective,
3231
+ ConnectionComponent,
3232
+ NodeComponent,
3233
+ EdgeComponent,
3234
+ NgTemplateOutlet,
3235
+ ], template: "<svg:svg\n rootSvgRef\n rootSvgContext\n rootPointer\n flowSizeController\n class=\"root-svg\"\n #flow\n>\n <defs [markers]=\"markers()\" flowDefs />\n\n <g background />\n\n <svg:g mapContext spacePointContext>\n <!-- Connection -->\n <svg:g\n connection\n [model]=\"connection\"\n [template]=\"connectionTemplateDirective()?.templateRef\"\n />\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 }\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 }\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\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 }\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 }\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"] }]
2976
3236
  }], propDecorators: { view: [{
2977
3237
  type: Input
2978
3238
  }], minZoom: [{
2979
3239
  type: Input
2980
3240
  }], maxZoom: [{
2981
3241
  type: Input
2982
- }], handlePositions: [{
2983
- type: Input
2984
3242
  }], background: [{
2985
3243
  type: Input
2986
- }], optimization: [{
2987
- type: Input
2988
3244
  }], entitiesSelectable: [{
2989
3245
  type: Input
2990
3246
  }], keyboardShortcuts: [{
2991
3247
  type: Input
2992
3248
  }], connection: [{
2993
3249
  type: Input,
2994
- args: [{ transform: (settings) => new ConnectionModel(settings) }]
3250
+ args: [{
3251
+ transform: (settings) => new ConnectionModel(settings),
3252
+ }]
2995
3253
  }], nodes: [{
2996
3254
  type: Input,
2997
3255
  args: [{ required: true }]
2998
3256
  }], edges: [{
2999
3257
  type: Input
3000
- }], onComponentNodeEvent: [{
3001
- type: Output
3002
- }], nodeTemplateDirective: [{
3003
- type: ContentChild,
3004
- args: [NodeHtmlTemplateDirective]
3005
- }], groupNodeTemplateDirective: [{
3006
- type: ContentChild,
3007
- args: [GroupNodeTemplateDirective]
3008
- }], edgeTemplateDirective: [{
3009
- type: ContentChild,
3010
- args: [EdgeTemplateDirective]
3011
- }], edgeLabelHtmlDirective: [{
3012
- type: ContentChild,
3013
- args: [EdgeLabelHtmlTemplateDirective]
3014
- }], connectionTemplateDirective: [{
3015
- type: ContentChild,
3016
- args: [ConnectionTemplateDirective]
3017
- }], mapContext: [{
3018
- type: ViewChild,
3019
- args: [MapContextDirective]
3020
- }], spacePointContext: [{
3021
- type: ViewChild,
3022
- args: [SpacePointContextDirective]
3023
3258
  }] } });
3024
3259
 
3260
+ class DragHandleDirective {
3261
+ get model() {
3262
+ return this.nodeAccessor.model();
3263
+ }
3264
+ constructor() {
3265
+ this.nodeAccessor = inject(NodeAccessorService);
3266
+ this.model.dragHandlesCount.update((count) => count + 1);
3267
+ inject(DestroyRef).onDestroy(() => {
3268
+ this.model.dragHandlesCount.update(count => count - 1);
3269
+ });
3270
+ }
3271
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DragHandleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3272
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: DragHandleDirective, isStandalone: true, selector: "[dragHandle]", host: { classAttribute: "vflow-drag-handle" }, ngImport: i0 }); }
3273
+ }
3274
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DragHandleDirective, decorators: [{
3275
+ type: Directive,
3276
+ args: [{
3277
+ standalone: true,
3278
+ selector: '[dragHandle]',
3279
+ host: {
3280
+ 'class': 'vflow-drag-handle'
3281
+ },
3282
+ }]
3283
+ }], ctorParameters: () => [] });
3284
+
3025
3285
  class SelectableDirective {
3026
3286
  constructor() {
3027
3287
  this.flowSettingsService = inject(FlowSettingsService);
@@ -3037,19 +3297,22 @@ class SelectableDirective {
3037
3297
  }
3038
3298
  entity() {
3039
3299
  if (this.parentNode) {
3040
- return this.parentNode.nodeModel;
3300
+ return this.parentNode.nodeModel();
3041
3301
  }
3042
3302
  else if (this.parentEdge) {
3043
- return this.parentEdge.model;
3303
+ return this.parentEdge.model();
3044
3304
  }
3045
3305
  return null;
3046
3306
  }
3047
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SelectableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3048
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: SelectableDirective, selector: "[selectable]", host: { listeners: { "mousedown": "onMousedown()", "touchstart": "onMousedown()" } }, ngImport: i0 }); }
3307
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3308
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: SelectableDirective, isStandalone: true, selector: "[selectable]", host: { listeners: { "mousedown": "onMousedown()", "touchstart": "onMousedown()" } }, ngImport: i0 }); }
3049
3309
  }
3050
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SelectableDirective, decorators: [{
3310
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectableDirective, decorators: [{
3051
3311
  type: Directive,
3052
- args: [{ selector: '[selectable]' }]
3312
+ args: [{
3313
+ standalone: true,
3314
+ selector: '[selectable]',
3315
+ }]
3053
3316
  }], propDecorators: { onMousedown: [{
3054
3317
  type: HostListener,
3055
3318
  args: ['mousedown']
@@ -3073,38 +3336,61 @@ class MiniMapComponent {
3073
3336
  /**
3074
3337
  * The color outside the viewport (invisible area)
3075
3338
  */
3076
- this.maskColor = `rgba(215, 215, 215, 0.6)`;
3339
+ this.maskColor = input(`rgba(215, 215, 215, 0.6)`);
3077
3340
  /**
3078
3341
  * The minimap stroke color
3079
3342
  */
3080
- this.strokeColor = `rgb(200, 200, 200)`;
3343
+ this.strokeColor = input(`rgb(200, 200, 200)`);
3344
+ /**
3345
+ * The corner of the flow where to render a mini-map
3346
+ */
3347
+ this.position = input('bottom-right');
3348
+ /**
3349
+ * Make a minimap bigger on hover
3350
+ */
3351
+ this.scaleOnHover = input(false);
3352
+ this.minimap = viewChild.required('minimap');
3081
3353
  this.minimapOffset = 10;
3082
3354
  this.minimapScale = computed(() => {
3083
- if (this.scaleOnHoverSignal()) {
3355
+ if (this.scaleOnHover()) {
3084
3356
  return this.hovered() ? 0.4 : 0.2;
3085
3357
  }
3086
3358
  return 0.2;
3087
3359
  });
3088
- this.viewportColor = computed(() => this.flowSettingsService.background().color ?? '#fff');
3360
+ this.viewportColor = computed(() => {
3361
+ const bg = this.flowSettingsService.background();
3362
+ if (bg.type === 'dots' || bg.type === 'solid') {
3363
+ return bg.color ?? '#fff';
3364
+ }
3365
+ return '#fff';
3366
+ });
3089
3367
  this.hovered = signal(false);
3090
3368
  this.minimapPoint = computed(() => {
3091
- switch (this.minimapPosition()) {
3369
+ switch (this.position()) {
3092
3370
  case 'top-left':
3093
3371
  return { x: this.minimapOffset, y: this.minimapOffset };
3094
3372
  case 'top-right':
3095
3373
  return {
3096
- x: this.flowSettingsService.computedFlowWidth() - this.minimapWidth() - this.minimapOffset,
3097
- y: this.minimapOffset
3374
+ x: this.flowSettingsService.computedFlowWidth() -
3375
+ this.minimapWidth() -
3376
+ this.minimapOffset,
3377
+ y: this.minimapOffset,
3098
3378
  };
3099
3379
  case 'bottom-left':
3100
3380
  return {
3101
3381
  x: this.minimapOffset,
3102
- y: this.flowSettingsService.computedFlowHeight() - this.minimapHeight() - this.minimapOffset
3382
+ y: this.flowSettingsService.computedFlowHeight() -
3383
+ this.minimapHeight() -
3384
+ this.minimapOffset,
3103
3385
  };
3104
3386
  case 'bottom-right':
3105
3387
  return {
3106
- x: this.flowSettingsService.computedFlowWidth() - this.minimapWidth() - this.minimapOffset,
3107
- y: this.flowSettingsService.computedFlowHeight() - this.minimapHeight() - this.minimapOffset
3388
+ x: this.flowSettingsService.computedFlowWidth() -
3389
+ this.minimapWidth() -
3390
+ this.minimapOffset,
3391
+ y: this.flowSettingsService.computedFlowHeight() -
3392
+ this.minimapHeight() -
3393
+ this.minimapOffset,
3108
3394
  };
3109
3395
  }
3110
3396
  });
@@ -3131,47 +3417,22 @@ class MiniMapComponent {
3131
3417
  const scale = vport.zoom * this.minimapScale();
3132
3418
  return `translate(${x} ${y}) scale(${scale})`;
3133
3419
  });
3134
- this.minimapPosition = signal('bottom-right');
3135
- this.scaleOnHoverSignal = signal(false);
3136
- }
3137
- /**
3138
- * The corner of the flow where to render a mini-map
3139
- */
3140
- set position(value) {
3141
- this.minimapPosition.set(value);
3142
- }
3143
- /**
3144
- * Make a minimap bigger on hover
3145
- */
3146
- set scaleOnHover(value) {
3147
- this.scaleOnHoverSignal.set(value);
3148
3420
  }
3149
3421
  ngOnInit() {
3150
3422
  const model = new MinimapModel();
3151
- model.template.set(this.minimap);
3423
+ model.template.set(this.minimap());
3152
3424
  this.entitiesService.minimap.set(model);
3153
3425
  }
3154
3426
  trackNodes(idx, { node }) {
3155
3427
  return node;
3156
3428
  }
3157
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MiniMapComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3158
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: MiniMapComponent, selector: "mini-map", inputs: { position: "position", maskColor: "maskColor", strokeColor: "strokeColor", scaleOnHover: "scaleOnHover" }, viewQueries: [{ propertyName: "minimap", first: true, predicate: ["minimap"], descendants: true, static: true }], ngImport: i0, template: "<ng-template #minimap>\n <svg:rect\n [attr.x]=\"minimapPoint().x\"\n [attr.y]=\"minimapPoint().y\"\n [attr.width]=\"minimapWidth()\"\n [attr.height]=\"minimapHeight()\"\n [attr.stroke]=\"strokeColor\"\n fill=\"none\"\n />\n\n <svg:svg\n [attr.x]=\"minimapPoint().x\"\n [attr.y]=\"minimapPoint().y\"\n [attr.width]=\"minimapWidth()\"\n [attr.height]=\"minimapHeight()\"\n (mouseover)=\"hovered.set(true)\"\n (mouseleave)=\"hovered.set(false)\"\n >\n <svg:rect\n [attr.width]=\"minimapWidth()\"\n [attr.height]=\"minimapHeight()\"\n [attr.fill]=\"maskColor\"\n />\n\n <svg:g [attr.transform]=\"minimapTransform()\">\n <svg:rect\n [attr.fill]=\"viewportColor()\"\n [attr.transform]=\"viewportTransform()\"\n [attr.width]=\"minimapWidth()\"\n [attr.height]=\"minimapHeight()\"\n />\n\n <ng-container\n *ngFor=\"let model of entitiesService.nodes(); trackBy: trackNodes\"\n >\n <svg:foreignObject\n *ngIf=\"model.node.type === 'default' || model.node.type === 'html-template' || model.isComponentType\"\n [attr.transform]=\"model.pointTransform()\"\n [attr.width]=\"model.size().width\"\n [attr.height]=\"model.size().height\"\n >\n <default-node\n [selected]=\"model.selected()\"\n [style.width.px]=\"model.size().width\"\n [style.height.px]=\"model.size().height\"\n [style.max-width.px]=\"model.size().width\"\n [style.max-height.px]=\"model.size().height\"\n >\n <div [outerHTML]=\"model.text()\"></div>\n </default-node>\n </svg:foreignObject>\n\n <svg:rect\n *ngIf=\"model.node.type === 'default-group' || model.node.type === 'template-group'\"\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [attr.transform]=\"model.pointTransform()\"\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 />\n\n </ng-container>\n </svg:g>\n </svg:svg>\n</ng-template>\n", styles: [".default-group-node{stroke-width:1.5px;fill-opacity:.05}.default-group-node_selected{stroke-width:2px}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: DefaultNodeComponent, selector: "default-node", inputs: ["selected"] }] }); }
3429
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MiniMapComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3430
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: MiniMapComponent, 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 } }, viewQueries: [{ propertyName: "minimap", first: true, predicate: ["minimap"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-template #minimap>\n <svg:rect\n [attr.x]=\"minimapPoint().x\"\n [attr.y]=\"minimapPoint().y\"\n [attr.width]=\"minimapWidth()\"\n [attr.height]=\"minimapHeight()\"\n [attr.stroke]=\"strokeColor()\"\n fill=\"none\"\n />\n\n <svg:svg\n [attr.x]=\"minimapPoint().x\"\n [attr.y]=\"minimapPoint().y\"\n [attr.width]=\"minimapWidth()\"\n [attr.height]=\"minimapHeight()\"\n (mouseover)=\"hovered.set(true)\"\n (mouseleave)=\"hovered.set(false)\"\n >\n <svg:rect\n [attr.width]=\"minimapWidth()\"\n [attr.height]=\"minimapHeight()\"\n [attr.fill]=\"maskColor()\"\n />\n\n <svg:g [attr.transform]=\"minimapTransform()\">\n <svg:rect\n [attr.fill]=\"viewportColor()\"\n [attr.transform]=\"viewportTransform()\"\n [attr.width]=\"minimapWidth()\"\n [attr.height]=\"minimapHeight()\"\n />\n\n @for (model of entitiesService.nodes(); track trackNodes($index, model)) {\n <ng-container>\n @if (\n model.node.type === \"default\" ||\n model.node.type === \"html-template\" ||\n model.isComponentType\n ) {\n <svg:foreignObject\n [attr.transform]=\"model.pointTransform()\"\n [attr.width]=\"model.size().width\"\n [attr.height]=\"model.size().height\"\n >\n <default-node\n [selected]=\"model.selected()\"\n [style.width.px]=\"model.size().width\"\n [style.height.px]=\"model.size().height\"\n [style.max-width.px]=\"model.size().width\"\n [style.max-height.px]=\"model.size().height\"\n >\n <div [outerHTML]=\"model.text()\"></div>\n </default-node>\n </svg:foreignObject>\n }\n @if (\n model.node.type === \"default-group\" ||\n model.node.type === \"template-group\"\n ) {\n <svg:rect\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [attr.transform]=\"model.pointTransform()\"\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 />\n }\n </ng-container>\n }\n </svg:g>\n </svg:svg>\n</ng-template>\n", styles: [".default-group-node{stroke-width:1.5px;fill-opacity:.05}.default-group-node_selected{stroke-width:2px}\n"], dependencies: [{ kind: "component", type: DefaultNodeComponent, selector: "default-node", inputs: ["selected"] }] }); }
3159
3431
  }
3160
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MiniMapComponent, decorators: [{
3432
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MiniMapComponent, decorators: [{
3161
3433
  type: Component,
3162
- args: [{ selector: 'mini-map', template: "<ng-template #minimap>\n <svg:rect\n [attr.x]=\"minimapPoint().x\"\n [attr.y]=\"minimapPoint().y\"\n [attr.width]=\"minimapWidth()\"\n [attr.height]=\"minimapHeight()\"\n [attr.stroke]=\"strokeColor\"\n fill=\"none\"\n />\n\n <svg:svg\n [attr.x]=\"minimapPoint().x\"\n [attr.y]=\"minimapPoint().y\"\n [attr.width]=\"minimapWidth()\"\n [attr.height]=\"minimapHeight()\"\n (mouseover)=\"hovered.set(true)\"\n (mouseleave)=\"hovered.set(false)\"\n >\n <svg:rect\n [attr.width]=\"minimapWidth()\"\n [attr.height]=\"minimapHeight()\"\n [attr.fill]=\"maskColor\"\n />\n\n <svg:g [attr.transform]=\"minimapTransform()\">\n <svg:rect\n [attr.fill]=\"viewportColor()\"\n [attr.transform]=\"viewportTransform()\"\n [attr.width]=\"minimapWidth()\"\n [attr.height]=\"minimapHeight()\"\n />\n\n <ng-container\n *ngFor=\"let model of entitiesService.nodes(); trackBy: trackNodes\"\n >\n <svg:foreignObject\n *ngIf=\"model.node.type === 'default' || model.node.type === 'html-template' || model.isComponentType\"\n [attr.transform]=\"model.pointTransform()\"\n [attr.width]=\"model.size().width\"\n [attr.height]=\"model.size().height\"\n >\n <default-node\n [selected]=\"model.selected()\"\n [style.width.px]=\"model.size().width\"\n [style.height.px]=\"model.size().height\"\n [style.max-width.px]=\"model.size().width\"\n [style.max-height.px]=\"model.size().height\"\n >\n <div [outerHTML]=\"model.text()\"></div>\n </default-node>\n </svg:foreignObject>\n\n <svg:rect\n *ngIf=\"model.node.type === 'default-group' || model.node.type === 'template-group'\"\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [attr.transform]=\"model.pointTransform()\"\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 />\n\n </ng-container>\n </svg:g>\n </svg:svg>\n</ng-template>\n", styles: [".default-group-node{stroke-width:1.5px;fill-opacity:.05}.default-group-node_selected{stroke-width:2px}\n"] }]
3163
- }], propDecorators: { position: [{
3164
- type: Input
3165
- }], maskColor: [{
3166
- type: Input
3167
- }], strokeColor: [{
3168
- type: Input
3169
- }], scaleOnHover: [{
3170
- type: Input
3171
- }], minimap: [{
3172
- type: ViewChild,
3173
- args: ['minimap', { static: true }]
3174
- }] } });
3434
+ args: [{ standalone: true, selector: 'mini-map', imports: [DefaultNodeComponent], template: "<ng-template #minimap>\n <svg:rect\n [attr.x]=\"minimapPoint().x\"\n [attr.y]=\"minimapPoint().y\"\n [attr.width]=\"minimapWidth()\"\n [attr.height]=\"minimapHeight()\"\n [attr.stroke]=\"strokeColor()\"\n fill=\"none\"\n />\n\n <svg:svg\n [attr.x]=\"minimapPoint().x\"\n [attr.y]=\"minimapPoint().y\"\n [attr.width]=\"minimapWidth()\"\n [attr.height]=\"minimapHeight()\"\n (mouseover)=\"hovered.set(true)\"\n (mouseleave)=\"hovered.set(false)\"\n >\n <svg:rect\n [attr.width]=\"minimapWidth()\"\n [attr.height]=\"minimapHeight()\"\n [attr.fill]=\"maskColor()\"\n />\n\n <svg:g [attr.transform]=\"minimapTransform()\">\n <svg:rect\n [attr.fill]=\"viewportColor()\"\n [attr.transform]=\"viewportTransform()\"\n [attr.width]=\"minimapWidth()\"\n [attr.height]=\"minimapHeight()\"\n />\n\n @for (model of entitiesService.nodes(); track trackNodes($index, model)) {\n <ng-container>\n @if (\n model.node.type === \"default\" ||\n model.node.type === \"html-template\" ||\n model.isComponentType\n ) {\n <svg:foreignObject\n [attr.transform]=\"model.pointTransform()\"\n [attr.width]=\"model.size().width\"\n [attr.height]=\"model.size().height\"\n >\n <default-node\n [selected]=\"model.selected()\"\n [style.width.px]=\"model.size().width\"\n [style.height.px]=\"model.size().height\"\n [style.max-width.px]=\"model.size().width\"\n [style.max-height.px]=\"model.size().height\"\n >\n <div [outerHTML]=\"model.text()\"></div>\n </default-node>\n </svg:foreignObject>\n }\n @if (\n model.node.type === \"default-group\" ||\n model.node.type === \"template-group\"\n ) {\n <svg:rect\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [attr.transform]=\"model.pointTransform()\"\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 />\n }\n </ng-container>\n }\n </svg:g>\n </svg:svg>\n</ng-template>\n", styles: [".default-group-node{stroke-width:1.5px;fill-opacity:.05}.default-group-node_selected{stroke-width:2px}\n"] }]
3435
+ }] });
3175
3436
 
3176
3437
  class ToolbarModel {
3177
3438
  constructor(node) {
@@ -3212,114 +3473,67 @@ class NodeToolbarComponent {
3212
3473
  constructor() {
3213
3474
  this.overlaysService = inject(OverlaysService);
3214
3475
  this.nodeService = inject(NodeAccessorService);
3476
+ this.position = input('top');
3477
+ this.toolbarContentTemplate = viewChild.required('toolbar');
3215
3478
  this.model = new ToolbarModel(this.nodeService.model());
3216
- }
3217
- set position(value) {
3218
- this.model.position.set(value);
3479
+ effect(() => this.model.position.set(this.position()), { allowSignalWrites: true });
3219
3480
  }
3220
3481
  ngOnInit() {
3221
- this.model.template.set(this.toolbarContentTemplate);
3482
+ this.model.template.set(this.toolbarContentTemplate());
3222
3483
  this.overlaysService.addToolbar(this.model);
3223
3484
  }
3224
3485
  ngOnDestroy() {
3225
3486
  this.overlaysService.removeToolbar(this.model);
3226
3487
  }
3227
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3228
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: NodeToolbarComponent, selector: "node-toolbar", inputs: { position: "position" }, viewQueries: [{ propertyName: "toolbarContentTemplate", first: true, predicate: ["toolbar"], descendants: true, static: true }], ngImport: i0, template: `
3488
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3489
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "17.3.12", type: NodeToolbarComponent, isStandalone: true, selector: "node-toolbar", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "toolbarContentTemplate", first: true, predicate: ["toolbar"], descendants: true, isSignal: true }], ngImport: i0, template: `
3229
3490
  <ng-template #toolbar>
3230
3491
  <div class="wrapper" nodeToolbarWrapper [model]="model">
3231
3492
  <ng-content />
3232
3493
  </div>
3233
3494
  </ng-template>
3234
- `, isInline: true, styles: [".wrapper{width:max-content}\n"], dependencies: [{ kind: "directive", type: i0.forwardRef(function () { return NodeToolbarWrapperDirective; }), selector: "[nodeToolbarWrapper]", inputs: ["model"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3495
+ `, isInline: true, styles: [".wrapper{width:max-content}\n"], dependencies: [{ kind: "directive", type: i0.forwardRef(() => NodeToolbarWrapperDirective), selector: "[nodeToolbarWrapper]", inputs: ["model"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3235
3496
  }
3236
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeToolbarComponent, decorators: [{
3497
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeToolbarComponent, decorators: [{
3237
3498
  type: Component,
3238
- args: [{ selector: 'node-toolbar', template: `
3499
+ args: [{ standalone: true, selector: 'node-toolbar', template: `
3239
3500
  <ng-template #toolbar>
3240
3501
  <div class="wrapper" nodeToolbarWrapper [model]="model">
3241
3502
  <ng-content />
3242
3503
  </div>
3243
3504
  </ng-template>
3244
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".wrapper{width:max-content}\n"] }]
3245
- }], propDecorators: { position: [{
3246
- type: Input
3247
- }], toolbarContentTemplate: [{
3248
- type: ViewChild,
3249
- args: ['toolbar', { static: true }]
3250
- }] } });
3505
+ `, changeDetection: ChangeDetectionStrategy.OnPush, imports: [forwardRef(() => NodeToolbarWrapperDirective)], styles: [".wrapper{width:max-content}\n"] }]
3506
+ }], ctorParameters: () => [] });
3251
3507
  class NodeToolbarWrapperDirective {
3252
3508
  constructor() {
3253
3509
  this.element = inject(ElementRef);
3510
+ this.model = input.required();
3254
3511
  }
3255
3512
  ngOnInit() {
3256
- this.model.size.set({
3513
+ this.model().size.set({
3257
3514
  width: this.element.nativeElement.clientWidth,
3258
- height: this.element.nativeElement.clientHeight
3259
- });
3260
- }
3261
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeToolbarWrapperDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3262
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: NodeToolbarWrapperDirective, selector: "[nodeToolbarWrapper]", inputs: { model: "model" }, ngImport: i0 }); }
3263
- }
3264
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeToolbarWrapperDirective, decorators: [{
3265
- type: Directive,
3266
- args: [{ selector: '[nodeToolbarWrapper]' }]
3267
- }], propDecorators: { model: [{
3268
- type: Input
3269
- }] } });
3270
-
3271
- class DragHandleDirective {
3272
- get model() {
3273
- return this.nodeAccessor.model();
3274
- }
3275
- constructor() {
3276
- this.nodeAccessor = inject(NodeAccessorService);
3277
- this.model.dragHandlesCount.update((count) => count + 1);
3278
- inject(DestroyRef).onDestroy(() => {
3279
- this.model.dragHandlesCount.update(count => count - 1);
3515
+ height: this.element.nativeElement.clientHeight,
3280
3516
  });
3281
3517
  }
3282
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DragHandleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3283
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: DragHandleDirective, selector: "[dragHandle]", host: { classAttribute: "vflow-drag-handle" }, ngImport: i0 }); }
3518
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeToolbarWrapperDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3519
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "17.3.12", type: NodeToolbarWrapperDirective, isStandalone: true, selector: "[nodeToolbarWrapper]", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
3284
3520
  }
3285
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DragHandleDirective, decorators: [{
3521
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeToolbarWrapperDirective, decorators: [{
3286
3522
  type: Directive,
3287
3523
  args: [{
3288
- selector: '[dragHandle]',
3289
- host: {
3290
- 'class': 'vflow-drag-handle'
3291
- }
3524
+ selector: '[nodeToolbarWrapper]',
3525
+ standalone: true
3292
3526
  }]
3293
- }], ctorParameters: function () { return []; } });
3527
+ }] });
3294
3528
 
3295
- const components = [
3529
+ const Vflow = [
3296
3530
  VflowComponent,
3297
- NodeComponent,
3298
- DefaultNodeComponent,
3299
- EdgeComponent,
3300
- EdgeLabelComponent,
3301
- ConnectionComponent,
3302
3531
  HandleComponent,
3303
- DefsComponent,
3304
- BackgroundComponent,
3305
3532
  ResizableComponent,
3306
- MiniMapComponent,
3307
- NodeToolbarComponent
3308
- ];
3309
- const directives = [
3310
- SpacePointContextDirective,
3311
- MapContextDirective,
3312
- RootSvgReferenceDirective,
3313
- RootSvgContextDirective,
3314
- HandleSizeControllerDirective,
3315
3533
  SelectableDirective,
3534
+ MiniMapComponent,
3535
+ NodeToolbarComponent,
3316
3536
  DragHandleDirective,
3317
- PointerDirective,
3318
- RootPointerDirective,
3319
- FlowSizeControllerDirective,
3320
- NodeToolbarWrapperDirective
3321
- ];
3322
- const templateDirectives = [
3323
3537
  NodeHtmlTemplateDirective,
3324
3538
  GroupNodeTemplateDirective,
3325
3539
  EdgeLabelHtmlTemplateDirective,
@@ -3327,65 +3541,6 @@ const templateDirectives = [
3327
3541
  ConnectionTemplateDirective,
3328
3542
  HandleTemplateDirective
3329
3543
  ];
3330
- class VflowModule {
3331
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: VflowModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
3332
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: VflowModule, declarations: [VflowComponent,
3333
- NodeComponent,
3334
- DefaultNodeComponent,
3335
- EdgeComponent,
3336
- EdgeLabelComponent,
3337
- ConnectionComponent,
3338
- HandleComponent,
3339
- DefsComponent,
3340
- BackgroundComponent,
3341
- ResizableComponent,
3342
- MiniMapComponent,
3343
- NodeToolbarComponent, SpacePointContextDirective,
3344
- MapContextDirective,
3345
- RootSvgReferenceDirective,
3346
- RootSvgContextDirective,
3347
- HandleSizeControllerDirective,
3348
- SelectableDirective,
3349
- DragHandleDirective,
3350
- PointerDirective,
3351
- RootPointerDirective,
3352
- FlowSizeControllerDirective,
3353
- NodeToolbarWrapperDirective, NodeHtmlTemplateDirective,
3354
- GroupNodeTemplateDirective,
3355
- EdgeLabelHtmlTemplateDirective,
3356
- EdgeTemplateDirective,
3357
- ConnectionTemplateDirective,
3358
- HandleTemplateDirective], imports: [NgIf, NgFor, NgTemplateOutlet, NgComponentOutlet, KeyValuePipe], exports: [VflowComponent,
3359
- HandleComponent,
3360
- ResizableComponent,
3361
- SelectableDirective,
3362
- MiniMapComponent,
3363
- NodeToolbarComponent,
3364
- DragHandleDirective, NodeHtmlTemplateDirective,
3365
- GroupNodeTemplateDirective,
3366
- EdgeLabelHtmlTemplateDirective,
3367
- EdgeTemplateDirective,
3368
- ConnectionTemplateDirective,
3369
- HandleTemplateDirective] }); }
3370
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: VflowModule }); }
3371
- }
3372
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: VflowModule, decorators: [{
3373
- type: NgModule,
3374
- args: [{
3375
- imports: [NgIf, NgFor, NgTemplateOutlet, NgComponentOutlet, KeyValuePipe],
3376
- exports: [
3377
- VflowComponent,
3378
- HandleComponent,
3379
- ResizableComponent,
3380
- SelectableDirective,
3381
- MiniMapComponent,
3382
- NodeToolbarComponent,
3383
- DragHandleDirective,
3384
- ...templateDirectives
3385
- ],
3386
- declarations: [...components, ...directives, ...templateDirectives],
3387
- }]
3388
- }] });
3389
3544
 
3390
3545
  const mockModel = () => new NodeModel({ id: 'mock', type: 'default', point: { x: 0, y: 0 } });
3391
3546
  function provideCustomNodeMocks() {
@@ -3442,11 +3597,11 @@ function provideCustomNodeMocks() {
3442
3597
  ];
3443
3598
  }
3444
3599
 
3445
- // Modules
3600
+ // Standalone Util
3446
3601
 
3447
3602
  /**
3448
3603
  * Generated bundle index. Do not edit.
3449
3604
  */
3450
3605
 
3451
- export { ChangesControllerDirective, ConnectionControllerDirective, ConnectionTemplateDirective, CustomDynamicNodeComponent, CustomNodeComponent, DragHandleDirective, EdgeLabelHtmlTemplateDirective, EdgeTemplateDirective, GroupNodeTemplateDirective, HandleComponent, HandleTemplateDirective, MiniMapComponent, NodeHtmlTemplateDirective, NodeToolbarComponent, NodeToolbarWrapperDirective, ResizableComponent, SelectableDirective, VflowComponent, VflowModule, isComponentDynamicNode, isComponentStaticNode, isDefaultDynamicGroupNode, isDefaultDynamicNode, isDefaultStaticGroupNode, isDefaultStaticNode, isDynamicNode, isStaticNode, isTemplateDynamicGroupNode, isTemplateDynamicNode, isTemplateStaticGroupNode, isTemplateStaticNode, provideCustomNodeMocks };
3606
+ 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 };
3452
3607
  //# sourceMappingURL=ngx-vflow.mjs.map