import { CommonModule } from '@angular/common';
import { Component, Input, Output, EventEmitter, inject, ChangeDetectionStrategy, ChangeDetectorRef, } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { IonButton, IonIcon, IonCheckbox, IonSpinner, IonSelect, IonSelectOption } from '@ionic/angular/standalone';
import { addIcons } from 'ionicons';
import { chevronUpOutline, chevronDownOutline, chevronBackOutline, chevronForwardOutline, documentOutline, } from 'ionicons/icons';
import { I18nService } from '../../../services/i18n';
import { DEFAULT_PAGE_SIZE_OPTIONS, } from './types';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
addIcons({
    chevronUpOutline,
    chevronDownOutline,
    chevronBackOutline,
    chevronForwardOutline,
    documentOutline,
});
/**
 * val-data-table
 *
 * A flexible data table component for displaying tabular data with sorting,
 * pagination, and selection features.
 *
 * @example Basic usage
 * ```html
 * <val-data-table
 *   [props]="{
 *     columns: [
 *       { key: 'name', label: 'Nombre', sortable: true },
 *       { key: 'email', label: 'Email' },
 *       { key: 'status', label: 'Estado' }
 *     ],
 *     data: users
 *   }"
 * ></val-data-table>
 * ```
 *
 * @example With pagination and selection
 * ```html
 * <val-data-table
 *   [props]="{
 *     columns: columns,
 *     data: participants,
 *     showPagination: true,
 *     pagination: {
 *       page: 0,
 *       pageSize: 25,
 *       total: totalCount
 *     },
 *     selection: {
 *       mode: 'multiple',
 *       selected: selectedParticipants
 *     },
 *     showSelectionColumn: true
 *   }"
 *   (selectionChange)="onSelectionChange($event)"
 *   (pageChange)="onPageChange($event)"
 * ></val-data-table>
 * ```
 */
