UNPKG

ngx-gem-spaas

Version:

This library contains services, components, images and styles to provide a unified look and way-of-working throughout GEM SPaaS.

829 lines 53.5 kB
import * as i0 from '@angular/core';
import { EventEmitter, Directive, Input, Output, HostListener, Component, ViewChild, ContentChildren, NgModule } from '@angular/core';
import { Subject, debounceTime } from 'rxjs';
import { BaseComponent, UtilsService } from 'ngx-gem-spaas';
import { takeUntil } from 'rxjs/operators';
import * as i1 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i2 from '@angular/material/icon';
import { MatIconModule } from '@angular/material/icon';
import * as i3 from '@angular/material/sort';
import { MatSortModule } from '@angular/material/sort';
import * as i4 from '@angular/material/tooltip';
import { MatTooltipModule } from '@angular/material/tooltip';
import * as i5 from '@angular/cdk/scrolling';
import { ScrollingModule } from '@angular/cdk/scrolling';
import * as i6 from '@angular/forms';
import { FormGroup, FormControl, ReactiveFormsModule } from '@angular/forms';
import * as i2$1 from '@angular/material/form-field';
import { MatFormFieldModule } from '@angular/material/form-field';
import * as i3$1 from '@angular/material/input';
import { MatInputModule } from '@angular/material/input';
import * as i4$1 from '@angular/material/select';
import { MatSelectModule } from '@angular/material/select';
import * as i5$1 from '@angular/material/core';

class TableSelectionFreeDirective {
    constructor() {
        this.freeSelectionMatrix = [];
        this.freeSelectionLockAxis = '';
        this.selectionChanged = new EventEmitter(); // will emit the last selected row and column
        this.isSelecting = false;
        this.selectionId = 1;
        // set the from/to variables to public because it's very handy to be able to access these directly in the template
        this.fromCol = 0;
        this.fromRow = 0;
        this.toCol = 0;
        this.toRow = 0;
        this.onDestroy = new Subject();
    }
    mouseDown(e) {
        const mouseData = this.checkMouseData(e);
        if (mouseData.valid) {
            this.onClickCell(e, mouseData.rowIdx, mouseData.colIdx);
        }
    }
    mouseMove(e) {
        const mouseData = this.checkMouseData(e);
        if (this.isSelecting &&
            mouseData.valid &&
            (mouseData.rowIdx !== this.toRow || mouseData.colIdx !== this.toCol)) {
            this.onSelecting(mouseData.rowIdx, mouseData.colIdx);
        }
    }
    mouseUp() {
        this.onStopSelect('mouseup');
    }
    mouseLeave() {
        this.onStopSelect('mouseleave');
    }
    sort() {
        this.resetSelectionRange(true, true);
        this.emitNewSelection();
    }
    ngOnDestroy() {
        this.onDestroy.next();
        this.onDestroy.complete();
    }
    checkMouseData(e) {
        const target = (e.target);
        let dataset = target?.dataset;
        if (!dataset?.rowIdx) {
            // also check the offsetParent, for cells with sub-divs
            dataset = (target?.offsetParent).dataset;
        }
        let rowIdx = -1, colIdx = -1;
        if (dataset?.rowIdx && dataset.colIdx) {
            rowIdx = Number.isNaN((Number(dataset.rowIdx))) ? -1 : Number(dataset.rowIdx);
            colIdx = Number.isNaN((Number(dataset.colIdx))) ? -1 : Number(dataset.colIdx);
        }
        return {
            valid: rowIdx > -1 && colIdx > -1,
            rowIdx: rowIdx,
            colIdx: colIdx
        };
    }
    onClickCell(e, rowIdx, colIdx) {
        if (!e) {
            return;
        }
        this.isSelecting = true;
        if (!e.shiftKey && !e.ctrlKey) {
            // normal click: update all selection variables
            ++this.selectionId;
            this.fromRow = rowIdx;
            this.fromCol = colIdx;
            this.toRow = rowIdx;
            this.toCol = colIdx;
            this.resetSelectionRange(true);
        }
        else if (e.shiftKey) {
            // shift click: set last variables for range selection
            document.getSelection()?.removeAllRanges();
            this.setTo(rowIdx, colIdx);
            this.updateSelectionRange();
        }
        else if (e.ctrlKey) {
            // ctrl-click in non-origin row/col and lock-axis is active: reset all (considered a regular click in this case)
            if ((this.freeSelectionLockAxis === 'x' && rowIdx !== this.fromRow) ||
                (this.freeSelectionLockAxis === 'y' && colIdx !== this.fromCol)) {
                this.resetSelectionRange(true);
            }
            // ctrl key: just set for cell itself
            ++this.selectionId;
            this.freeSelectionMatrix[rowIdx][colIdx] = !this.freeSelectionMatrix[rowIdx][colIdx] ? this.selectionId : 0;
            if (this.freeSelectionMatrix[rowIdx][colIdx]) {
                this.fromRow = rowIdx;
                this.fromCol = colIdx;
                this.setTo(rowIdx, colIdx);
            }
            else {
                // it's a deselection: search for last selected cell to put focus on
                for (let row = 0; row < this.freeSelectionMatrix.length; row++) {
                    for (let col = 0; col < this.freeSelectionMatrix[row].length; col++) {
                        if (this.freeSelectionMatrix[row][col]) {
                            this.toRow = row;
                            this.toCol = col;
                        }
                    }
                }
            }
        }
    }
    onSelecting(rowIdx, colIdx) {
        if (this.isSelecting) {
            document.getSelection()?.removeAllRanges();
            this.setTo(rowIdx, colIdx);
            this.resetSelectionRange();
            this.updateSelectionRange();
        }
    }
    onStopSelect(fromMouseEvent) {
        if (this.isSelecting) {
            this.isSelecting = false;
            if (fromMouseEvent === 'mouseup') {
                this.emitNewSelection();
            }
        }
    }
    emitNewSelection() {
        this.selectionChanged.emit(this.freeSelectionMatrix[this.toRow][this.toCol] > 0 ?
            { row: this.toRow, column: this.toCol } :
            { row: -1, column: -1 });
    }
    setTo(rowIdx, colIdx) {
        this.toRow = this.freeSelectionLockAxis === 'x' ? this.fromRow : rowIdx;
        this.toCol = this.freeSelectionLockAxis === 'y' ? this.fromCol : colIdx;
    }
    resetSelectionRange(fullReset = false, fromSort = false) {
        const wasSelected = this.freeSelectionMatrix[this.toRow][this.toCol] > 0;
        for (let rowIdx = 0; rowIdx < this.freeSelectionMatrix.length; rowIdx++) {
            for (let colIdx = 0; colIdx < this.freeSelectionMatrix[rowIdx].length; colIdx++) {
                if (fullReset || this.freeSelectionMatrix[rowIdx][colIdx] === this.selectionId) {
                    this.freeSelectionMatrix[rowIdx][colIdx] = 0;
                }
            }
        }
        this.freeSelectionMatrix[this.toRow][this.toCol] = fromSort || wasSelected ? 0 : this.selectionId;
    }
    updateSelectionRange() {
        const fromRow = Math.min(this.fromRow, this.toRow);
        const toRow = Math.max(this.fromRow, this.toRow);
        const fromCol = Math.min(this.fromCol, this.toCol);
        const toCol = Math.max(this.fromCol, this.toCol);
        for (let rowIdx = fromRow; rowIdx <= toRow; rowIdx++) {
            for (let colIdx = fromCol; colIdx <= toCol; colIdx++) {
                this.freeSelectionMatrix[rowIdx][colIdx] = this.selectionId;
            }
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableSelectionFreeDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: TableSelectionFreeDirective, selector: "[spaasTableSelectionFree]", inputs: { freeSelectionMatrix: "freeSelectionMatrix", freeSelectionLockAxis: "freeSelectionLockAxis" }, outputs: { selectionChanged: "selectionChanged" }, host: { listeners: { "mousedown": "mouseDown($event)", "mousemove": "mouseMove($event)", "mouseup": "mouseUp($event)", "mouseleave": "mouseLeave($event)", "tableSortedOrFiltered": "sort($event)" } }, exportAs: ["spaasTableSelectionFree"], ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableSelectionFreeDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[spaasTableSelectionFree]',
                    exportAs: 'spaasTableSelectionFree'
                }]
        }], propDecorators: { freeSelectionMatrix: [{
                type: Input
            }], freeSelectionLockAxis: [{
                type: Input
            }], selectionChanged: [{
                type: Output
            }], mouseDown: [{
                type: HostListener,
                args: ['mousedown', ['$event']]
            }], mouseMove: [{
                type: HostListener,
                args: ['mousemove', ['$event']]
            }], mouseUp: [{
                type: HostListener,
                args: ['mouseup', ['$event']]
            }], mouseLeave: [{
                type: HostListener,
                args: ['mouseleave', ['$event']]
            }], sort: [{
                type: HostListener,
                args: ['tableSortedOrFiltered', ['$event']]
            }] } });

