UNPKG

@foblex/flow

Version:

An Angular library designed to simplify the creation and manipulation of dynamic flow. Provides components for flows, nodes, and connections, automating node manipulation and inter-node connections.

1,130 lines (1,052 loc) 495 kB
import * as i0 from '@angular/core'; import { InjectionToken, inject, Injectable, effect, Directive, input, computed, DestroyRef, EventEmitter, booleanAttribute, Input, Output, ElementRef, Inject, Component, ChangeDetectionStrategy, ViewChild, Optional, numberAttribute, ContentChildren, Injector, ViewContainerRef, TemplateRef, NgZone, contentChild, output, viewChild, Renderer2, NgModule } from '@angular/core'; import { RectExtensions, RoundedRect, TransformModelExtensions, PointExtensions, SizeExtensions, Point, LineExtensions, GetIntersections, findClosestAlignment, setRectToElement, adjustRectToMinSize, setRectToViewBox } from '@foblex/2d'; import { __decorate } from 'tslib'; import * as i2$1 from '@foblex/mediator'; import { FExecutionRegister, FMediator } from '@foblex/mediator'; import * as i1 from '@foblex/platform'; import { BrowserService, PlatformService, EOperationSystem } from '@foblex/platform'; import { normalizeDomElementId, castToEnum, isClosestElementHasClass, flatMap, getOrCreateRootNodeForViewRef, deepCloneNode, disableDragInteractions, extendStyles, getDataAttrValueFromClosestElementWithClass } from '@foblex/utils'; import * as i2 from '@angular/common'; import { CommonModule } from '@angular/common'; const F_BACKGROUND_PATTERN = new InjectionToken('F_BACKGROUND_PATTERN'); class GetElementRoundedRectRequest { element; constructor(element) { this.element = element; } } let GetElementRoundedRectExecution = class GetElementRoundedRectExecution { _fBrowser = inject(BrowserService); handle(request) { return this._getRoundedRect(RectExtensions.fromElement(request.element), request.element, this._getComputedStyle(request.element)); } _getRoundedRect(rect, element, styles) { return new RoundedRect(rect.x, rect.y, rect.width, rect.height, this._toPixels(styles.borderTopLeftRadius, element, styles.fontSize), this._toPixels(styles.borderTopRightRadius, element, styles.fontSize), this._toPixels(styles.borderBottomRightRadius, element, styles.fontSize), this._toPixels(styles.borderBottomLeftRadius, element, styles.fontSize)); } _getComputedStyle(element) { return this._fBrowser.window.getComputedStyle(element); } _toPixels(value, element, fontSize) { return this._fBrowser.toPixels(value, element.clientWidth, element.clientHeight, fontSize) || 0; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: GetElementRoundedRectExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: GetElementRoundedRectExecution }); }; GetElementRoundedRectExecution = __decorate([ FExecutionRegister(GetElementRoundedRectRequest) ], GetElementRoundedRectExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: GetElementRoundedRectExecution, decorators: [{ type: Injectable }] }); class AddBackgroundToStoreRequest { fBackground; constructor(fBackground) { this.fBackground = fBackground; } } class NotifyDataChangedRequest { } let NotifyDataChangedExecution = class NotifyDataChangedExecution { _fComponentsStore = inject(FComponentsStore); handle(request) { this._fComponentsStore.dataChanged(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NotifyDataChangedExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NotifyDataChangedExecution }); }; NotifyDataChangedExecution = __decorate([ FExecutionRegister(NotifyDataChangedRequest) ], NotifyDataChangedExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NotifyDataChangedExecution, decorators: [{ type: Injectable }] }); class ListenDataChangesRequest { } function debounceTime(delay) { let timeoutId; return callback => { return () => { clearTimeout(timeoutId); timeoutId = setTimeout(() => callback(), delay); }; }; } class FChannel { _listeners = new Set(); notify() { this._listeners.forEach((callback) => callback()); } listen(callback) { this._listeners.add(callback); return () => this.stop(callback); } stop(callback) { this._listeners.delete(callback); } } class FResizeChannel extends FChannel { _htmlElement; _observer = new ResizeObserver(() => this.notify()); _isObserving = false; constructor(_htmlElement) { super(); this._htmlElement = _htmlElement; } listen(callback) { if (!this._isObserving) { this._observer.observe(this._htmlElement); this._isObserving = true; } return super.listen(callback); } stop(callback) { super.stop(callback); if (this._listeners.size === 0) { this._disconnect(); } } _disconnect() { this._observer.unobserve(this._htmlElement); this._observer.disconnect(); this._isObserving = false; } } class FChannelHub { _channels = []; _operators = []; constructor(...channels) { this._channels = [...channels]; } pipe(...operators) { const result = new FChannelHub(...this._channels); result._operators = [...this._operators, ...operators]; return result; } listen(destroyRef, callback) { let modifiedCallback = callback; this._operators.forEach(operator => { modifiedCallback = operator(modifiedCallback); }); const unsubscribeCallbacks = this._channels.map(channel => channel.listen(() => modifiedCallback())); destroyRef.onDestroy(() => { unsubscribeCallbacks.forEach(unsubscribe => unsubscribe()); }); } } function mediatorEffect(fn, options) { let isFirstRun = true; return effect(() => { const request = fn(); if (isFirstRun) { isFirstRun = false; return; } options?.injector?.get(FMediator).execute(request); }, options); } function notifyOnStart() { return callback => { callback(); return callback; }; } let ListenDataChangesExecution = class ListenDataChangesExecution { _fComponentsStore = inject(FComponentsStore); handle(request) { return new FChannelHub(this._fComponentsStore.dataChanges$) .pipe(notifyOnStart(), debounceTime(1)); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ListenDataChangesExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ListenDataChangesExecution }); }; ListenDataChangesExecution = __decorate([ FExecutionRegister(ListenDataChangesRequest) ], ListenDataChangesExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ListenDataChangesExecution, decorators: [{ type: Injectable }] }); class ListenCountChangesRequest { } let ListenCountChangesExecution = class ListenCountChangesExecution { _fComponentsStore = inject(FComponentsStore); handle(request) { return new FChannelHub(this._fComponentsStore.countChanges$) .pipe(notifyOnStart(), debounceTime(1)); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ListenCountChangesExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ListenCountChangesExecution }); }; ListenCountChangesExecution = __decorate([ FExecutionRegister(ListenCountChangesRequest) ], ListenCountChangesExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ListenCountChangesExecution, decorators: [{ type: Injectable }] }); class ListenTransformChangesRequest { } let ListenTransformChangesExecution = class ListenTransformChangesExecution { _fComponentsStore = inject(FComponentsStore); handle(request) { return new FChannelHub(this._fComponentsStore.transformChanges$, this._fComponentsStore.dataChanges$, this._fComponentsStore.countChanges$); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ListenTransformChangesExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ListenTransformChangesExecution }); }; ListenTransformChangesExecution = __decorate([ FExecutionRegister(ListenTransformChangesRequest) ], ListenTransformChangesExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ListenTransformChangesExecution, decorators: [{ type: Injectable }] }); class NotifyTransformChangedRequest { } class FComponentsStore { transformChanges$ = new FChannel(); dataChanges$ = new FChannel(); countChanges$ = new FChannel(); get flowHost() { return this.fFlow?.hostElement; } fComponents = {}; fFlow; fCanvas; fBackground; fNodes = []; fConnections = []; fTempConnection; fSnapConnection; fMarkers = []; fOutputs = []; fInputs = []; fOutlets = []; fDraggable; fLineAlignment; addComponent(collection, component) { collection.push(component); this.countChanged(); } removeComponent(collection, component) { const index = collection.indexOf(component); if (index > -1) { collection.splice(index, 1); this.countChanged(); } } countChanged() { this.countChanges$.notify(); } dataChanged() { this.dataChanges$.notify(); } transformChanged() { this.transformChanges$.notify(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FComponentsStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FComponentsStore }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FComponentsStore, decorators: [{ type: Injectable }] }); let NotifyTransformChangedExecution = class NotifyTransformChangedExecution { _fComponentsStore = inject(FComponentsStore); handle(request) { this._fComponentsStore.transformChanged(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NotifyTransformChangedExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NotifyTransformChangedExecution }); }; NotifyTransformChangedExecution = __decorate([ FExecutionRegister(NotifyTransformChangedRequest) ], NotifyTransformChangedExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NotifyTransformChangedExecution, decorators: [{ type: Injectable }] }); const F_STORAGE_PROVIDERS = [ NotifyDataChangedExecution, ListenCountChangesExecution, ListenDataChangesExecution, ListenTransformChangesExecution, NotifyTransformChangedExecution, FComponentsStore, ]; let AddBackgroundToStoreExecution = class AddBackgroundToStoreExecution { _fComponentsStore = inject(FComponentsStore); handle(request) { this._fComponentsStore.fBackground = request.fBackground; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddBackgroundToStoreExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddBackgroundToStoreExecution }); }; AddBackgroundToStoreExecution = __decorate([ FExecutionRegister(AddBackgroundToStoreRequest) ], AddBackgroundToStoreExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddBackgroundToStoreExecution, decorators: [{ type: Injectable }] }); class AddPatternToBackgroundRequest { fPattern; constructor(fPattern) { this.fPattern = fPattern; } } let uniqueId$c = 0; let AddPatternToBackgroundExecution = class AddPatternToBackgroundExecution { _fComponentsStore = inject(FComponentsStore); _fBrowser = inject(BrowserService); get _fBackground() { return this._fComponentsStore.fBackground; } handle(request) { const children = request.fPattern?.hostElement.getElementsByTagName('pattern') || []; const pattern = children.length ? children[0] : undefined; if (pattern) { const defs = createSVGElement('defs', this._fBrowser); pattern.id = 'f-background-pattern-' + uniqueId$c++; request.fPattern?.hostElement.remove(); defs.appendChild(pattern); this._fBackground.hostElement?.firstChild?.appendChild(defs); const rect = createSVGElement('rect', this._fBrowser); rect.setAttribute('fill', 'url(#' + pattern.id + ')'); rect.setAttribute('width', '100%'); rect.setAttribute('height', '100%'); this._fBackground.hostElement.firstChild?.appendChild(rect); const transform = this._fComponentsStore.fCanvas?.transform || TransformModelExtensions.default(); request.fPattern?.setTransform(transform); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddPatternToBackgroundExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddPatternToBackgroundExecution }); }; AddPatternToBackgroundExecution = __decorate([ FExecutionRegister(AddPatternToBackgroundRequest) ], AddPatternToBackgroundExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddPatternToBackgroundExecution, decorators: [{ type: Injectable }] }); class RemoveBackgroundFromStoreRequest { fConnection; constructor(fConnection) { this.fConnection = fConnection; } } let RemoveBackgroundFromStoreExecution = class RemoveBackgroundFromStoreExecution { _fComponentsStore = inject(FComponentsStore); handle(request) { this._fComponentsStore.fBackground = undefined; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RemoveBackgroundFromStoreExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RemoveBackgroundFromStoreExecution }); }; RemoveBackgroundFromStoreExecution = __decorate([ FExecutionRegister(RemoveBackgroundFromStoreRequest) ], RemoveBackgroundFromStoreExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RemoveBackgroundFromStoreExecution, decorators: [{ type: Injectable }] }); class SetBackgroundTransformRequest { fTransform; constructor(fTransform) { this.fTransform = fTransform; } } let SetBackgroundTransformExecution = class SetBackgroundTransformExecution { _fComponentsStore = inject(FComponentsStore); handle(request) { this._fComponentsStore.fBackground?.setTransform(request.fTransform); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SetBackgroundTransformExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SetBackgroundTransformExecution }); }; SetBackgroundTransformExecution = __decorate([ FExecutionRegister(SetBackgroundTransformRequest) ], SetBackgroundTransformExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SetBackgroundTransformExecution, decorators: [{ type: Injectable }] }); const F_BACKGROUND_FEATURES = [ AddBackgroundToStoreExecution, AddPatternToBackgroundExecution, RemoveBackgroundFromStoreExecution, SetBackgroundTransformExecution ]; class AddCanvasToStoreRequest { fCanvas; constructor(fCanvas) { this.fCanvas = fCanvas; } } let AddCanvasToStoreExecution = class AddCanvasToStoreExecution { _fComponentsStore = inject(FComponentsStore); handle(request) { this._fComponentsStore.fCanvas = request.fCanvas; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddCanvasToStoreExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddCanvasToStoreExecution }); }; AddCanvasToStoreExecution = __decorate([ FExecutionRegister(AddCanvasToStoreRequest) ], AddCanvasToStoreExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddCanvasToStoreExecution, decorators: [{ type: Injectable }] }); class CenterGroupOrNodeRequest { id; animated; constructor(id, animated) { this.id = id; this.animated = animated; } } let CenterGroupOrNodeExecution = class CenterGroupOrNodeExecution { _fComponentsStore = inject(FComponentsStore); get transform() { return this._fComponentsStore.fCanvas.transform; } _fMediator = inject(FMediator); handle(request) { const fNode = this.getNode(request.id); if (!fNode) { return; } this.toCenter(this.getNodeRect(fNode), this.getFlowRect(), fNode.position); this._fMediator.execute(new RedrawCanvasWithAnimationRequest(request.animated)); } toCenter(fNodeRect, fFlowRect, position) { this.transform.scaledPosition = PointExtensions.initialize(); this.transform.position = PointExtensions.initialize((fFlowRect.width - fNodeRect.width) / 2 - position.x * this.transform.scale, (fFlowRect.height - fNodeRect.height) / 2 - position.y * this.transform.scale); } getNode(id) { return this._fComponentsStore.fNodes.find((x) => x.fId === id); } getNodeRect(fNode) { return RectExtensions.fromElement(fNode.hostElement); } getFlowRect() { return RectExtensions.fromElement(this._fComponentsStore.fFlow.hostElement); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CenterGroupOrNodeExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CenterGroupOrNodeExecution }); }; CenterGroupOrNodeExecution = __decorate([ FExecutionRegister(CenterGroupOrNodeRequest) ], CenterGroupOrNodeExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CenterGroupOrNodeExecution, decorators: [{ type: Injectable }] }); class FitToFlowRequest { toCenter; animated; constructor(toCenter, animated) { this.toCenter = toCenter; this.animated = animated; } } let FitToFlowExecution = class FitToFlowExecution { _fComponentsStore = inject(FComponentsStore); get transform() { return this._fComponentsStore.fCanvas.transform; } _fMediator = inject(FMediator); handle(request) { const fNodesRect = this._fMediator.execute(new CalculateNodesBoundingBoxRequest()) || RectExtensions.initialize(); if (fNodesRect.width === 0 || fNodesRect.height === 0) { return; } this.fitToParent(fNodesRect, RectExtensions.fromElement(this._fComponentsStore.fFlow.hostElement), this._fComponentsStore.fNodes.map((x) => x.position), request.toCenter); this._fMediator.execute(new RedrawCanvasWithAnimationRequest(request.animated)); } fitToParent(rect, parentRect, points, toCenter) { this.transform.scaledPosition = PointExtensions.initialize(); this.transform.position = this.getZeroPositionWithoutScale(points); const itemsContainerWidth = (rect.width / this.transform.scale) + toCenter.x; const itemsContainerHeight = (rect.height / this.transform.scale) + toCenter.y; if ((itemsContainerWidth > parentRect.width || itemsContainerHeight > parentRect.height) || itemsContainerWidth < parentRect.width && itemsContainerHeight < parentRect.height) { this.transform.scale = Math.min(parentRect.width / itemsContainerWidth, parentRect.height / itemsContainerHeight); } const newX = (parentRect.width - itemsContainerWidth * this.transform.scale) / 2 - this.transform.position.x * this.transform.scale; const newY = (parentRect.height - itemsContainerHeight * this.transform.scale) / 2 - this.transform.position.y * this.transform.scale; this.transform.position = PointExtensions.initialize(newX + (toCenter.x / 2) * this.transform.scale, newY + (toCenter.y / 2) * this.transform.scale); } getZeroPositionWithoutScale(points) { const xPoint = points.length ? Math.min(...points.map((point) => point.x)) : 0; const yPoint = points.length ? Math.min(...points.map((point) => point.y)) : 0; return PointExtensions.initialize(xPoint, yPoint); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FitToFlowExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FitToFlowExecution }); }; FitToFlowExecution = __decorate([ FExecutionRegister(FitToFlowRequest) ], FitToFlowExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FitToFlowExecution, decorators: [{ type: Injectable }] }); class GetCanvasRequest { } let GetCanvasExecution = class GetCanvasExecution { _fComponentsStore = inject(FComponentsStore); handle(request) { const result = this._fComponentsStore.fCanvas; if (!result) { throw new Error(`Canvas not found in store`); } return result; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: GetCanvasExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: GetCanvasExecution }); }; GetCanvasExecution = __decorate([ FExecutionRegister(GetCanvasRequest) ], GetCanvasExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: GetCanvasExecution, decorators: [{ type: Injectable }] }); class InputCanvasPositionRequest { transform; position; constructor(transform, position) { this.transform = transform; this.position = position; } } let InputCanvasPositionExecution = class InputCanvasPositionExecution { _fComponentsStore = inject(FComponentsStore); handle(request) { if (!request.position) { return; } const position = PointExtensions.sum(request.transform.position, request.transform.scaledPosition); if (!PointExtensions.isEqual(position, request.position)) { request.transform.position = request.position; request.transform.scaledPosition = PointExtensions.initialize(); this._fComponentsStore.fCanvas?.redraw(); } return void 0; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: InputCanvasPositionExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: InputCanvasPositionExecution }); }; InputCanvasPositionExecution = __decorate([ FExecutionRegister(InputCanvasPositionRequest) ], InputCanvasPositionExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: InputCanvasPositionExecution, decorators: [{ type: Injectable }] }); class InputCanvasScaleRequest { transform; scale; constructor(transform, scale) { this.transform = transform; this.scale = scale; } } let InputCanvasScaleExecution = class InputCanvasScaleExecution { _fComponentsStore = inject(FComponentsStore); handle(request) { if (!request.scale && request.scale !== 0) { return; } request.transform.scale = request.scale; this._fComponentsStore.fCanvas?.redraw(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: InputCanvasScaleExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: InputCanvasScaleExecution }); }; InputCanvasScaleExecution = __decorate([ FExecutionRegister(InputCanvasScaleRequest) ], InputCanvasScaleExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: InputCanvasScaleExecution, decorators: [{ type: Injectable }] }); class RedrawCanvasWithAnimationRequest { animated; constructor(animated) { this.animated = animated; } } function transitionEnd(element, callback) { const onTransitionEnd = (event) => { if (event.propertyName === 'transform') { element.removeEventListener('transitionend', onTransitionEnd); callback(event); } }; element.addEventListener('transitionend', onTransitionEnd); } let RedrawCanvasWithAnimationExecution = class RedrawCanvasWithAnimationExecution { _fComponentsStore = inject(FComponentsStore); get _fCanvasElement() { return this._fComponentsStore.fCanvas.hostElement; } handle(request) { request.animated ? this._redrawWithAnimation() : this._redraw(); this._fComponentsStore.fCanvas.emitCanvasChangeEvent(); } _redrawWithAnimation() { this._fComponentsStore.fCanvas.redrawWithAnimation(); transitionEnd(this._fCanvasElement, () => this._fComponentsStore.dataChanged()); } _redraw() { this._fComponentsStore.fCanvas.redraw(); this._fComponentsStore.dataChanged(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RedrawCanvasWithAnimationExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RedrawCanvasWithAnimationExecution }); }; RedrawCanvasWithAnimationExecution = __decorate([ FExecutionRegister(RedrawCanvasWithAnimationRequest) ], RedrawCanvasWithAnimationExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RedrawCanvasWithAnimationExecution, decorators: [{ type: Injectable }] }); class RemoveCanvasFromStoreRequest { } let RemoveCanvasFromStoreExecution = class RemoveCanvasFromStoreExecution { _fComponentsStore = inject(FComponentsStore); handle(request) { this._fComponentsStore.fCanvas = undefined; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RemoveCanvasFromStoreExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RemoveCanvasFromStoreExecution }); }; RemoveCanvasFromStoreExecution = __decorate([ FExecutionRegister(RemoveCanvasFromStoreRequest) ], RemoveCanvasFromStoreExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RemoveCanvasFromStoreExecution, decorators: [{ type: Injectable }] }); class ResetScaleRequest { } let ResetScaleExecution = class ResetScaleExecution { _fComponentsStore = inject(FComponentsStore); get transform() { return this._fComponentsStore.fCanvas.transform; } handle(request) { this.transform.scale = 1; this.transform.scaledPosition = PointExtensions.initialize(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ResetScaleExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ResetScaleExecution }); }; ResetScaleExecution = __decorate([ FExecutionRegister(ResetScaleRequest) ], ResetScaleExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ResetScaleExecution, decorators: [{ type: Injectable }] }); class ResetScaleAndCenterRequest { animated; constructor(animated) { this.animated = animated; } } let ResetScaleAndCenterExecution = class ResetScaleAndCenterExecution { _fMediator = inject(FMediator); _fComponentsStore = inject(FComponentsStore); get _transform() { return this._fComponentsStore.fCanvas.transform; } handle(request) { const fNodesRect = this._fMediator.execute(new CalculateNodesBoundingBoxRequest()) || RectExtensions.initialize(); if (fNodesRect.width === 0 || fNodesRect.height === 0) { return; } this._oneToOneCentering(fNodesRect, RectExtensions.fromElement(this._fComponentsStore.fFlow.hostElement), this._fComponentsStore.fNodes.map((x) => x.position)); this._fMediator.execute(new RedrawCanvasWithAnimationRequest(request.animated)); } _oneToOneCentering(rect, parentRect, points) { this._transform.scaledPosition = PointExtensions.initialize(); this._transform.position = this._getZeroPositionWithoutScale(points); const newX = (parentRect.width - rect.width / this._transform.scale) / 2 - this._transform.position.x; const newY = (parentRect.height - rect.height / this._transform.scale) / 2 - this._transform.position.y; this._transform.scale = 1; this._transform.position = PointExtensions.initialize(newX, newY); } _getZeroPositionWithoutScale(points) { const xPoint = points.length ? Math.min(...points.map((point) => point.x)) : 0; const yPoint = points.length ? Math.min(...points.map((point) => point.y)) : 0; return PointExtensions.initialize(xPoint, yPoint); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ResetScaleAndCenterExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ResetScaleAndCenterExecution }); }; ResetScaleAndCenterExecution = __decorate([ FExecutionRegister(ResetScaleAndCenterRequest) ], ResetScaleAndCenterExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ResetScaleAndCenterExecution, decorators: [{ type: Injectable }] }); class UpdateScaleRequest { scale; toPosition; constructor(scale, toPosition) { this.scale = scale; this.toPosition = toPosition; } } let UpdateScaleExecution = class UpdateScaleExecution { _fComponentsStore = inject(FComponentsStore); get transform() { return this._fComponentsStore.fCanvas.transform; } handle(request) { if (request.scale !== this.transform.scale) { const summaryPosition = PointExtensions.sum(this.transform.scaledPosition, this.transform.position); const newX = request.toPosition.x - (request.toPosition.x - summaryPosition.x) * request.scale / this.transform.scale; const newY = request.toPosition.y - (request.toPosition.y - summaryPosition.y) * request.scale / this.transform.scale; this.transform.scale = request.scale; this.transform.scaledPosition = PointExtensions.sub(PointExtensions.initialize(newX, newY), this.transform.position); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: UpdateScaleExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: UpdateScaleExecution }); }; UpdateScaleExecution = __decorate([ FExecutionRegister(UpdateScaleRequest) ], UpdateScaleExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: UpdateScaleExecution, decorators: [{ type: Injectable }] }); const F_CANVAS_FEATURES = [ AddCanvasToStoreExecution, CenterGroupOrNodeExecution, FitToFlowExecution, GetCanvasExecution, InputCanvasPositionExecution, InputCanvasScaleExecution, RedrawCanvasWithAnimationExecution, RemoveCanvasFromStoreExecution, ResetScaleExecution, ResetScaleAndCenterExecution, UpdateScaleExecution ]; class AddConnectionForCreateToStoreRequest { fConnection; constructor(fConnection) { this.fConnection = fConnection; } } let AddConnectionForCreateToStoreExecution = class AddConnectionForCreateToStoreExecution { _fComponentsStore = inject(FComponentsStore); handle(request) { this._fComponentsStore.fTempConnection = request.fConnection; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddConnectionForCreateToStoreExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddConnectionForCreateToStoreExecution }); }; AddConnectionForCreateToStoreExecution = __decorate([ FExecutionRegister(AddConnectionForCreateToStoreRequest) ], AddConnectionForCreateToStoreExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddConnectionForCreateToStoreExecution, decorators: [{ type: Injectable }] }); class AddConnectionMarkerToStoreRequest { fComponent; constructor(fComponent) { this.fComponent = fComponent; } } let AddConnectionMarkerToStoreExecution = class AddConnectionMarkerToStoreExecution { _fComponentsStore = inject(FComponentsStore); handle(request) { this._fComponentsStore.addComponent(this._fComponentsStore.fMarkers, request.fComponent); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddConnectionMarkerToStoreExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddConnectionMarkerToStoreExecution }); }; AddConnectionMarkerToStoreExecution = __decorate([ FExecutionRegister(AddConnectionMarkerToStoreRequest) ], AddConnectionMarkerToStoreExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddConnectionMarkerToStoreExecution, decorators: [{ type: Injectable }] }); class AddConnectionToStoreRequest { fConnection; constructor(fConnection) { this.fConnection = fConnection; } } let AddConnectionToStoreExecution = class AddConnectionToStoreExecution { _fComponentsStore = inject(FComponentsStore); handle(request) { this._fComponentsStore.fConnections.push(request.fConnection); this._fComponentsStore.dataChanged(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddConnectionToStoreExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddConnectionToStoreExecution }); }; AddConnectionToStoreExecution = __decorate([ FExecutionRegister(AddConnectionToStoreRequest) ], AddConnectionToStoreExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddConnectionToStoreExecution, decorators: [{ type: Injectable }] }); class AddSnapConnectionToStoreRequest { fConnection; constructor(fConnection) { this.fConnection = fConnection; } } let AddSnapConnectionToStoreExecution = class AddSnapConnectionToStoreExecution { _fComponentsStore = inject(FComponentsStore); handle(request) { this._fComponentsStore.fSnapConnection = request.fConnection; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddSnapConnectionToStoreExecution, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddSnapConnectionToStoreExecution }); }; AddSnapConnectionToStoreExecution = __decorate([ FExecutionRegister(AddSnapConnectionToStoreRequest) ], AddSnapConnectionToStoreExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddSnapConnectionToStoreExecution, decorators: [{ type: Injectable }] }); class CreateConnectionMarkersRequest { fConnection; constructor(fConnection) { this.fConnection = fConnection; } } let CreateConnectionMarkersExecution = class CreateConnectionMarkersExecution { fBrowser; fComponentsStore; constructor(fBrowser, fComponentsStore) { this.fBrowser = fBrowser; this.fComponentsStore = fComponentsStore; } handle(request) { const element = createSVGElement$1('defs', this.fBrowser); const fConnection = request.fConnection; this.getMarkers(fConnection).forEach((marker) => { const markerElement = this.createMarkerElement(marker, fConnection.fId); const clone = marker.hostElement.cloneNode(true); clone.setAttribute('height', `${marker.height}`); clone.setAttribute('width', `${marker.width}`); clone.removeAttribute('markerUnits'); clone.style.display = 'unset'; markerElement.append(clone); element.append(markerElement); }); fConnection.fDefs.nativeElement.innerHTML = element.innerHTML; this.makeSafariCompatible(fConnection); } getMarkers(fConnection) { return this.fComponentsStore.fMarkers.filter((x) => fConnection.hostElement.contains(x.hostElement)); } // Safari does not support markers on path elements if markers are defined after the path element makeSafariCompatible(fConnection) { fConnection.fPath.hostElement.replaceWith(fConnection.fPath.hostElement); } createMarkerElement(marker, fConnectionId) { const markerElement = createSVGElement$1('marker', this.fBrowser); markerElement.setAttribute('id', normalizeDomElementId(marker.type + '-' + fConnectionId)); markerElement.setAttribute('markerHeight', `${marker.height}`); markerElement.setAttribute('markerWidth', `${marker.width}`); markerElement.setAttribute('orient', `${marker.orient}`); markerElement.setAttribute('refX', `${marker.refX}`); markerElement.setAttribute('refY', `${marker.refY}`); markerElement.setAttribute('markerUnits', `${marker.markerUnits}`); return markerElement; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CreateConnectionMarkersExecution, deps: [{ token: i1.BrowserService }, { token: FComponentsStore }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CreateConnectionMarkersExecution }); }; CreateConnectionMarkersExecution = __decorate([ FExecutionRegister(CreateConnectionMarkersRequest) ], CreateConnectionMarkersExecution); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CreateConnectionMarkersExecution, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: i1.BrowserService }, { type: FComponentsStore }] }); function createSVGElement$1(tag, fBrowser) { return fBrowser.document.createElementNS('http://www.w3.org/2000/svg', tag); } class CalculateConnectionLineByBehaviorRequest { outputRect; inputRect; behavior; outputSide; inputSide; constructor(outputRect, inputRect, behavior, outputSide, inputSide) { this.outputRect = outputRect; this.inputRect = inputRect; this.behavior = behavior; this.outputSide = outputSide; this.inputSide = inputSide; } } class CalculateCenterBetweenPointsHandler { handle(request) { const { source, target } = request; const offsetX = Math.abs(target.x - source.x) / 2; const centerX = (target.x < source.x) ? target.x + offsetX : target.x - offsetX; const offsetY = Math.abs(target.y - source.y) / 2; const centerY = (target.y < source.y) ? target.y + offsetY : target.y - offsetY; return PointExtensions.initialize(centerX, centerY); } } class CalculateCenterBetweenPointsRequest { source; target; constructor(source, target) { this.source = source; this.target = target; } } class CalculateConnectionCenterHandler { handle(request) { const { points } = request; let totalDistance = 0; let distances = []; for (let i = 0; i < points.length - 1; i++) { const distance = this.calculateDistance(points[i], points[i + 1]); distances.push(distance); totalDistance += distance; } let accumulatedDistance = 0; let centerIndex = 0; const halfTotalDistance = totalDistance / 2; for (let i = 0; i < distances.length; i++) { accumulatedDistance += distances[i]; if (accumulatedDistance >= halfTotalDistance) { centerIndex = i; break; } } const remainingDistanceToCenter = halfTotalDistance - (accumulatedDistance - distances[centerIndex]); return this.findPointAtDistance(points[centerIndex], points[centerIndex + 1], remainingDistanceToCenter); } calculateDistance(pointA, pointB) { return Math.sqrt(Math.pow(pointB.x - pointA.x, 2) + Math.pow(pointB.y - pointA.y, 2)); } findPointAtDistance(startPoint, endPoint, distance) { const totalDistance = this.calculateDistance(startPoint, endPoint); const ratio = distance / totalDistance; const x = (1 - ratio) * startPoint.x + ratio * endPoint.x; const y = (1 - ratio) * startPoint.y + ratio * endPoint.y; return { x, y }; } } class CalculateConnectionCenterRequest { points; constructor(points) { this.points = points; } } var EFConnectableSide; (function (EFConnectableSide) { EFConnectableSide["LEFT"] = "left"; EFConnectableSide["TOP"] = "top"; EFConnectableSide["RIGHT"] = "right"; EFConnectableSide["BOTTOM"] = "bottom"; EFConnectableSide["AUTO"] = "auto"; })(EFConnectableSide || (EFConnectableSide = {})); class FConnectorBase { _isConnected = false; get isConnected() { return this._isConnected; } toConnector = []; isSelfConnectable = true; fConnectableSide = EFConnectableSide.AUTO; userFConnectableSide = EFConnectableSide.AUTO; isContains(element) { return this.hostElement.contains(element); } setConnected(toConnector) { this._isConnected = true; this.toConnector.push(toConnector); } resetConnected() { this._isConnected = false; this.toConnector = []; } } const F_NODE_INPUT = new InjectionToken('F_NODE_INPUT'); class FNodeInputBase extends FConnectorBase { get canBeConnected() { return !this.disabled && (this.multiple ? true : !this.isConnected); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FNodeInputBase, deps: null, target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: FNodeInputBase, usesInheritance: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FNodeInputBase, decorators: [{ type: Directive }] }); var EFResizeHandleType; (function (EFResizeHandleType) { EFResizeHandleType["LEFT"] = "left"; EFResizeHandleType["LEFT_TOP"] = "left-top"; EFResizeHandleType["TOP"] = "top"; EFResizeHandleType["RIGHT_TOP"] = "right-top"; EFResizeHandleType["RIGHT"] = "right"; EFResizeHandleType["RIGHT_BOTTOM"] = "right-bottom"; EFResizeHandleType["BOTTOM"] = "bottom"; EFResizeHandleType["LEFT_BOTTOM"] = "left-bottom"; })(EFResizeHandleType || (EFResizeHandleType = {})); class FResizeHandleDirective { type = input.required({ alias: 'fResizeHandleType', transform: (x) => castToEnum(x, 'fResizeHandleType', EFResizeHandleType) }); class = computed(() => { return `f-resize-handle-${EFResizeHandleType[this.type().toUpperCase()]}`; }); static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FResizeHandleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "18.2.13", type: FResizeHandleDirective, selector: "[fResizeHandle]", inputs: { type: { classPropertyName: "type", publicName: "fResizeHandleType", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-f-resize-handle-type": "type().toUpperCase()", "class": "class()" }, classAttribute: "f-resize-handle f-component" }, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FResizeHandleDirective, decorators: [{ type: Directive, args: [{ selector: "[fResizeHandle]", host: { class: `f-resize-handle f-component`, '[attr.data-f-resize-handle-type]': 'type().toUpperCase()', '[class]': 'class()' }, }] }] }); class FRotateHandleDirective { static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FRotateHandleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: FRotateHandleDirective, selector: "[fRotateHandle]", host: { classAttribute: "f-rotate-handle f-component" }, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FRotateHandleDirective, decorators: [{ type: Directive, args: [{ selector: "[fRotateHandle]", host: { class: `f-rotate-handle f-component`, }, }] }] }); function isRotateHandle(element) { return isClosestElementHasClass(element, '.f-rotate-handle'); } class FDragHandleDirective { static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FDragHandleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: FDragHandleDirective, selector: "[fDragHandle]", host: { classAttribute: "f-drag-handle f-component" }, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FDragHandleDirective, decorators: [{ type: Directive, args: [{ selector: "[fDragHandle]", host: { class: "f-drag-handle f-component" }, }] }] }); const F_SELECTED_CLASS = 'f-selected'; function mixinChangeSelection(base) { return class extends base { fId = ''; fSelectionDisabled = false; unmarkAsSelected() { this.unmarkChildrenAsSelected?.(); this.hostElement.classList.remove(F_SELECTED_CLASS); } markAsSelected() { this.markChildrenAsSelected?.(); if (!this.isSelected()) { this.hostElement.classList.add(F_SELECTED