export class DataTableComponent {
    constructor() {
        this.rowClick = new EventEmitter();
        this.selectionChange = new EventEmitter();
        this.sortChange = new EventEmitter();
        this.pageChange = new EventEmitter();
        this.displayedData = [];
        this.currentSort = null;
        this.selectedRows = new Set();
        /** Cached visible columns for performance */
        this._visibleColumns = [];
        this.cdr = inject(ChangeDetectorRef);
        this.i18n = inject(I18nService);
    }
    ngOnInit() {
        this.initializeState();
        this.updateDisplayedData();
    }
    ngOnChanges(changes) {
        if (changes['props']) {
            this.initializeState();
            this.updateDisplayedData();
        }
    }
    initializeState() {
        // Cache visible columns for performance
        this._visibleColumns = this.props.columns.filter(c => c.visible !== false);
        // Initialize sort
        this.currentSort = this.props.sort || null;
        // Initialize selection
        if (this.props.selection?.selected) {
            this.selectedRows = new Set(this.props.selection.selected.map(row => this.getRowId(row)));
        }
    }
    updateDisplayedData() {
        let data = [...this.props.data];
        // Apply client-side sorting
        if (this.props.clientSort && this.currentSort) {
            data = this.sortData(data);
        }
        // Apply client-side pagination
        if (this.props.clientPagination && this.props.pagination) {
            const start = this.props.pagination.page * this.props.pagination.pageSize;
            const end = start + this.props.pagination.pageSize;
            data = data.slice(start, end);
        }
        this.displayedData = data;
        this.cdr.markForCheck();
    }
    sortData(data) {
        if (!this.currentSort)
            return data;
        const column = this.props.columns.find(c => c.key === this.currentSort?.column);
        if (!column)
            return data;
        return [...data].sort((a, b) => {
            if (column.sortFn) {
                const result = column.sortFn(a, b);
                return this.currentSort?.direction === 'desc' ? -result : result;
            }
            const valueA = this.getCellValue(a, column);
            const valueB = this.getCellValue(b, column);
            let comparison = 0;
            if (valueA == null && valueB == null)
                comparison = 0;
            else if (valueA == null)
                comparison = 1;
            else if (valueB == null)
                comparison = -1;
            else if (typeof valueA === 'string' && typeof valueB === 'string') {
                comparison = valueA.localeCompare(valueB);
            }
            else {
                comparison = valueA < valueB ? -1 : valueA > valueB ? 1 : 0;
            }
            return this.currentSort?.direction === 'desc' ? -comparison : comparison;
        });
    }
    get visibleColumns() {
        return this._visibleColumns;
    }
    get totalColumns() {
        let count = this.visibleColumns.length;
        if (this.props.showSelectionColumn)
            count++;
        if (this.props.showRowNumbers)
            count++;
        if (this.props.actionsTemplate)
            count++;
        return count;
    }
    get emptyState() {
        const defaultEmptyState = {
            icon: 'document-outline',
            title: this.i18n.t('noData'),
            description: this.i18n.t('noRecordsFound'),
        };
        return this.props.emptyState || defaultEmptyState;
    }
    /** Get actions column label */
    getActionsLabel() {
        return this.props.actionsLabel || this.i18n.t('actions');
    }
    /** Get pagination info text */
    getPaginationInfoText() {
        return `${this.i18n.t('showing')} ${this.paginationStart}-${this.paginationEnd} ${this.i18n.t('of')} ${this.props.pagination?.total}`;
    }
    /** Get per page text */
    getPerPageText(size) {
        return `${size} ${this.i18n.t('perPage')}`;
    }
    /** Get first page aria label */
    getFirstPageLabel() {
        return this.i18n.t('firstPage');
    }
    /** Get previous page aria label */
    getPreviousPageLabel() {
        return this.i18n.t('previousPage');
    }
    /** Get next page aria label */
    getNextPageLabel() {
        return this.i18n.t('nextPage');
    }
    /** Get last page aria label */
    getLastPageLabel() {
        return this.i18n.t('lastPage');
    }
    get pageSizeOptions() {
        return this.props.pagination?.pageSizeOptions || DEFAULT_PAGE_SIZE_OPTIONS;
    }
    get totalPages() {
        if (!this.props.pagination)
            return 1;
        return Math.ceil(this.props.pagination.total / this.props.pagination.pageSize);
    }
    get paginationStart() {
        if (!this.props.pagination)
            return 1;
        return this.props.pagination.page * this.props.pagination.pageSize + 1;
    }
    get paginationEnd() {
        if (!this.props.pagination)
            return this.displayedData.length;
        return Math.min((this.props.pagination.page + 1) * this.props.pagination.pageSize, this.props.pagination.total);
    }
    get isAllSelected() {
        if (this.displayedData.length === 0)
            return false;
        return this.displayedData.every(row => this.isRowSelected(row));
    }
    get isIndeterminate() {
        const selectedCount = this.displayedData.filter(row => this.isRowSelected(row)).length;
        return selectedCount > 0 && selectedCount < this.displayedData.length;
    }
    getCellValue(row, column) {
        const field = column.field || column.key;
        return field.split('.').reduce((obj, key) => obj?.[key], row);
    }
    getFormattedValue(row, column) {
        const value = this.getCellValue(row, column);
        if (column.format) {
            return column.format(value, row);
        }
        return value ?? '';
    }
    getColumnClass(column) {
        const classes = [column.cssClass || ''];
        if (column.sticky) {
            classes.push(`sticky-${column.sticky}`);
        }
        if (column.align) {
            classes.push(`align-${column.align}`);
        }
        return classes.filter(Boolean).join(' ');
    }
    getAriaSort(column) {
        if (!column.sortable)
            return null;
        if (this.currentSort?.column !== column.key)
            return 'none';
        return this.currentSort.direction === 'asc' ? 'ascending' : 'descending';
    }
    getRowNumber(index) {
        const start = this.props.rowNumberStart ?? 1;
        if (this.props.pagination) {
            return start + this.props.pagination.page * this.props.pagination.pageSize + index;
        }
        return start + index;
    }
    getRowId(row) {
        if (this.props.selection?.trackBy) {
            return this.props.selection.trackBy(row);
        }
        return row;
    }
    trackByFn(row) {
        return this.getRowId(row);
    }
    isRowSelected(row) {
        return this.selectedRows.has(this.getRowId(row));
    }
    onSort(column) {
        if (!column.sortable)
            return;
        let direction = 'asc';
        if (this.currentSort?.column === column.key) {
            if (this.currentSort.direction === 'asc') {
                direction = 'desc';
            }
            else {
                direction = null;
            }
        }
        if (direction) {
            this.currentSort = { column: column.key, direction };
        }
        else {
            this.currentSort = null;
        }
        this.sortChange.emit({
            column: column.key,
            direction,
        });
        if (this.props.clientSort) {
            this.updateDisplayedData();
        }
    }
    onRowClick(row, index, event) {
        if (!this.props.rowClickable)
            return;
        this.rowClick.emit({
            row,
            index,
            event,
        });
    }
    toggleSelectAll(event) {
        const checked = event.detail.checked;
        if (checked) {
            this.displayedData.forEach(row => {
                this.selectedRows.add(this.getRowId(row));
            });
        }
        else {
            this.displayedData.forEach(row => {
                this.selectedRows.delete(this.getRowId(row));
            });
        }
        this.emitSelectionChange(checked ? 'selectAll' : 'deselectAll');
    }
    toggleRowSelection(row, event) {
        const rowId = this.getRowId(row);
        const checked = event.detail.checked;
        if (checked) {
            this.selectedRows.add(rowId);
        }
        else {
            this.selectedRows.delete(rowId);
        }
        this.emitSelectionChange(checked ? 'select' : 'deselect', row);
    }
    selectSingleRow(row) {
        const rowId = this.getRowId(row);
        const wasSelected = this.selectedRows.has(rowId);
        this.selectedRows.clear();
        if (!wasSelected) {
            this.selectedRows.add(rowId);
            this.emitSelectionChange('select', row);
        }
        else {
            this.emitSelectionChange('deselect', row);
        }
    }
    emitSelectionChange(action, changedRow) {
        const selected = this.props.data.filter(row => this.isRowSelected(row));
        this.selectionChange.emit({
            selected,
            changedRow,
            action,
        });
    }
    goToPage(page) {
        if (!this.props.pagination)
            return;
        const previousPage = this.props.pagination.page;
        const maxPage = this.totalPages - 1;
        const newPage = Math.max(0, Math.min(page, maxPage));
        this.pageChange.emit({
            page: newPage,
            pageSize: this.props.pagination.pageSize,
            previousPage,
        });
        if (this.props.clientPagination) {
            this.props.pagination.page = newPage;
            this.updateDisplayedData();
        }
    }
    onPageSizeChange(event) {
        if (!this.props.pagination)
            return;
        const newPageSize = event.detail.value;
        const previousPage = this.props.pagination.page;
        // Recalculate page to keep first visible item
        const firstItem = previousPage * this.props.pagination.pageSize;
        const newPage = Math.floor(firstItem / newPageSize);
        this.pageChange.emit({
            page: newPage,
            pageSize: newPageSize,
            previousPage,
        });
        if (this.props.clientPagination) {
            this.props.pagination.pageSize = newPageSize;
            this.props.pagination.page = newPage;
            this.updateDisplayedData();
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DataTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: DataTableComponent, isStandalone: true, selector: "val-data-table", inputs: { props: "props" }, outputs: { rowClick: "rowClick", selectionChange: "selectionChange", sortChange: "sortChange", pageChange: "pageChange" }, usesOnChanges: true, ngImport: i0, template: `
    <div
      class="data-table-container"
      [class]="props.cssClass"
      [class.size-small]="props.size === 'small'"
      [class.size-medium]="props.size === 'medium' || !props.size"
      [class.size-large]="props.size === 'large'"
      [class.bordered]="props.bordered"
      [class.striped]="props.striped"
      [class.hoverable]="props.hoverable !== false"
      [class.sticky-header]="props.stickyHeader"
      [class.responsive-cards]="props.responsiveMode === 'cards'"
      [class.elevation-none]="props.elevation === 'none'"
      [class.elevation-low]="props.elevation === 'low'"
      [class.elevation-high]="props.elevation === 'high'"
      [class.header-gradient]="props.headerGradient"
      [class.checkbox-circular]="props.checkboxStyle === 'circular'"
      [class.row-highlight-border]="props.rowHighlightStyle === 'border-left'"
      [class.row-highlight-both]="props.rowHighlightStyle === 'both'"
      [style.--max-height]="props.maxHeight"
    >
      <!-- Toolbar slot -->
      <div class="table-toolbar" #toolbarContainer>
        <ng-content select="[toolbar]"></ng-content>
      </div>

      <!-- Loading overlay -->
      @if (props.loadingState?.loading) {
        <div class="loading-overlay">
          <ion-spinner name="circular"></ion-spinner>
          @if (props.loadingState?.message) {
            <span class="loading-message">{{ props.loadingState.message }}</span>
          }
        </div>
      }

      <div class="table-wrapper" [class.is-loading]="props.loadingState?.loading">
        <table role="grid" [attr.aria-label]="props.ariaLabel">
          @if (props.caption) {
            <caption class="sr-only">
              {{
                props.caption
              }}
            </caption>
          }

          <thead>
            <tr>
              <!-- Selection column -->
              @if (props.showSelectionColumn && props.selection?.mode === 'multiple') {
                <th class="selection-cell">
                  <ion-checkbox
                    [checked]="isAllSelected"
                    [indeterminate]="isIndeterminate"
                    (ionChange)="toggleSelectAll($event)"
                  ></ion-checkbox>
                </th>
              }
              @if (props.showSelectionColumn && props.selection?.mode === 'single') {
                <th class="selection-cell"></th>
              }

              <!-- Row number column -->
              @if (props.showRowNumbers) {
                <th class="row-number-cell">#</th>
              }

              <!-- Data columns -->
              @for (column of visibleColumns; track column.key) {
                <th
                  [class]="getColumnClass(column)"
                  [style.width]="column.width"
                  [style.min-width]="column.minWidth"
                  [style.max-width]="column.maxWidth"
                  [class.sortable]="column.sortable"
                  [class.sorted]="currentSort?.column === column.key"
                  (click)="column.sortable ? onSort(column) : null"
                  [attr.aria-sort]="getAriaSort(column)"
                >
                  @if (column.headerTemplate) {
                    <ng-container *ngTemplateOutlet="column.headerTemplate; context: { column }"></ng-container>
                  } @else {
                    <span class="header-content">
                      {{ column.label }}
                      @if (column.sortable) {
                        <span class="sort-icons">
                          <ion-icon
                            name="chevron-up-outline"
                            [class.active]="currentSort?.column === column.key && currentSort?.direction === 'asc'"
                          ></ion-icon>
                          <ion-icon
                            name="chevron-down-outline"
                            [class.active]="currentSort?.column === column.key && currentSort?.direction === 'desc'"
                          ></ion-icon>
                        </span>
                      }
                    </span>
                  }
                </th>
              }

              <!-- Actions column -->
              @if (props.actionsTemplate) {
                <th class="actions-cell" [style.width]="props.actionsWidth || '100px'">
                  {{ getActionsLabel() }}
                </th>
              }
            </tr>
          </thead>

          <tbody>
            @if (displayedData.length === 0 && !props.loadingState?.loading) {
              <tr class="empty-row">
                <td [attr.colspan]="totalColumns">
                  <div class="empty-state">
                    @if (emptyState.template) {
                      <ng-container *ngTemplateOutlet="emptyState.template"></ng-container>
                    } @else {
                      @if (emptyState.icon) {
                        <ion-icon [name]="emptyState.icon" class="empty-icon"></ion-icon>
                      }
                      @if (emptyState.title) {
                        <h4 class="empty-title">{{ emptyState.title }}</h4>
                      }
                      @if (emptyState.description) {
                        <p class="empty-description">{{ emptyState.description }}</p>
                      }
                    }
                  </div>
                </td>
              </tr>
            } @else {
              @for (row of displayedData; track trackByFn(row); let i = $index) {
                <tr
                  [class.selected]="isRowSelected(row)"
                  [class.clickable]="props.rowClickable"
                  (click)="onRowClick(row, i, $event)"
                >
                  <!-- Selection cell -->
                  @if (props.showSelectionColumn) {
                    <td class="selection-cell">
                      @if (props.selection?.mode === 'multiple') {
                        <ion-checkbox
                          [checked]="isRowSelected(row)"
                          (ionChange)="toggleRowSelection(row, $event)"
                          (click)="$event.stopPropagation()"
                        ></ion-checkbox>
                      } @else if (props.selection?.mode === 'single') {
                        <input
                          type="radio"
                          [checked]="isRowSelected(row)"
                          (click)="selectSingleRow(row); $event.stopPropagation()"
                        />
                      }
                    </td>
                  }

                  <!-- Row number -->
                  @if (props.showRowNumbers) {
                    <td class="row-number-cell">{{ getRowNumber(i) }}</td>
                  }

                  <!-- Data cells -->
                  @for (column of visibleColumns; track column.key) {
                    <td [class]="getColumnClass(column)" [style.text-align]="column.align">
                      @if (column.cellTemplate) {
                        <ng-container
                          *ngTemplateOutlet="
                            column.cellTemplate;
                            context: { row, column, value: getCellValue(row, column) }
                          "
                        ></ng-container>
                      } @else {
                        {{ getFormattedValue(row, column) }}
                      }
                    </td>
                  }

                  <!-- Actions cell -->
                  @if (props.actionsTemplate) {
                    <td class="actions-cell">
                      <ng-container
                        *ngTemplateOutlet="props.actionsTemplate; context: { row, index: i }"
                      ></ng-container>
                    </td>
                  }
                </tr>
              }
            }
          </tbody>
        </table>
      </div>

      <!-- Card view (responsive mobile) -->
      @if (props.responsiveMode === 'cards') {
        <div class="card-list">
          @if (displayedData.length === 0 && !props.loadingState?.loading) {
            <div class="empty-state">
              @if (emptyState.icon) {
                <ion-icon [name]="emptyState.icon" class="empty-icon"></ion-icon>
              }
              @if (emptyState.title) {
                <h4 class="empty-title">{{ emptyState.title }}</h4>
              }
              @if (emptyState.description) {
                <p class="empty-description">{{ emptyState.description }}</p>
              }
            </div>
          } @else {
            @for (row of displayedData; track trackByFn(row); let i = $index) {
              @if (props.mobileCardTemplate) {
                <ng-container
                  *ngTemplateOutlet="props.mobileCardTemplate; context: { row, index: i, columns: visibleColumns }"
                ></ng-container>
              } @else {
                <div
                  class="data-card"
                  [class.selected]="isRowSelected(row)"
                  [class.clickable]="props.rowClickable"
                  (click)="onRowClick(row, i, $event)"
                >
                  <!-- Card header with selection -->
                  @if (props.showSelectionColumn) {
                    <div class="card-header">
                      <div class="card-selection">
                        @if (props.selection?.mode === 'multiple') {
                          <ion-checkbox
                            [checked]="isRowSelected(row)"
                            (ionChange)="toggleRowSelection(row, $event)"
                            (click)="$event.stopPropagation()"
                          ></ion-checkbox>
                        } @else if (props.selection?.mode === 'single') {
                          <input
                            type="radio"
                            [checked]="isRowSelected(row)"
                            (click)="selectSingleRow(row); $event.stopPropagation()"
                          />
                        }
                      </div>
                      @if (props.showRowNumbers) {
                        <span class="row-number">{{ getRowNumber(i) }}</span>
                      }
                    </div>
                  }

                  <!-- Card body with fields -->
                  <div class="card-body">
                    @for (column of visibleColumns; track column.key) {
                      <div class="card-field">
                        <span class="card-field__label">{{ column.label }}</span>
                        <span class="card-field__value">
                          @if (column.cellTemplate) {
                            <ng-container
                              *ngTemplateOutlet="
                                column.cellTemplate;
                                context: { row, column, value: getCellValue(row, column) }
                              "
                            ></ng-container>
                          } @else {
                            {{ getFormattedValue(row, column) }}
                          }
                        </span>
                      </div>
                    }
                  </div>

                  <!-- Card actions -->
                  @if (props.actionsTemplate) {
                    <div class="card-actions">
                      <ng-container
                        *ngTemplateOutlet="props.actionsTemplate; context: { row, index: i }"
                      ></ng-container>
                    </div>
                  }
                </div>
              }
            }
          }
        </div>
      }

      <!-- Pagination -->
      @if (props.showPagination && props.pagination) {
        <div class="pagination-container">
          <div class="pagination-info">
            <span>
              {{ getPaginationInfoText() }}
            </span>

            @if (pageSizeOptions.length > 1) {
              <ion-select
                [value]="props.pagination.pageSize"
                (ionChange)="onPageSizeChange($event)"
                interface="popover"
                class="page-size-select"
              >
                @for (size of pageSizeOptions; track size) {
                  <ion-select-option [value]="size">{{ getPerPageText(size) }}</ion-select-option>
                }
              </ion-select>
            }
          </div>

          <div class="pagination-controls">
            <ion-button
              fill="clear"
              size="small"
              [disabled]="props.pagination.page === 0"
              (click)="goToPage(0)"
              [attr.aria-label]="getFirstPageLabel()"
            >
              <ion-icon slot="icon-only" name="chevron-back-outline"></ion-icon>
              <ion-icon slot="icon-only" name="chevron-back-outline" style="margin-left: -12px"></ion-icon>
            </ion-button>

            <ion-button
              fill="clear"
              size="small"
              [disabled]="props.pagination.page === 0"
              (click)="goToPage(props.pagination.page - 1)"
              [attr.aria-label]="getPreviousPageLabel()"
            >
              <ion-icon slot="icon-only" name="chevron-back-outline"></ion-icon>
            </ion-button>

            <span class="page-indicator"> {{ props.pagination.page + 1 }} / {{ totalPages }} </span>

            <ion-button
              fill="clear"
              size="small"
              [disabled]="props.pagination.page >= totalPages - 1"
              (click)="goToPage(props.pagination.page + 1)"
              [attr.aria-label]="getNextPageLabel()"
            >
              <ion-icon slot="icon-only" name="chevron-forward-outline"></ion-icon>
            </ion-button>

            <ion-button
              fill="clear"
              size="small"
              [disabled]="props.pagination.page >= totalPages - 1"
              (click)="goToPage(totalPages - 1)"
              [attr.aria-label]="getLastPageLabel()"
            >
              <ion-icon slot="icon-only" name="chevron-forward-outline"></ion-icon>
              <ion-icon slot="icon-only" name="chevron-forward-outline" style="margin-left: -12px"></ion-icon>
            </ion-button>
          </div>
        </div>
      }
    </div>
  `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}:host{display:block}.data-table-container{--dt-elevation-none: none;--dt-elevation-low: 0 1px 3px rgba(0, 0, 0, .08), 0 1px 2px rgba(0, 0, 0, .04);--dt-elevation-medium: 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -1px rgba(0, 0, 0, .06);--dt-elevation-high: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);--dt-primary: var(--ion-color-primary, #4f46e5);--dt-primary-rgb: var(--ion-color-primary-rgb, 79, 70, 229);--dt-surface: var(--ion-background-color, #ffffff);--dt-surface-variant: #f8fafc;--dt-border: #e2e8f0;--dt-text-primary: #1e293b;--dt-text-secondary: #64748b;--dt-text-muted: #94a3b8;--dt-gradient-start: #6366f1;--dt-gradient-end: #8b5cf6;--dt-border-radius: 16px;--dt-cell-padding-x: 16px;--dt-cell-padding-y: 14px;--dt-header-padding-y: 12px}.data-table-container{position:relative;background:var(--dt-surface);border-radius:var(--dt-border-radius);box-shadow:var(--dt-elevation-medium);border:1px solid var(--dt-border);overflow:hidden}.data-table-container.elevation-none{box-shadow:var(--dt-elevation-none)}.data-table-container.elevation-low{box-shadow:var(--dt-elevation-low)}.data-table-container.elevation-high{box-shadow:var(--dt-elevation-high)}.data-table-container.header-gradient:before{content:\"\";position:absolute;top:0;left:0;right:0;height:4px;background:linear-gradient(90deg,var(--dt-gradient-start),var(--dt-gradient-end));border-radius:var(--dt-border-radius) var(--dt-border-radius) 0 0;z-index:2}.loading-overlay{position:absolute;inset:0;background:#ffffffe6;backdrop-filter:blur(2px);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;z-index:10}.loading-overlay ion-spinner{--color: var(--dt-primary);width:32px;height:32px}.loading-message{font-size:.875rem;font-weight:500;color:var(--dt-text-secondary)}.table-wrapper{overflow-x:auto;max-height:var(--max-height)}.table-wrapper.is-loading{opacity:.5;pointer-events:none}.table-wrapper::-webkit-scrollbar{height:8px;width:8px}.table-wrapper::-webkit-scrollbar-track{background:var(--dt-surface-variant);border-radius:4px}.table-wrapper::-webkit-scrollbar-thumb{background:var(--dt-border);border-radius:4px}.table-wrapper::-webkit-scrollbar-thumb:hover{background:var(--dt-text-muted)}table{width:100%;border-collapse:collapse;font-size:.875rem}th,td{padding:var(--dt-cell-padding-y) var(--dt-cell-padding-x);text-align:left;vertical-align:middle}thead{background:var(--dt-surface-variant)}thead th{font-weight:600;font-size:.8125rem;color:var(--dt-text-secondary);white-space:nowrap;position:relative;border-bottom:1px solid var(--dt-border);padding:var(--dt-header-padding-y) var(--dt-cell-padding-x);transition:all .2s ease}thead th.sortable{cursor:pointer;-webkit-user-select:none;user-select:none}thead th.sortable:hover{background:#00000008;color:var(--dt-text-primary)}thead th.sorted{color:var(--dt-primary);background:rgba(var(--dt-primary-rgb),.04)}.header-content{display:flex;align-items:center;gap:8px}.sort-icons{display:flex;flex-direction:column;gap:0;opacity:.4;transition:opacity .2s ease}.sortable:hover .sort-icons{opacity:.7}.sorted .sort-icons{opacity:1}.sort-icons ion-icon{font-size:.75rem;color:var(--dt-text-muted);margin:-3px 0;transition:all .2s ease}.sort-icons ion-icon.active{color:var(--dt-primary);transform:scale(1.2)}tbody tr{border-bottom:1px solid var(--dt-border)}tbody tr:last-child{border-bottom:none}tbody tr.clickable{cursor:pointer}tbody tr.selected{background:rgba(var(--dt-primary-rgb),.06)}tbody td{color:var(--dt-text-primary);font-size:.875rem}.hoverable tbody tr:hover:not(.empty-row){background:var(--dt-surface-variant)}.hoverable tbody tr:hover:not(.empty-row).selected{background:rgba(var(--dt-primary-rgb),.08)}.align-left{text-align:left}.align-center{text-align:center}.align-right{text-align:right}.selection-cell{width:52px;min-width:52px;max-width:52px;text-align:center;padding:8px 12px;box-sizing:border-box}.selection-cell ion-checkbox{--size: 20px;--border-radius: 50%;--border-width: 2px;--border-color: var(--dt-border);--border-color-checked: var(--dt-primary);--background: transparent;--background-checked: var(--dt-primary);--checkmark-color: white;--checkmark-width: 2px;margin:0;display:block}.selection-cell ion-checkbox::part(container){border-radius:50%}.selection-cell input[type=radio]{width:20px;height:20px;cursor:pointer;accent-color:var(--dt-primary);margin:0;display:block}.checkbox-circular .selection-cell ion-checkbox{--border-radius: 50%}.checkbox-circular .selection-cell ion-checkbox::part(container){border-radius:50%}.row-number-cell{width:60px;text-align:center;color:var(--dt-text-muted);font-size:.75rem;font-weight:500}.actions-cell{text-align:center;white-space:nowrap}.sticky-start{position:sticky;left:0;background:inherit;z-index:1;box-shadow:2px 0 4px #0000000d}.sticky-end{position:sticky;right:0;background:inherit;z-index:1;box-shadow:-2px 0 4px #0000000d}.empty-row td{padding:64px 16px}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;color:var(--dt-text-secondary)}.empty-icon{font-size:3.5rem;margin-bottom:20px;opacity:.4;color:var(--dt-text-muted)}.empty-title{font-size:1.125rem;font-weight:600;margin:0 0 8px;color:var(--dt-text-primary)}.empty-description{font-size:.875rem;margin:0;max-width:320px;color:var(--dt-text-secondary);line-height:1.5}.pagination-container{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-top:1px solid var(--dt-border);background:var(--dt-surface);flex-wrap:wrap;gap:16px}.pagination-info{display:flex;align-items:center;gap:20px;font-size:.875rem;color:var(--dt-text-secondary)}.pagination-info span{font-weight:500}.page-size-select{--padding-start: 12px;--padding-end: 12px;font-size:.875rem;min-width:140px;--background: var(--dt-surface-variant);--border-radius: 8px}.pagination-controls{display:flex;align-items:center;gap:8px}.pagination-controls ion-button{--padding-start: 10px;--padding-end: 10px;--border-radius: 8px;--background: var(--dt-surface-variant);--background-hover: var(--dt-border);--color: var(--dt-text-secondary);--color-hover: var(--dt-text-primary);margin:0;height:36px;min-width:36px}.pagination-controls ion-button:disabled{opacity:.4}.pagination-controls ion-button ion-icon{font-size:1rem}.page-indicator{padding:0 16px;font-size:.875rem;color:var(--dt-text-primary);font-weight:600;background:var(--dt-surface-variant);border-radius:8px;height:36px;display:flex;align-items:center;min-width:80px;justify-content:center}.bordered th,.bordered td{border:1px solid var(--dt-border)}.striped tbody tr:nth-child(2n){background:var(--dt-surface-variant)}.striped tbody tr:nth-child(2n).selected{background:rgba(var(--dt-primary-rgb),.08)}.sticky-header .table-wrapper{overflow-y:auto}.sticky-header thead{position:sticky;top:0;z-index:5;box-shadow:0 1px 0 var(--dt-border)}.size-small{--dt-cell-padding-x: 12px;--dt-cell-padding-y: 10px;--dt-header-padding-y: 10px}.size-small th,.size-small td{font-size:.8125rem}.size-small thead th{font-size:.75rem}.size-small .selection-cell{width:44px;padding:6px 8px}.size-small .selection-cell ion-checkbox{--size: 18px}.size-small .row-number-cell{width:48px;font-size:.6875rem}.size-small .pagination-container{padding:12px 16px}.size-small .pagination-info,.size-small .page-indicator{font-size:.8125rem}.size-small .pagination-controls ion-button{height:32px;min-width:32px}.size-small .page-indicator{height:32px;min-width:70px}.size-large{--dt-cell-padding-x: 20px;--dt-cell-padding-y: 18px;--dt-header-padding-y: 16px}.size-large th,.size-large td{font-size:.9375rem}.size-large thead th{font-size:.875rem}.size-large .selection-cell{width:60px;padding:12px 16px}.size-large .selection-cell ion-checkbox{--size: 24px}.size-large .row-number-cell{width:72px;font-size:.875rem}.size-large .pagination-container{padding:20px 24px}.size-large .pagination-info,.size-large .page-indicator{font-size:.9375rem}.size-large .pagination-controls ion-button{height:40px;min-width:40px}.size-large .page-indicator{height:40px;min-width:90px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media (max-width: 768px){.data-table-container{--dt-border-radius: 12px}.pagination-container{flex-direction:column;align-items:stretch;gap:12px}.pagination-info{justify-content:space-between}.pagination-controls{justify-content:center}}.table-toolbar{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:20px;border-bottom:1px solid var(--dt-border);background:var(--dt-surface);flex-wrap:wrap}.table-toolbar:empty{display:none}@media (max-width: 576px){.table-toolbar{flex-direction:column;align-items:stretch;padding:16px}}.status-badge{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border-radius:9999px;font-size:.75rem;font-weight:600;white-space:nowrap;letter-spacing:.025em}.status-badge--success{background:#dcfce7;color:#15803d}.status-badge--warning{background:#fef3c7;color:#b45309}.status-badge--danger{background:#fee2e2;color:#dc2626}.status-badge--primary{background:#e0e7ff;color:#4338ca}.status-badge--secondary{background:#f1f5f9;color:#475569}.status-badge--medium{background:#f1f5f9;color:#64748b}.status-badge--tertiary{background:#f3e8ff;color:#7c3aed}.status-badge--filled.status-badge--success{background:#22c55e;color:#fff}.status-badge--filled.status-badge--warning{background:#f59e0b;color:#fff}.status-badge--filled.status-badge--danger{background:#ef4444;color:#fff}.status-badge--filled.status-badge--primary{background:var(--dt-primary);color:#fff}.status-badge--outlined{background:transparent;border:1.5px solid currentColor}.status-badge--outlined.status-badge--success{color:#16a34a}.status-badge--outlined.status-badge--warning{color:#d97706}.status-badge--outlined.status-badge--danger{color:#dc2626}.status-badge--outlined.status-badge--primary{color:var(--dt-primary)}.action-buttons{display:flex;gap:6px;justify-content:center}.action-buttons ion-button{--padding-start: 8px;--padding-end: 8px;--border-radius: 8px;margin:0}.action-buttons ion-button ion-icon{font-size:1.125rem}.card-list{display:none;padding:12px;gap:12px}.data-card{background:var(--dt-surface);border:1px solid var(--dt-border);border-radius:12px;padding:16px;margin-bottom:12px;transition:all .2s ease}.data-card.selected{border-color:var(--dt-primary);background:rgba(var(--dt-primary-rgb),.04);box-shadow:0 0 0 1px var(--dt-primary)}.data-card.clickable{cursor:pointer}.data-card.clickable:hover{box-shadow:var(--dt-elevation-medium);transform:translateY(-2px)}.data-card.clickable:active{transform:translateY(0)}.card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;padding-bottom:12px;border-bottom:1px solid var(--dt-border)}.card-selection{display:flex;align-items:center}.card-body{display:flex;flex-direction:column;gap:12px}.card-field{display:flex;justify-content:space-between;align-items:flex-start;gap:16px}.card-field__label{font-size:.75rem;font-weight:600;color:var(--dt-text-muted);flex-shrink:0}.card-field__value{font-size:.875rem;color:var(--dt-text-primary);text-align:right;word-break:break-word;font-weight:500}.card-actions{display:flex;justify-content:flex-end;margin-top:16px;padding-top:12px;border-top:1px solid var(--dt-border)}@media (max-width: 768px){.responsive-cards .table-wrapper{display:none}.responsive-cards .card-list{display:block}}:host-context(body.dark) .data-table-container,:host-context(.dark) .data-table-container,:host-context(.ion-palette-dark) .data-table-container,:host-context(html.ion-palette-dark) .data-table-container,:host-context([data-theme=dark]) .data-table-container{--dt-surface: #1e293b;--dt-surface-variant: #334155;--dt-border: #475569;--dt-text-primary: #f1f5f9;--dt-text-secondary: #94a3b8;--dt-text-muted: #64748b}:host-context(body.dark) .loading-overlay,:host-context(.dark) .loading-overlay,:host-context(.ion-palette-dark) .loading-overlay,:host-context(html.ion-palette-dark) .loading-overlay,:host-context([data-theme=dark]) .loading-overlay{background:#1e293be6}:host-context(body.dark) .status-badge--success,:host-context(.dark) .status-badge--success,:host-context(.ion-palette-dark) .status-badge--success,:host-context(html.ion-palette-dark) .status-badge--success,:host-context([data-theme=dark]) .status-badge--success{background:#22c55e33;color:#4ade80}:host-context(body.dark) .status-badge--warning,:host-context(.dark) .status-badge--warning,:host-context(.ion-palette-dark) .status-badge--warning,:host-context(html.ion-palette-dark) .status-badge--warning,:host-context([data-theme=dark]) .status-badge--warning{background:#f59e0b33;color:#fbbf24}:host-context(body.dark) .status-badge--danger,:host-context(.dark) .status-badge--danger,:host-context(.ion-palette-dark) .status-badge--danger,:host-context(html.ion-palette-dark) .status-badge--danger,:host-context([data-theme=dark]) .status-badge--danger{background:#ef444433;color:#f87171}:host-context(body.dark) .status-badge--primary,:host-context(.dark) .status-badge--primary,:host-context(.ion-palette-dark) .status-badge--primary,:host-context(html.ion-palette-dark) .status-badge--primary,:host-context([data-theme=dark]) .status-badge--primary{background:#6366f133;color:#a5b4fc}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonCheckbox, selector: "ion-checkbox", inputs: ["checked", "color", "disabled", "errorText", "helperText", "indeterminate", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "shape", "toggleIcon", "value"] }, { kind: "component", type: IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DataTableComponent, decorators: [{
            type: Component,
            args: [{ selector: 'val-data-table', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, FormsModule, IonButton, IonIcon, IonCheckbox, IonSpinner, IonSelect, IonSelectOption], template: `
    <div
      class="data-table-container"
      [class]="props.cssClass"
      [class.size-small]="props.size === 'small'"
      [class.size-medium]="props.size === 'medium' || !props.size"
      [class.size-large]="props.size === 'large'"
      [class.bordered]="props.bordered"
      [class.striped]="props.striped"
      [class.hoverable]="props.hoverable !== false"
      [class.sticky-header]="props.stickyHeader"
      [class.responsive-cards]="props.responsiveMode === 'cards'"
      [class.elevation-none]="props.elevation === 'none'"
      [class.elevation-low]="props.elevation === 'low'"
      [class.elevation-high]="props.elevation === 'high'"
      [class.header-gradient]="props.headerGradient"
      [class.checkbox-circular]="props.checkboxStyle === 'circular'"
      [class.row-highlight-border]="props.rowHighlightStyle === 'border-left'"
      [class.row-highlight-both]="props.rowHighlightStyle === 'both'"
      [style.--max-height]="props.maxHeight"
    >
      <!-- Toolbar slot -->
      <div class="table-toolbar" #toolbarContainer>
        <ng-content select="[toolbar]"></ng-content>
      </div>

      <!-- Loading overlay -->
      @if (props.loadingState?.loading) {
        <div class="loading-overlay">
          <ion-spinner name="circular"></ion-spinner>
          @if (props.loadingState?.message) {
            <span class="loading-message">{{ props.loadingState.message }}</span>
          }
        </div>
      }

      <div class="table-wrapper" [class.is-loading]="props.loadingState?.loading">
        <table role="grid" [attr.aria-label]="props.ariaLabel">
          @if (props.caption) {
            <caption class="sr-only">
              {{
                props.caption
              }}
            </caption>
          }

          <thead>
            <tr>
              <!-- Selection column -->
              @if (props.showSelectionColumn && props.selection?.mode === 'multiple') {
                <th class="selection-cell">
                  <ion-checkbox
                    [checked]="isAllSelected"
                    [indeterminate]="isIndeterminate"
                    (ionChange)="toggleSelectAll($event)"
                  ></ion-checkbox>
                </th>
              }
              @if (props.showSelectionColumn && props.selection?.mode === 'single') {
                <th class="selection-cell"></th>
              }

              <!-- Row number column -->
              @if (props.showRowNumbers) {
                <th class="row-number-cell">#</th>
              }

              <!-- Data columns -->
              @for (column of visibleColumns; track column.key) {
                <th
                  [class]="getColumnClass(column)"
                  [style.width]="column.width"
                  [style.min-width]="column.minWidth"
                  [style.max-width]="column.maxWidth"
                  [class.sortable]="column.sortable"
                  [class.sorted]="currentSort?.column === column.key"
                  (click)="column.sortable ? onSort(column) : null"
                  [attr.aria-sort]="getAriaSort(column)"
                >
                  @if (column.headerTemplate) {
                    <ng-container *ngTemplateOutlet="column.headerTemplate; context: { column }"></ng-container>
                  } @else {
                    <span class="header-content">
                      {{ column.label }}
                      @if (column.sortable) {
                        <span class="sort-icons">
                          <ion-icon
                            name="chevron-up-outline"
                            [class.active]="currentSort?.column === column.key && currentSort?.direction === 'asc'"
                          ></ion-icon>
                          <ion-icon
                            name="chevron-down-outline"
                            [class.active]="currentSort?.column === column.key && currentSort?.direction === 'desc'"
                          ></ion-icon>
                        </span>
                      }
                    </span>
                  }
                </th>
              }

              <!-- Actions column -->
              @if (props.actionsTemplate) {
                <th class="actions-cell" [style.width]="props.actionsWidth || '100px'">
                  {{ getActionsLabel() }}
                </th>
              }
            </tr>
          </thead>

          <tbody>
            @if (displayedData.length === 0 && !props.loadingState?.loading) {
              <tr class="empty-row">
                <td [attr.colspan]="totalColumns">
                  <div class="empty-state">
                    @if (emptyState.template) {
                      <ng-container *ngTemplateOutlet="emptyState.template"></ng-container>
                    } @else {
                      @if (emptyState.icon) {
                        <ion-icon [name]="emptyState.icon" class="empty-icon"></ion-icon>
                      }
                      @if (emptyState.title) {
                        <h4 class="empty-title">{{ emptyState.title }}</h4>
                      }
                      @if (emptyState.description) {
                        <p class="empty-description">{{ emptyState.description }}</p>
                      }
                    }
                  </div>
                </td>
              </tr>
            } @else {
              @for (row of displayedData; track trackByFn(row); let i = $index) {
                <tr
                  [class.selected]="isRowSelected(row)"
                  [class.clickable]="props.rowClickable"
                  (click)="onRowClick(row, i, $event)"
                >
                  <!-- Selection cell -->
                  @if (props.showSelectionColumn) {
                    <td class="selection-cell">
                      @if (props.selection?.mode === 'multiple') {
                        <ion-checkbox
                          [checked]="isRowSelected(row)"
                          (ionChange)="toggleRowSelection(row, $event)"
                          (click)="$event.stopPropagation()"
                        ></ion-checkbox>
                      } @else if (props.selection?.mode === 'single') {
                        <input
                          type="radio"
                          [checked]="isRowSelected(row)"
                          (click)="selectSingleRow(row); $event.stopPropagation()"
                        />
                      }
                    </td>
                  }

                  <!-- Row number -->
                  @if (props.showRowNumbers) {
                    <td class="row-number-cell">{{ getRowNumber(i) }}</td>
                  }

                  <!-- Data cells -->
                  @for (column of visibleColumns; track column.key) {
                    <td [class]="getColumnClass(column)" [style.text-align]="column.align">
                      @if (column.cellTemplate) {
                        <ng-container
                          *ngTemplateOutlet="
                            column.cellTemplate;
                            context: { row, column, value: getCellValue(row, column) }
                          "
                        ></ng-container>
                      } @else {
                        {{ getFormattedValue(row, column) }}
                      }
                    </td>
                  }

                  <!-- Actions cell -->
                  @if (props.actionsTemplate) {
                    <td class="actions-cell">
                      <ng-container
                        *ngTemplateOutlet="props.actionsTemplate; context: { row, index: i }"
                      ></ng-container>
                    </td>
                  }
                </tr>
              }
            }
          </tbody>
        </table>
      </div>

      <!-- Card view (responsive mobile) -->
      @if (props.responsiveMode === 'cards') {
        <div class="card-list">
          @if (displayedData.length === 0 && !props.loadingState?.loading) {
            <div class="empty-state">
              @if (emptyState.icon) {
                <ion-icon [name]="emptyState.icon" class="empty-icon"></ion-icon>
              }
              @if (emptyState.title) {
                <h4 class="empty-title">{{ emptyState.title }}</h4>
              }
              @if (emptyState.description) {
                <p class="empty-description">{{ emptyState.description }}</p>
              }
            </div>
          } @else {
            @for (row of displayedData; track trackByFn(row); let i = $index) {
              @if (props.mobileCardTemplate) {
                <ng-container
                  *ngTemplateOutlet="props.mobileCardTemplate; context: { row, index: i, columns: visibleColumns }"
                ></ng-container>
              } @else {
                <div
                  class="data-card"
                  [class.selected]="isRowSelected(row)"
                  [class.clickable]="props.rowClickable"
                  (click)="onRowClick(row, i, $event)"
                >
                  <!-- Card header with selection -->
                  @if (props.showSelectionColumn) {
                    <div class="card-header">
                      <div class="card-selection">
                        @if (props.selection?.mode === 'multiple') {
                          <ion-checkbox
                            [checked]="isRowSelected(row)"
                            (ionChange)="toggleRowSelection(row, $event)"
                            (click)="$event.stopPropagation()"
                          ></ion-checkbox>
                        } @else if (props.selection?.mode === 'single') {
                          <input
                            type="radio"
                            [checked]="isRowSelected(row)"
                            (click)="selectSingleRow(row); $event.stopPropagation()"
                          />
                        }
                      </div>
                      @if (props.showRowNumbers) {
                        <span class="row-number">{{ getRowNumber(i) }}</span>
                      }
                    </div>
                  }

                  <!-- Card body with fields -->
                  <div class="card-body">
                    @for (column of visibleColumns; track column.key) {
                      <div class="card-field">
                        <span class="card-field__label">{{ column.label }}</span>
                        <span class="card-field__value">
                          @if (column.cellTemplate) {
                            <ng-container
                              *ngTemplateOutlet="
                                column.cellTemplate;
                                context: { row, column, value: getCellValue(row, column) }
                              "
                            ></ng-container>
                          } @else {
                            {{ getFormattedValue(row, column) }}
                          }
                        </span>
                      </div>
                    }
                  </div>

                  <!-- Card actions -->
                  @if (props.actionsTemplate) {
                    <div class="card-actions">
                      <ng-container
                        *ngTemplateOutlet="props.actionsTemplate; context: { row, index: i }"
                      ></ng-container>
                    </div>
                  }
                </div>
              }
            }
          }
        </div>
      }

      <!-- Pagination -->
      @if (props.showPagination && props.pagination) {
        <div class="pagination-container">
          <div class="pagination-info">
            <span>
              {{ getPaginationInfoText() }}
            </span>

            @if (pageSizeOptions.length > 1) {
              <ion-select
                [value]="props.pagination.pageSize"
                (ionChange)="onPageSizeChange($event)"
                interface="popover"
                class="page-size-select"
              >
                @for (size of pageSizeOptions; track size) {
                  <ion-select-option [value]="size">{{ getPerPageText(size) }}</ion-select-option>
                }
              </ion-select>
            }
          </div>

          <div class="pagination-controls">
            <ion-button
              fill="clear"
              size="small"
              [disabled]="props.pagination.page === 0"
              (click)="goToPage(0)"
              [attr.aria-label]="getFirstPageLabel()"
            >
              <ion-icon slot="icon-only" name="chevron-back-outline"></ion-icon>
              <ion-icon slot="icon-only" name="chevron-back-outline" style="margin-left: -12px"></ion-icon>
            </ion-button>

            <ion-button
              fill="clear"
              size="small"
              [disabled]="props.pagination.page === 0"
              (click)="goToPage(props.pagination.page - 1)"
              [attr.aria-label]="getPreviousPageLabel()"
            >
              <ion-icon slot="icon-only" name="chevron-back-outline"></ion-icon>
            </ion-button>

            <span class="page-indicator"> {{ props.pagination.page + 1 }} / {{ totalPages }} </span>

            <ion-button
              fill="clear"
              size="small"
              [disabled]="props.pagination.page >= totalPages - 1"
              (click)="goToPage(props.pagination.page + 1)"
              [attr.aria-label]="getNextPageLabel()"
            >
              <ion-icon slot="icon-only" name="chevron-forward-outline"></ion-icon>
            </ion-button>

            <ion-button
              fill="clear"
              size="small"
              [disabled]="props.pagination.page >= totalPages - 1"
              (click)="goToPage(totalPages - 1)"
              [attr.aria-label]="getLastPageLabel()"
            >
              <ion-icon slot="icon-only" name="chevron-forward-outline"></ion-icon>
              <ion-icon slot="icon-only" name="chevron-forward-outline" style="margin-left: -12px"></ion-icon>
            </ion-button>
          </div>
        </div>
      }
    </div>
  `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}:host{display:block}.data-table-container{--dt-elevation-none: none;--dt-elevation-low: 0 1px 3px rgba(0, 0, 0, .08), 0 1px 2px rgba(0, 0, 0, .04);--dt-elevation-medium: 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -1px rgba(0, 0, 0, .06);--dt-elevation-high: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);--dt-primary: var(--ion-color-primary, #4f46e5);--dt-primary-rgb: var(--ion-color-primary-rgb, 79, 70, 229);--dt-surface: var(--ion-background-color, #ffffff);--dt-surface-variant: #f8fafc;--dt-border: #e2e8f0;--dt-text-primary: #1e293b;--dt-text-secondary: #64748b;--dt-text-muted: #94a3b8;--dt-gradient-start: #6366f1;--dt-gradient-end: #8b5cf6;--dt-border-radius: 16px;--dt-cell-padding-x: 16px;--dt-cell-padding-y: 14px;--dt-header-padding-y: 12px}.data-table-container{position:relative;background:var(--dt-surface);border-radius:var(--dt-border-radius);box-shadow:var(--dt-elevation-medium);border:1px solid var(--dt-border);overflow:hidden}.data-table-container.elevation-none{box-shadow:var(--dt-elevation-none)}.data-table-container.elevation-low{box-shadow:var(--dt-elevation-low)}.data-table-container.elevation-high{box-shadow:var(--dt-elevation-high)}.data-table-container.header-gradient:before{content:\"\";position:absolute;top:0;left:0;right:0;height:4px;background:linear-gradient(90deg,var(--dt-gradient-start),var(--dt-gradient-end));border-radius:var(--dt-border-radius) var(--dt-border-radius) 0 0;z-index:2}.loading-overlay{position:absolute;inset:0;background:#ffffffe6;backdrop-filter:blur(2px);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;z-index:10}.loading-overlay ion-spinner{--color: var(--dt-primary);width:32px;height:32px}.loading-message{font-size:.875rem;font-weight:500;color:var(--dt-text-secondary)}.table-wrapper{overflow-x:auto;max-height:var(--max-height)}.table-wrapper.is-loading{opacity:.5;pointer-events:none}.table-wrapper::-webkit-scrollbar{height:8px;width:8px}.table-wrapper::-webkit-scrollbar-track{background:var(--dt-surface-variant);border-radius:4px}.table-wrapper::-webkit-scrollbar-thumb{background:var(--dt-border);border-radius:4px}.table-wrapper::-webkit-scrollbar-thumb:hover{background:var(--dt-text-muted)}table{width:100%;border-collapse:collapse;font-size:.875rem}th,td{padding:var(--dt-cell-padding-y) var(--dt-cell-padding-x);text-align:left;vertical-align:middle}thead{background:var(--dt-surface-variant)}thead th{font-weight:600;font-size:.8125rem;color:var(--dt-text-secondary);white-space:nowrap;position:relative;border-bottom:1px solid var(--dt-border);padding:var(--dt-header-padding-y) var(--dt-cell-padding-x);transition:all .2s ease}thead th.sortable{cursor:pointer;-webkit-user-select:none;user-select:none}thead th.sortable:hover{background:#00000008;color:var(--dt-text-primary)}thead th.sorted{color:var(--dt-primary);background:rgba(var(--dt-primary-rgb),.04)}.header-content{display:flex;align-items:center;gap:8px}.sort-icons{display:flex;flex-direction:column;gap:0;opacity:.4;transition:opacity .2s ease}.sortable:hover .sort-icons{opacity:.7}.sorted .sort-icons{opacity:1}.sort-icons ion-icon{font-size:.75rem;color:var(--dt-text-muted);margin:-3px 0;transition:all .2s ease}.sort-icons ion-icon.active{color:var(--dt-primary);transform:scale(1.2)}tbody tr{border-bottom:1px solid var(--dt-border)}tbody tr:last-child{border-bottom:none}tbody tr.clickable{cursor:pointer}tbody tr.selected{background:rgba(var(--dt-primary-rgb),.06)}tbody td{color:var(--dt-text-primary);font-size:.875rem}.hoverable tbody tr:hover:not(.empty-row){background:var(--dt-surface-variant)}.hoverable tbody tr:hover:not(.empty-row).selected{background:rgba(var(--dt-primary-rgb),.08)}.align-left{text-align:left}.align-center{text-align:center}.align-right{text-align:right}.selection-cell{width:52px;min-width:52px;max-width:52px;text-align:center;padding:8px 12px;box-sizing:border-box}.selection-cell ion-checkbox{--size: 20px;--border-radius: 50%;--border-width: 2px;--border-color: var(--dt-border);--border-color-checked: var(--dt-primary);--background: transparent;--background-checked: var(--dt-primary);--checkmark-color: white;--checkmark-width: 2px;margin:0;display:block}.selection-cell ion-checkbox::part(container){border-radius:50%}.selection-cell input[type=radio]{width:20px;height:20px;cursor:pointer;accent-color:var(--dt-primary);margin:0;display:block}.checkbox-circular .selection-cell ion-checkbox{--border-radius: 50%}.checkbox-circular .selection-cell ion-checkbox::part(container){border-radius:50%}.row-number-cell{width:60px;text-align:center;color:var(--dt-text-muted);font-size:.75rem;font-weight:500}.actions-cell{text-align:center;white-space:nowrap}.sticky-start{position:sticky;left:0;background:inherit;z-index:1;box-shadow:2px 0 4px #0000000d}.sticky-end{position:sticky;right:0;background:inherit;z-index:1;box-shadow:-2px 0 4px #0000000d}.empty-row td{padding:64px 16px}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;color:var(--dt-text-secondary)}.empty-icon{font-size:3.5rem;margin-bottom:20px;opacity:.4;color:var(--dt-text-muted)}.empty-title{font-size:1.125rem;font-weight:600;margin:0 0 8px;color:var(--dt-text-primary)}.empty-description{font-size:.875rem;margin:0;max-width:320px;color:var(--dt-text-secondary);line-height:1.5}.pagination-container{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-top:1px solid var(--dt-border);background:var(--dt-surface);flex-wrap:wrap;gap:16px}.pagination-info{display:flex;align-items:center;gap:20px;font-size:.875rem;color:var(--dt-text-secondary)}.pagination-info span{font-weight:500}.page-size-select{--padding-start: 12px;--padding-end: 12px;font-size:.875rem;min-width:140px;--background: var(--dt-surface-variant);--border-radius: 8px}.pagination-controls{display:flex;align-items:center;gap:8px}.pagination-controls ion-button{--padding-start: 10px;--padding-end: 10px;--border-radius: 8px;--background: var(--dt-surface-variant);--background-hover: var(--dt-border);--color: var(--dt-text-secondary);--color-hover: var(--dt-text-primary);margin:0;height:36px;min-width:36px}.pagination-controls ion-button:disabled{opacity:.4}.pagination-controls ion-button ion-icon{font-size:1rem}.page-indicator{padding:0 16px;font-size:.875rem;color:var(--dt-text-primary);font-weight:600;background:var(--dt-surface-variant);border-radius:8px;height:36px;display:flex;align-items:center;min-width:80px;justify-content:center}.bordered th,.bordered td{border:1px solid var(--dt-border)}.striped tbody tr:nth-child(2n){background:var(--dt-surface-variant)}.striped tbody tr:nth-child(2n).selected{background:rgba(var(--dt-primary-rgb),.08)}.sticky-header .table-wrapper{overflow-y:auto}.sticky-header thead{position:sticky;top:0;z-index:5;box-shadow:0 1px 0 var(--dt-border)}.size-small{--dt-cell-padding-x: 12px;--dt-cell-padding-y: 10px;--dt-header-padding-y: 10px}.size-small th,.size-small td{font-size:.8125rem}.size-small thead th{font-size:.75rem}.size-small .selection-cell{width:44px;padding:6px 8px}.size-small .selection-cell ion-checkbox{--size: 18px}.size-small .row-number-cell{width:48px;font-size:.6875rem}.size-small .pagination-container{padding:12px 16px}.size-small .pagination-info,.size-small .page-indicator{font-size:.8125rem}.size-small .pagination-controls ion-button{height:32px;min-width:32px}.size-small .page-indicator{height:32px;min-width:70px}.size-large{--dt-cell-padding-x: 20px;--dt-cell-padding-y: 18px;--dt-header-padding-y: 16px}.size-large th,.size-large td{font-size:.9375rem}.size-large thead th{font-size:.875rem}.size-large .selection-cell{width:60px;padding:12px 16px}.size-large .selection-cell ion-checkbox{--size: 24px}.size-large .row-number-cell{width:72px;font-size:.875rem}.size-large .pagination-container{padding:20px 24px}.size-large .pagination-info,.size-large .page-indicator{font-size:.9375rem}.size-large .pagination-controls ion-button{height:40px;min-width:40px}.size-large .page-indicator{height:40px;min-width:90px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media (max-width: 768px){.data-table-container{--dt-border-radius: 12px}.pagination-container{flex-direction:column;align-items:stretch;gap:12px}.pagination-info{justify-content:space-between}.pagination-controls{justify-content:center}}.table-toolbar{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:20px;border-bottom:1px solid var(--dt-border);background:var(--dt-surface);flex-wrap:wrap}.table-toolbar:empty{display:none}@media (max-width: 576px){.table-toolbar{flex-direction:column;align-items:stretch;padding:16px}}.status-badge{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border-radius:9999px;font-size:.75rem;font-weight:600;white-space:nowrap;letter-spacing:.025em}.status-badge--success{background:#dcfce7;color:#15803d}.status-badge--warning{background:#fef3c7;color:#b45309}.status-badge--danger{background:#fee2e2;color:#dc2626}.status-badge--primary{background:#e0e7ff;color:#4338ca}.status-badge--secondary{background:#f1f5f9;color:#475569}.status-badge--medium{background:#f1f5f9;color:#64748b}.status-badge--tertiary{background:#f3e8ff;color:#7c3aed}.status-badge--filled.status-badge--success{background:#22c55e;color:#fff}.status-badge--filled.status-badge--warning{background:#f59e0b;color:#fff}.status-badge--filled.status-badge--danger{background:#ef4444;color:#fff}.status-badge--filled.status-badge--primary{background:var(--dt-primary);color:#fff}.status-badge--outlined{background:transparent;border:1.5px solid currentColor}.status-badge--outlined.status-badge--success{color:#16a34a}.status-badge--outlined.status-badge--warning{color:#d97706}.status-badge--outlined.status-badge--danger{color:#dc2626}.status-badge--outlined.status-badge--primary{color:var(--dt-primary)}.action-buttons{display:flex;gap:6px;justify-content:center}.action-buttons ion-button{--padding-start: 8px;--padding-end: 8px;--border-radius: 8px;margin:0}.action-buttons ion-button ion-icon{font-size:1.125rem}.card-list{display:none;padding:12px;gap:12px}.data-card{background:var(--dt-surface);border:1px solid var(--dt-border);border-radius:12px;padding:16px;margin-bottom:12px;transition:all .2s ease}.data-card.selected{border-color:var(--dt-primary);background:rgba(var(--dt-primary-rgb),.04);box-shadow:0 0 0 1px var(--dt-primary)}.data-card.clickable{cursor:pointer}.data-card.clickable:hover{box-shadow:var(--dt-elevation-medium);transform:translateY(-2px)}.data-card.clickable:active{transform:translateY(0)}.card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;padding-bottom:12px;border-bottom:1px solid var(--dt-border)}.card-selection{display:flex;align-items:center}.card-body{display:flex;flex-direction:column;gap:12px}.card-field{display:flex;justify-content:space-between;align-items:flex-start;gap:16px}.card-field__label{font-size:.75rem;font-weight:600;color:var(--dt-text-muted);flex-shrink:0}.card-field__value{font-size:.875rem;color:var(--dt-text-primary);text-align:right;word-break:break-word;font-weight:500}.card-actions{display:flex;justify-content:flex-end;margin-top:16px;padding-top:12px;border-top:1px solid var(--dt-border)}@media (max-width: 768px){.responsive-cards .table-wrapper{display:none}.responsive-cards .card-list{display:block}}:host-context(body.dark) .data-table-container,:host-context(.dark) .data-table-container,:host-context(.ion-palette-dark) .data-table-container,:host-context(html.ion-palette-dark) .data-table-container,:host-context([data-theme=dark]) .data-table-container{--dt-surface: #1e293b;--dt-surface-variant: #334155;--dt-border: #475569;--dt-text-primary: #f1f5f9;--dt-text-secondary: #94a3b8;--dt-text-muted: #64748b}:host-context(body.dark) .loading-overlay,:host-context(.dark) .loading-overlay,:host-context(.ion-palette-dark) .loading-overlay,:host-context(html.ion-palette-dark) .loading-overlay,:host-context([data-theme=dark]) .loading-overlay{background:#1e293be6}:host-context(body.dark) .status-badge--success,:host-context(.dark) .status-badge--success,:host-context(.ion-palette-dark) .status-badge--success,:host-context(html.ion-palette-dark) .status-badge--success,:host-context([data-theme=dark]) .status-badge--success{background:#22c55e33;color:#4ade80}:host-context(body.dark) .status-badge--warning,:host-context(.dark) .status-badge--warning,:host-context(.ion-palette-dark) .status-badge--warning,:host-context(html.ion-palette-dark) .status-badge--warning,:host-context([data-theme=dark]) .status-badge--warning{background:#f59e0b33;color:#fbbf24}:host-context(body.dark) .status-badge--danger,:host-context(.dark) .status-badge--danger,:host-context(.ion-palette-dark) .status-badge--danger,:host-context(html.ion-palette-dark) .status-badge--danger,:host-context([data-theme=dark]) .status-badge--danger{background:#ef444433;color:#f87171}:host-context(body.dark) .status-badge--primary,:host-context(.dark) .status-badge--primary,:host-context(.ion-palette-dark) .status-badge--primary,:host-context(html.ion-palette-dark) .status-badge--primary,:host-context([data-theme=dark]) .status-badge--primary{background:#6366f133;color:#a5b4fc}\n"] }]
        }], propDecorators: { props: [{
                type: Input
            }], rowClick: [{
                type: Output
            }], selectionChange: [{
                type: Output
            }], sortChange: [{
                type: Output
            }], pageChange: [{
                type: Output
            }] } });
//# sourceMappingURL=data:application/json;base64, 