class TableHeaderDirective {
    constructor(templateRef) {
        this.templateRef = templateRef;
        this.spaasTableHeader = '';
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableHeaderDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: TableHeaderDirective, selector: "[spaasTableHeader]", inputs: { spaasTableHeader: "spaasTableHeader" }, exportAs: ["spaasTableHeader"], ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableHeaderDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[spaasTableHeader]',
                    exportAs: 'spaasTableHeader'
                }]
        }], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { spaasTableHeader: [{
                type: Input
            }] } });

class TableCellDirective {
    constructor(templateRef) {
        this.templateRef = templateRef;
        this.spaasTableCell = '';
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableCellDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: TableCellDirective, selector: "[spaasTableCell]", inputs: { spaasTableCell: "spaasTableCell" }, exportAs: ["spaasTableCell"], ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableCellDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[spaasTableCell]',
                    exportAs: 'spaasTableCell'
                }]
        }], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { spaasTableCell: [{
                type: Input
            }] } });

class TableComponent extends BaseComponent {
    constructor() {
        super(...arguments);
        this.tableData = [];
        this.columns = [];
        this.columnMaxWidth = 214;
        this.freeSelectionMatrix = null;
        this.rowSelectionMatrix = null;
        this.orientation = 'vertical';
        this.showToTop = false;
        this.withSort = true;
        this.filter = null;
        this.align = '';
        // do not just change the name of this emitter. Selection directives listen to it.
        this.tableSortedOrFiltered = new EventEmitter();
        this.vScroller = null;
        // these shallow copies are necessary because we want to keep the reference to the parent tableData
        // aka, we want the parent tableData to also get sorted and filtered
        this.origData = []; // a shallow copy for the original order
        this.domData = []; // a shallow copy for the DOM rendering (without this copying, the changeDetection would not fire on sort)
        this.toTopActive = false;
        this.scrolling$ = new Subject();
        this.activeSort = null;
    }
    static compare(a, b, isAsc) {
        const conv = isAsc ? 1 : -1;
        if (typeof a === 'string' && typeof b === 'string') {
            return ((a || '').toLowerCase() < (b || '').toLowerCase() ? -1 : 1) * conv;
        }
        return ((a || '') < (b || '') ? -1 : 1) * conv;
    }
    ngOnInit() {
        if (this.showToTop) {
            this.checkToTop();
        }
        if (this.filter) {
            this.filter.filterChanged
                .pipe(takeUntil(this.onDestroy$))
                .subscribe(() => {
                this.sortAndFilter();
            });
        }
    }
    ngAfterContentInit() {
        for (const col of this.columns) {
            // set optional booleans that should be true by default
            if (!col.hasOwnProperty('withSort')) {
                col.withSort = true;
            }
            // then set the templates, if any provided
            const headerTemplate = this.headerTemplates.find((h) => h.spaasTableHeader === col.dataField);
            if (headerTemplate) {
                col.headerTemplate = headerTemplate.templateRef;
            }
            const cellTemplate = this.cellTemplates.find((h) => h.spaasTableCell === col.dataField);
            if (cellTemplate) {
                col.cellTemplate = cellTemplate.templateRef;
            }
        }
    }
    ngOnChanges(changes) {
        if (changes.hasOwnProperty('tableData')) {
            this.origData = this.tableData.slice();
            this.sortAndFilter();
        }
    }
    ngOnDestroy() {
        this.resetTableData();
        super.ngOnDestroy();
    }
    onScroll() {
        this.scrolling$.next();
    }
    checkToTop() {
        this.scrolling$
            .pipe(debounceTime(400))
            .subscribe(() => {
            if (this.vScroller) {
                this.toTopActive = (this.vScroller.getOffsetToRenderedContentStart() || 0) > 400;
            }
        });
    }
    onGoToTop() {
        if (this.vScroller) {
            this.vScroller.scrollToOffset(0);
        }
    }
    onSort(matSort) {
        this.activeSort = matSort;
        this.sortAndFilter();
    }
    sortAndFilter() {
        // first always reset to avoid strange sorting behaviour
        this.resetTableData();
        // first filter
        if (this.filter?.filterString) {
            // filter tableData itself, so the parent data is also filtered (necessary for selection)
            const func = this.createFilterFunction(this.filter.filterString);
            for (let rowIdx = 0; rowIdx < this.tableData.length; rowIdx++) {
                if (!(func(this.tableData[rowIdx]))) {
                    this.tableData.splice(rowIdx, 1);
                    rowIdx--;
                }
            }
        }
        // then sort
        if (this.activeSort?.active && this.activeSort?.direction) {
            // sort tableData itself, so the parent data is also sorted (necessary for selection)
            const isAsc = this.activeSort.direction === 'asc';
            this.tableData.sort((a, b) => {
                return TableComponent.compare(a[this.activeSort?.active || ''], b[this.activeSort?.active || ''], isAsc);
            });
        }
        this.updateDomData();
        this.onGoToTop();
    }
    ;
    createFilterFunction(funcBody) {
        return Function.call(this, 'e', 'return ' + funcBody + ';');
    }
    resetTableData() {
        // reset tableData to the origData order, without breaking reference with the parent data
        this.tableData.length = 0;
        this.tableData.push(...this.origData);
    }
    updateDomData() {
        this.domData = this.tableData.slice();
        // only emit when there is actual data...
        // else it's not a real sort or filter (can't change anything to non-existing data)
        if (this.origData?.length) {
            // wrap it in setTimeout to avoid "expression has changed after it was checked" errors that might occur if
            // the parent component is displaying the number of rows in the data (new js VM turn invoked)
            setTimeout(() => {
                this.tableSortedOrFiltered.emit(this.domData.length);
            });
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: TableComponent, selector: "spaas-table", inputs: { tableData: "tableData", columns: "columns", columnMaxWidth: "columnMaxWidth", freeSelectionMatrix: "freeSelectionMatrix", rowSelectionMatrix: "rowSelectionMatrix", orientation: "orientation", showToTop: "showToTop", withSort: "withSort", filter: "filter", align: "align" }, outputs: { tableSortedOrFiltered: "tableSortedOrFiltered" }, queries: [{ propertyName: "headerTemplates", predicate: TableHeaderDirective }, { propertyName: "cellTemplates", predicate: TableCellDirective }], viewQueries: [{ propertyName: "vScroller", first: true, predicate: ["vScroller"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"spaas-table pos-relative\">\r\n\r\n  @if (orientation === 'vertical') {\r\n    <div (matSortChange)=\"onSort($event)\"\r\n         (scroll)=\"onScroll()\"\r\n         [matSortDisabled]=\"!withSort\"\r\n         cdkVirtualScrollingElement\r\n         class=\"flextable by-row striped flex col {{align}}\"\r\n         matSort>\r\n      <!-- header row -->\r\n      <div class=\"row header pos-sticky-vertical\">\r\n        @for (column of columns; track column) {\r\n          <div [disabled]=\"!column.withSort\"\r\n               [mat-sort-header]=\"column.dataField\"\r\n               class=\"cell {{column.cssClasses}}\">\r\n            <ng-container [ngTemplateOutlet]=\"column.headerTemplate || NoVertHeaderTemplate\">\r\n            </ng-container>\r\n            <ng-template #NoVertHeaderTemplate>\r\n              {{ column.columnLabel || column.dataField }}\r\n            </ng-template>\r\n          </div>\r\n        }\r\n      </div>\r\n      <!-- virtual scroller with data rows -->\r\n      <cdk-virtual-scroll-viewport #vScroller itemSize=\"36\">\r\n        <div *cdkVirtualFor=\"let row of domData; let rowIdx = index\"\r\n             [class.selected]=\"rowSelectionMatrix?.[rowIdx]\"\r\n             class=\"row\">\r\n          @for (column of columns; track column; let colIdx = $index) {\r\n            <div [attr.data-col-idx]=\"colIdx\"\r\n                 [attr.data-row-idx]=\"rowIdx\"\r\n                 [class.selected]=\"freeSelectionMatrix?.[rowIdx]?.[colIdx]\"\r\n                 class=\"cell {{column.cssClasses}}\">\r\n              <ng-container [ngTemplateOutletContext]=\"{row: row}\"\r\n                            [ngTemplateOutlet]=\"column.cellTemplate || NoVertCellTemplate\">\r\n              </ng-container>\r\n              <ng-template #NoVertCellTemplate>\r\n                {{ row[column.dataField] }}\r\n              </ng-template>\r\n            </div>\r\n          }\r\n        </div>\r\n      </cdk-virtual-scroll-viewport>\r\n    </div>\r\n  } @else {\r\n    <div (matSortChange)=\"onSort($event)\"\r\n         (scroll)=\"onScroll()\"\r\n         [matSortDisabled]=\"!withSort\"\r\n         cdkVirtualScrollingElement\r\n         class=\"flextable by-column striped {{align}}\"\r\n         matSort>\r\n      <!-- header column -->\r\n      <div class=\"column header pos-sticky-horizontal\">\r\n        @for (column of columns; track column) {\r\n          <div [disabled]=\"!column.withSort\"\r\n               [mat-sort-header]=\"column.dataField\"\r\n               [style.max-width.px]=\"columnMaxWidth\"\r\n               class=\"cell {{column.cssClasses}}\">\r\n            <ng-container [ngTemplateOutlet]=\"column.headerTemplate || NoHorHeaderTemplate\">\r\n            </ng-container>\r\n            <ng-template #NoHorHeaderTemplate>\r\n              {{ column.columnLabel || column.dataField }}\r\n            </ng-template>\r\n          </div>\r\n        }\r\n      </div>\r\n      <!-- virtual scroller with data columns -->\r\n      <cdk-virtual-scroll-viewport #vScroller [orientation]=\"'horizontal'\" itemSize=\"114\">\r\n        <div *cdkVirtualFor=\"let row of domData; let rowIdx = index\"\r\n             [class.selected]=\"rowSelectionMatrix?.[rowIdx]\"\r\n             [style.max-width.px]=\"columnMaxWidth\"\r\n             class=\"column\">\r\n          @for (column of columns; track column; let colIdx = $index) {\r\n            <div [attr.data-col-idx]=\"colIdx\"\r\n                 [attr.data-row-idx]=\"rowIdx\"\r\n                 [class.selected]=\"freeSelectionMatrix?.[rowIdx]?.[colIdx]\"\r\n                 class=\"cell {{column.cssClasses}}\">\r\n              <ng-container [ngTemplateOutletContext]=\"{row: row}\"\r\n                            [ngTemplateOutlet]=\"column.cellTemplate || NoHorCellTemplate\">\r\n              </ng-container>\r\n              <ng-template #NoHorCellTemplate>\r\n                {{ row[column.dataField] }}\r\n              </ng-template>\r\n            </div>\r\n          }\r\n        </div>\r\n      </cdk-virtual-scroll-viewport>\r\n    </div>\r\n  }\r\n\r\n  @if (showToTop && toTopActive) {\r\n    <div (click)=\"onGoToTop()\"\r\n         [matTooltip]=\"orientation === 'vertical' ? 'to top' : 'to left'\"\r\n         class=\"flextable__to-top\"\r\n         matTooltipClass=\"bg-accent\">\r\n      <mat-icon [fontIcon]=\"orientation === 'vertical' ? 'arrow_upward' : 'arrow_back'\" class=\"small\">\r\n      </mat-icon>\r\n    </div>\r\n  }\r\n\r\n</div>\r\n", styles: [".spaas-table{height:100%;width:100%}\n"], dependencies: [{ kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i3.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i3.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: i5.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i5.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i5.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "directive", type: i5.CdkVirtualScrollableElement, selector: "[cdkVirtualScrollingElement]" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableComponent, decorators: [{
            type: Component,
            args: [{ selector: 'spaas-table', template: "<div class=\"spaas-table pos-relative\">\r\n\r\n  @if (orientation === 'vertical') {\r\n    <div (matSortChange)=\"onSort($event)\"\r\n         (scroll)=\"onScroll()\"\r\n         [matSortDisabled]=\"!withSort\"\r\n         cdkVirtualScrollingElement\r\n         class=\"flextable by-row striped flex col {{align}}\"\r\n         matSort>\r\n      <!-- header row -->\r\n      <div class=\"row header pos-sticky-vertical\">\r\n        @for (column of columns; track column) {\r\n          <div [disabled]=\"!column.withSort\"\r\n               [mat-sort-header]=\"column.dataField\"\r\n               class=\"cell {{column.cssClasses}}\">\r\n            <ng-container [ngTemplateOutlet]=\"column.headerTemplate || NoVertHeaderTemplate\">\r\n            </ng-container>\r\n            <ng-template #NoVertHeaderTemplate>\r\n              {{ column.columnLabel || column.dataField }}\r\n            </ng-template>\r\n          </div>\r\n        }\r\n      </div>\r\n      <!-- virtual scroller with data rows -->\r\n      <cdk-virtual-scroll-viewport #vScroller itemSize=\"36\">\r\n        <div *cdkVirtualFor=\"let row of domData; let rowIdx = index\"\r\n             [class.selected]=\"rowSelectionMatrix?.[rowIdx]\"\r\n             class=\"row\">\r\n          @for (column of columns; track column; let colIdx = $index) {\r\n            <div [attr.data-col-idx]=\"colIdx\"\r\n                 [attr.data-row-idx]=\"rowIdx\"\r\n                 [class.selected]=\"freeSelectionMatrix?.[rowIdx]?.[colIdx]\"\r\n                 class=\"cell {{column.cssClasses}}\">\r\n              <ng-container [ngTemplateOutletContext]=\"{row: row}\"\r\n                            [ngTemplateOutlet]=\"column.cellTemplate || NoVertCellTemplate\">\r\n              </ng-container>\r\n              <ng-template #NoVertCellTemplate>\r\n                {{ row[column.dataField] }}\r\n              </ng-template>\r\n            </div>\r\n          }\r\n        </div>\r\n      </cdk-virtual-scroll-viewport>\r\n    </div>\r\n  } @else {\r\n    <div (matSortChange)=\"onSort($event)\"\r\n         (scroll)=\"onScroll()\"\r\n         [matSortDisabled]=\"!withSort\"\r\n         cdkVirtualScrollingElement\r\n         class=\"flextable by-column striped {{align}}\"\r\n         matSort>\r\n      <!-- header column -->\r\n      <div class=\"column header pos-sticky-horizontal\">\r\n        @for (column of columns; track column) {\r\n          <div [disabled]=\"!column.withSort\"\r\n               [mat-sort-header]=\"column.dataField\"\r\n               [style.max-width.px]=\"columnMaxWidth\"\r\n               class=\"cell {{column.cssClasses}}\">\r\n            <ng-container [ngTemplateOutlet]=\"column.headerTemplate || NoHorHeaderTemplate\">\r\n            </ng-container>\r\n            <ng-template #NoHorHeaderTemplate>\r\n              {{ column.columnLabel || column.dataField }}\r\n            </ng-template>\r\n          </div>\r\n        }\r\n      </div>\r\n      <!-- virtual scroller with data columns -->\r\n      <cdk-virtual-scroll-viewport #vScroller [orientation]=\"'horizontal'\" itemSize=\"114\">\r\n        <div *cdkVirtualFor=\"let row of domData; let rowIdx = index\"\r\n             [class.selected]=\"rowSelectionMatrix?.[rowIdx]\"\r\n             [style.max-width.px]=\"columnMaxWidth\"\r\n             class=\"column\">\r\n          @for (column of columns; track column; let colIdx = $index) {\r\n            <div [attr.data-col-idx]=\"colIdx\"\r\n                 [attr.data-row-idx]=\"rowIdx\"\r\n                 [class.selected]=\"freeSelectionMatrix?.[rowIdx]?.[colIdx]\"\r\n                 class=\"cell {{column.cssClasses}}\">\r\n              <ng-container [ngTemplateOutletContext]=\"{row: row}\"\r\n                            [ngTemplateOutlet]=\"column.cellTemplate || NoHorCellTemplate\">\r\n              </ng-container>\r\n              <ng-template #NoHorCellTemplate>\r\n                {{ row[column.dataField] }}\r\n              </ng-template>\r\n            </div>\r\n          }\r\n        </div>\r\n      </cdk-virtual-scroll-viewport>\r\n    </div>\r\n  }\r\n\r\n  @if (showToTop && toTopActive) {\r\n    <div (click)=\"onGoToTop()\"\r\n         [matTooltip]=\"orientation === 'vertical' ? 'to top' : 'to left'\"\r\n         class=\"flextable__to-top\"\r\n         matTooltipClass=\"bg-accent\">\r\n      <mat-icon [fontIcon]=\"orientation === 'vertical' ? 'arrow_upward' : 'arrow_back'\" class=\"small\">\r\n      </mat-icon>\r\n    </div>\r\n  }\r\n\r\n</div>\r\n", styles: [".spaas-table{height:100%;width:100%}\n"] }]
        }], propDecorators: { tableData: [{
                type: Input,
                args: [{ required: true }]
            }], columns: [{
                type: Input,
                args: [{ required: true }]
            }], columnMaxWidth: [{
                type: Input
            }], freeSelectionMatrix: [{
                type: Input
            }], rowSelectionMatrix: [{
                type: Input
            }], orientation: [{
                type: Input
            }], showToTop: [{
                type: Input
            }], withSort: [{
                type: Input
            }], filter: [{
                type: Input
            }], align: [{
                type: Input
            }], tableSortedOrFiltered: [{
                type: Output
            }], vScroller: [{
                type: ViewChild,
                args: ['vScroller']
            }], headerTemplates: [{
                type: ContentChildren,
                args: [TableHeaderDirective]
            }], cellTemplates: [{
                type: ContentChildren,
                args: [TableCellDirective]
            }] } });

class TableSelectionRowDirective {
    constructor() {
        this.rowSelectionMatrix = [];
        this.multiSelect = false;
        this.selectionChanged = new EventEmitter(); // will emit last selected row index
        this.isSelecting = false;
        this.selectionId = 1;
        // set the from/to variables to public because it's very handy to be able to access these directly in the template
        this.fromRow = 0;
        this.toRow = 0;
        this.onDestroy = new Subject();
    }
    mouseDown(e) {
        const mouseData = this.checkMouseData(e);
        if (mouseData.valid) {
            this.onClickCell(e, mouseData.rowIdx);
        }
    }
    mouseMove(e) {
        const mouseData = this.checkMouseData(e);
        if (this.isSelecting && mouseData.valid && mouseData.rowIdx !== this.toRow) {
            this.onSelecting(mouseData.rowIdx);
        }
    }
    mouseUp() {
        this.onStopSelect('mouseup');
    }
    mouseLeave() {
        this.onStopSelect('mouseleave');
    }
    sort() {
        this.resetSelectionRange(true, true);
        this.emitNewSelection();
    }
    ngOnDestroy() {
        this.onDestroy.next();
        this.onDestroy.complete();
    }
    checkMouseData(e) {
        const target = (e.target);
        let dataset = target?.dataset;
        if (!dataset?.rowIdx) {
            // also check the offsetParent, for cells with sub-divs
            dataset = (target?.offsetParent).dataset;
        }
        let rowIdx = -1;
        if (dataset?.rowIdx) {
            rowIdx = Number.isNaN((Number(dataset.rowIdx))) ? -1 : Number(dataset.rowIdx);
        }
        return {
            valid: rowIdx > -1,
            rowIdx: rowIdx,
        };
    }
    onClickCell(e, rowIdx) {
        if (!e) {
            return;
        }
        this.isSelecting = true;
        if (!e.shiftKey && !e.ctrlKey) {
            // normal click: update all selection variables
            ++this.selectionId;
            this.fromRow = rowIdx;
            this.toRow = rowIdx;
            this.resetSelectionRange(true);
        }
        else if (e.shiftKey && this.multiSelect) {
            // shift click: set last variables for range selection
            document.getSelection()?.removeAllRanges();
            this.toRow = rowIdx;
            this.updateSelectionRange();
        }
        else if (e.ctrlKey && this.multiSelect) {
            // ctrl key: just set for row itself
            ++this.selectionId;
            this.rowSelectionMatrix[rowIdx] = !this.rowSelectionMatrix[rowIdx] ? this.selectionId : 0;
            if (this.rowSelectionMatrix[rowIdx]) {
                this.fromRow = rowIdx;
                this.toRow = rowIdx;
            }
            else {
                // it's a deselection: search for last selected row to put focus on
                for (let row = 0; row < this.rowSelectionMatrix.length; row++) {
                    if (this.rowSelectionMatrix[row]) {
                        this.toRow = row;
                    }
                }
            }
        }
    }
    onSelecting(rowIdx) {
        if (this.isSelecting && this.multiSelect) {
            document.getSelection()?.removeAllRanges();
            this.toRow = rowIdx;
            this.resetSelectionRange();
            this.updateSelectionRange();
        }
    }
    onStopSelect(fromMouseEvent) {
        if (this.isSelecting) {
            this.isSelecting = false;
            if (fromMouseEvent === 'mouseup') {
                this.emitNewSelection();
            }
        }
    }
    emitNewSelection() {
        this.selectionChanged.emit(this.rowSelectionMatrix[this.toRow] > 0 ? this.toRow : -1);
    }
    resetSelectionRange(fullReset = false, fromSort = false) {
        const wasSelected = this.rowSelectionMatrix[this.toRow] > 0;
        for (let rowIdx = 0; rowIdx < this.rowSelectionMatrix.length; rowIdx++) {
            if (fullReset || this.rowSelectionMatrix[rowIdx] === this.selectionId) {
                this.rowSelectionMatrix[rowIdx] = 0;
            }
        }
        this.rowSelectionMatrix[this.toRow] = fromSort || wasSelected ? 0 : this.selectionId;
    }
    updateSelectionRange() {
        const fromRow = Math.min(this.fromRow, this.toRow);
        const toRow = Math.max(this.fromRow, this.toRow);
        for (let rowIdx = fromRow; rowIdx <= toRow; rowIdx++) {
            this.rowSelectionMatrix[rowIdx] = this.selectionId;
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableSelectionRowDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: TableSelectionRowDirective, selector: "[spaasTableSelectionRow]", inputs: { rowSelectionMatrix: "rowSelectionMatrix", multiSelect: "multiSelect" }, outputs: { selectionChanged: "selectionChanged" }, host: { listeners: { "mousedown": "mouseDown($event)", "mousemove": "mouseMove($event)", "mouseup": "mouseUp($event)", "mouseleave": "mouseLeave($event)", "tableSortedOrFiltered": "sort($event)" } }, exportAs: ["spaasTableSelectionRow"], ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableSelectionRowDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[spaasTableSelectionRow]',
                    exportAs: 'spaasTableSelectionRow'
                }]
        }], propDecorators: { rowSelectionMatrix: [{
                type: Input
            }], multiSelect: [{
                type: Input
            }], selectionChanged: [{
                type: Output
            }], mouseDown: [{
                type: HostListener,
                args: ['mousedown', ['$event']]
            }], mouseMove: [{
                type: HostListener,
                args: ['mousemove', ['$event']]
            }], mouseUp: [{
                type: HostListener,
                args: ['mouseup', ['$event']]
            }], mouseLeave: [{
                type: HostListener,
                args: ['mouseleave', ['$event']]
            }], sort: [{
                type: HostListener,
                args: ['tableSortedOrFiltered', ['$event']]
            }] } });

class TableColumnModel {
    constructor() {
        this.cellTemplate = null;
        this.columnLabel = '';
        this.dataField = '';
        this.withFilterDefault = '';
        this.withFilterSelect = '';
        this.withSort = true;
    }
}
class TableColumnFilterModel extends TableColumnModel {
    constructor() {
        super(...arguments);
        this.filterDropdownValues = [];
    }
    update(col) {
        Object.assign(this, col);
    }
}

class TableFilterComponent {
    static cleanValue(val) {
        // trim, escape backslashes and lowercase the value
        return (val + '').trim().replace(/\\/g, '\\\\').toLowerCase();
    }
    constructor() {
        this.tableData = [];
        this.columns = [];
        this.withFreeSearch = true;
        this.filterChanged = new EventEmitter();
        // also emit separately that the "clear all" button has been clicked (for parent components with additional filtering)
        this.filterCleared = new EventEmitter();
        this.filterString = '';
        this.filterForm = new FormGroup({});
        this.filterColumns = [];
        this.FREESEARCH_CTRL = 'freeSearch';
        this.ALL_VALUE = '';
        this.filterForm.addControl(this.FREESEARCH_CTRL, new FormControl(''));
    }
    ngOnChanges(changes) {
        if (changes.hasOwnProperty('columns')) {
            this.setFilterFormAndColumns();
        }
        if (changes.hasOwnProperty('tableData') && this.tableData?.length) {
            this.setDropdownLists();
        }
    }
    setFilterFormAndColumns() {
        this.filterColumns = [];
        let hasValidDefault = false;
        for (const col of this.columns) {
            if (col.withFilterSelect) {
                let newValidDefault = false;
                const filterCol = new TableColumnFilterModel();
                filterCol.update(col);
                this.filterColumns.push(filterCol);
                if (col.withFilterSelect === 'single') {
                    newValidDefault = !!col.withFilterDefault && typeof col.withFilterDefault === 'string';
                    const filterDefault = newValidDefault ? col.withFilterDefault : '';
                    this.filterForm.addControl(col.dataField, new FormControl(filterDefault));
                }
                else {
                    newValidDefault = !!col.withFilterDefault && Array.isArray(col.withFilterDefault) && col.withFilterDefault.length > 0;
                    const filterDefault = newValidDefault ? col.withFilterDefault : [this.ALL_VALUE];
                    this.filterForm.addControl(col.dataField, new FormControl(filterDefault));
                }
                hasValidDefault = hasValidDefault || newValidDefault;
            }
        }
        if (hasValidDefault) {
            this.updateFilter();
        }
    }
    setDropdownLists() {
        if (!this.filterColumns.length) {
            // should not happen since the columns should always be initialised before the data, but do the check anyway
            this.setFilterFormAndColumns();
        }
        for (const col of this.filterColumns) {
            const allColValues = this.tableData.map((t) => t[col.dataField] === null ? '' : '' + t[col.dataField]);
            col.filterDropdownValues = UtilsService.distinct(allColValues);
        }
    }
    onSelectAll(column) {
        if (column.withFilterSelect === 'multiple') {
            this.filterForm.controls[column.dataField].patchValue([this.ALL_VALUE]);
        }
        this.updateFilter();
    }
    onSelectOne(column) {
        if (column.withFilterSelect === 'multiple') {
            const val = this.filterForm.controls[column.dataField].value;
            if (!val.length) {
                // user has deselected the only selected value => set to "all" value
                this.filterForm.controls[column.dataField].patchValue([this.ALL_VALUE]);
            }
            else {
                // user has selected an option, deselect "all" value
                this.filterForm.controls[column.dataField].patchValue(val.filter((v) => v !== this.ALL_VALUE));
            }
        }
        this.updateFilter();
    }
    updateFilter() {
        let freeValueFilter = '';
        let dropdownFilter = '';
        // first free search
        const freeValue = TableFilterComponent.cleanValue(this.filterForm.controls[this.FREESEARCH_CTRL].value);
        if (freeValue) {
            // here we add ALL columns, not just the ones with filter === true
            for (const col of this.columns) {
                freeValueFilter += '("" + e["' + col.dataField + '"]).toLowerCase().includes("' + freeValue + '") || ';
            }
            freeValueFilter = '(' + freeValueFilter.substring(0, freeValueFilter.length - 4) + ') ';
        }
        // then dropdown fields
        for (const col of this.filterColumns) {
            if (col.withFilterSelect == 'single') {
                const colFilterValue = TableFilterComponent.cleanValue(this.filterForm.controls[col.dataField].value);
                if (colFilterValue) {
                    dropdownFilter += '("" + e["' + col.dataField + '"]).toLowerCase() === "' + colFilterValue + '" && ';
                }
            }
            else {
                const colFilterValues = this.filterForm.controls[col.dataField].value;
                let multiGroup = '';
                for (const val of colFilterValues) {
                    if (val) {
                        multiGroup += '("" + e["' + col.dataField + '"]).toLowerCase() === "' + TableFilterComponent.cleanValue(val) + '" || ';
                    }
                }
                if (multiGroup) {
                    dropdownFilter += '(' + multiGroup.substring(0, multiGroup.length - 4) + ') && ';
                }
            }
        }
        if (dropdownFilter) {
            dropdownFilter = '(' + dropdownFilter.substring(0, dropdownFilter.length - 4) + ') ';
        }
        const concatFilter = freeValueFilter && dropdownFilter ? freeValueFilter + ' && ' + dropdownFilter : freeValueFilter || dropdownFilter;
        this.emitFilter(concatFilter);
    }
    onReset() {
        this.filterForm.controls[this.FREESEARCH_CTRL].patchValue('');
        for (const col of this.filterColumns) {
            const ctrl = this.filterForm.controls[col.dataField];
            ctrl.patchValue(col.withFilterSelect === 'single' ? '' : [this.ALL_VALUE]);
        }
        this.emitFilter('');
        this.filterCleared.emit();
    }
    emitFilter(filter) {
        this.filterString = filter;
        this.filterChanged.emit(filter);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: TableFilterComponent, selector: "spaas-table-filter", inputs: { tableData: "tableData", columns: "columns", withFreeSearch: "withFreeSearch" }, outputs: { filterChanged: "filterChanged", filterCleared: "filterCleared" }, usesOnChanges: true, ngImport: i0, template: "<div [formGroup]=\"filterForm\"\r\n     [ngClass]=\"{\r\n     'column': withFreeSearch,\r\n     'row-reverse': !withFreeSearch,\r\n     }\"\r\n     class=\"filter pad-small flex column-gap-10\">\r\n\r\n  <div class=\"flex wrap column-gap-10 align-center\">\r\n\r\n    @if (withFreeSearch) {\r\n      <mat-form-field class=\"grow-h free-search\"\r\n                      floatLabel=\"always\">\r\n        <mat-label>search any field...</mat-label>\r\n        <input matInput\r\n               type=\"search\"\r\n               (search)=\"updateFilter()\"\r\n               formControlName=\"freeSearch\">\r\n      </mat-form-field>\r\n    }\r\n\r\n    <div class=\"flex column-gap-10 pad-small-top\">\r\n      @if (withFreeSearch) {\r\n        <button class=\"primary\"\r\n                (click)=\"updateFilter()\">\r\n          search\r\n        </button>\r\n      }\r\n      @if (filterColumns?.length) {\r\n        <button class=\"error\"\r\n                (click)=\"onReset()\">\r\n          clear all\r\n        </button>\r\n      }\r\n    </div>\r\n\r\n  </div>\r\n\r\n  <div class=\"flex wrap column-gap-10 align-center\"\r\n       [class.grow-h]=\"!withFreeSearch\">\r\n\r\n    @for (column of filterColumns; track column) {\r\n      <mat-form-field class=\"grow-h\"\r\n                      floatLabel=\"always\">\r\n        <mat-label>{{ column.columnLabel || column.dataField }}</mat-label>\r\n        <mat-select [formControlName]=\"column.dataField\"\r\n                    [multiple]=\"column.withFilterSelect === 'multiple'\">\r\n          <mat-option (click)=\"onSelectAll(column)\" [value]=\"ALL_VALUE\">all</mat-option>\r\n          @for (val of column.filterDropdownValues; track val) {\r\n            <mat-option (click)=\"onSelectOne(column)\"\r\n                        [value]=\"val\">\r\n              {{ val }}\r\n            </mat-option>\r\n          }\r\n        </mat-select>\r\n      </mat-form-field>\r\n    }\r\n\r\n  </div>\r\n\r\n</div>\r\n", styles: [".filter .mat-mdc-form-field{min-width:140px}.filter .mat-mdc-form-field.free-search{max-width:300px}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: i2$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl],      input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i4$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i5$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i6.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i6.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i6.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableFilterComponent, decorators: [{
            type: Component,
            args: [{ selector: 'spaas-table-filter', template: "<div [formGroup]=\"filterForm\"\r\n     [ngClass]=\"{\r\n     'column': withFreeSearch,\r\n     'row-reverse': !withFreeSearch,\r\n     }\"\r\n     class=\"filter pad-small flex column-gap-10\">\r\n\r\n  <div class=\"flex wrap column-gap-10 align-center\">\r\n\r\n    @if (withFreeSearch) {\r\n      <mat-form-field class=\"grow-h free-search\"\r\n                      floatLabel=\"always\">\r\n        <mat-label>search any field...</mat-label>\r\n        <input matInput\r\n               type=\"search\"\r\n               (search)=\"updateFilter()\"\r\n               formControlName=\"freeSearch\">\r\n      </mat-form-field>\r\n    }\r\n\r\n    <div class=\"flex column-gap-10 pad-small-top\">\r\n      @if (withFreeSearch) {\r\n        <button class=\"primary\"\r\n                (click)=\"updateFilter()\">\r\n          search\r\n        </button>\r\n      }\r\n      @if (filterColumns?.length) {\r\n        <button class=\"error\"\r\n                (click)=\"onReset()\">\r\n          clear all\r\n        </button>\r\n      }\r\n    </div>\r\n\r\n  </div>\r\n\r\n  <div class=\"flex wrap column-gap-10 align-center\"\r\n       [class.grow-h]=\"!withFreeSearch\">\r\n\r\n    @for (column of filterColumns; track column) {\r\n      <mat-form-field class=\"grow-h\"\r\n                      floatLabel=\"always\">\r\n        <mat-label>{{ column.columnLabel || column.dataField }}</mat-label>\r\n        <mat-select [formControlName]=\"column.dataField\"\r\n                    [multiple]=\"column.withFilterSelect === 'multiple'\">\r\n          <mat-option (click)=\"onSelectAll(column)\" [value]=\"ALL_VALUE\">all</mat-option>\r\n          @for (val of column.filterDropdownValues; track val) {\r\n            <mat-option (click)=\"onSelectOne(column)\"\r\n                        [value]=\"val\">\r\n              {{ val }}\r\n            </mat-option>\r\n          }\r\n        </mat-select>\r\n      </mat-form-field>\r\n    }\r\n\r\n  </div>\r\n\r\n</div>\r\n", styles: [".filter .mat-mdc-form-field{min-width:140px}.filter .mat-mdc-form-field.free-search{max-width:300px}\n"] }]
        }], ctorParameters: () => [], propDecorators: { tableData: [{
                type: Input
            }], columns: [{
                type: Input
            }], withFreeSearch: [{
                type: Input
            }], filterChanged: [{
                type: Output
            }], filterCleared: [{
                type: Output
            }] } });

class SpaasTableModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SpaasTableModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.12", ngImport: i0, type: SpaasTableModule, declarations: [TableCellDirective,
            TableComponent,
            TableFilterComponent,
            TableHeaderDirective,
            TableSelectionFreeDirective,
            TableSelectionRowDirective], imports: [CommonModule,
            MatFormFieldModule,
            MatIconModule,
            MatInputModule,
            MatSelectModule,
            MatSortModule,
            MatTooltipModule,
            ReactiveFormsModule,
            ScrollingModule], exports: [TableCellDirective,
            TableComponent,
            TableFilterComponent,
            TableHeaderDirective,
            TableSelectionFreeDirective,
            TableSelectionRowDirective] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SpaasTableModule, imports: [CommonModule,
            MatFormFieldModule,
            MatIconModule,
            MatInputModule,
            MatSelectModule,
            MatSortModule,
            MatTooltipModule,
            ReactiveFormsModule,
            ScrollingModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SpaasTableModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [
                        TableCellDirective,
                        TableComponent,
                        TableFilterComponent,
                        TableHeaderDirective,
                        TableSelectionFreeDirective,
                        TableSelectionRowDirective,
                    ],
                    exports: [
                        TableCellDirective,
                        TableComponent,
                        TableFilterComponent,
                        TableHeaderDirective,
                        TableSelectionFreeDirective,
                        TableSelectionRowDirective,
                    ],
                    imports: [
                        CommonModule,
                        MatFormFieldModule,
                        MatIconModule,
                        MatInputModule,
                        MatSelectModule,
                        MatSortModule,
                        MatTooltipModule,
                        ReactiveFormsModule,
                        ScrollingModule,
                    ],
                    providers: []
                }]
        }] });

// MODULE

/**
 * Generated bundle index. Do not edit.
 */

export { SpaasTableModule, TableCellDirective, TableColumnFilterModel, TableColumnModel, TableComponent, TableFilterComponent, TableHeaderDirective, TableSelectionFreeDirective, TableSelectionRowDirective };
//# sourceMappingURL=ngx-gem-spaas-table.mjs.map