@ddiazr/data-table 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,9 +14,12 @@ npm install @ddiazr/data-table
14
14
  npm i bootstrap @fortawesome/fontawesome-free
15
15
  ```
16
16
 
17
- ## TableColumn && TableAction
17
+ ## Interfaces && Type
18
18
 
19
19
  ```bash
20
+ type DataType = 'string' | 'number' | 'currency' | 'date' | 'boolean';
21
+ type Position = 'end' | 'start';
22
+
20
23
  interface TableAction<T> {
21
24
  label: string;
22
25
  icon?: string;
@@ -36,48 +39,33 @@ interface TableColumn<T> {
36
39
 
37
40
  ## Campos
38
41
 
39
- | Propiedad | Tipo | Obligatorio | Descripción |
40
- | --------------- | ------------------ | ----------- | ----------------------------------------------------- |
41
- | `data` | `any[]` | ✅ Sí | Datos de entrada segun el jsonen la tabla |
42
- | `columns` | `ColumnConfig[]` | ✅ Sí | Datos de las columnas que quieras que tenga la tabla |
43
- | `filterPlaceholder` | `string` | ❌ No | Si necesita cambiar al buscador el placeholder |
44
- | `showExportButtons` | `boolean` | ❌ No | Todos los botnes de exportar (EXCEL, PDF O PRINT) |
45
- | `actions` | `TableAction<T>[]` | ❌ No | Funcion que devuelve la accion segun el columnsConfig |
42
+ | Propiedad | Tipo | Obligatorio | Descripción |
43
+ | ------------------- | ------------------ | ----------- | ------------------------------------------------------------------------------- |
44
+ | `data` | `any[]` | ✅ Sí | Json que contendra la tabla |
45
+ | `columns` | `ColumnConfig[]` | ✅ Sí | Columnas que seran parametrizadas a mostrar al usuario |
46
+ | `filterPlaceholder` | `string` | ❌ No | Si necesita cambiar al buscador el placeholder |
47
+ | `showExportButtons` | `boolean` | ❌ No | Todos los botones de exportar defecto false (EXCEL, PDF O PRINT) |
48
+ | `actions` | `TableAction<T>[]` | ❌ No | Funcion que devuelve la accion segun el columnsConfig |
49
+ | `positionActions` | `Position` | ❌ No | La posicion de los botones action. start(primera columna), end (ultima columna) |
46
50
 
47
51
  ## Uso básico
48
52
 
49
53
  ```typescript
50
- import { DataTable } from '@ddiazr/utilt-service';
51
-
52
- interface TableAction<T> {
53
- label: string;
54
- icon?: string;
55
- styleClass?: string; // Clases CSS (ej: Bootstrap)
56
- callback: (row: T) => void;
57
- isVisible?: (row: T) => boolean;
58
- }
54
+ import { DataTable, TableColumn, TableAction, DataType, Position } from '@ddiazr/data-table';
59
55
 
60
- interface TableColumn<T> {
61
- key: keyof T | 'actions' | 'select';
62
- label: string;
63
- isSortable?: boolean;
64
- templateRef?: any;
65
- dataType?: DataType;
66
- }
67
56
  @Component({
68
57
  imports: [DataTable],
69
58
  template: `
70
- <tbl-generic-drag-and-drop
59
+ <dtbl-data-table
71
60
  [data]="data()"
72
- [columns]="columns()"
61
+ [columns]="columns()"
73
62
  [actions]="actions()"
74
- filterPlaceholder='BUSCAR POR'
63
+ filterPlaceholder="BUSCAR POR"
75
64
  [showExportButtons]="true"
76
65
  />
77
66
  `,
78
67
  })
79
68
  export class AppComponent {
80
-
81
69
  data = signal<any[]>([
82
70
  {
83
71
  id: 1,
@@ -95,8 +83,8 @@ export class AppComponent {
95
83
  },
96
84
  ]);
97
85
  //DECALRAMOS LAS COLUMNAS QUE VA A CONTENER LA TABLA
98
- columns = signal<TableColumn[]>([
99
- {
86
+ columns = signal<TableColumn<any>[]>([
87
+ {
100
88
  key: 'id',
101
89
  label: 'ID',
102
90
  },
@@ -134,7 +122,7 @@ export class AppComponent {
134
122
  label: 'Edit',
135
123
  icon: 'fa fa-edit',
136
124
  styleClass: 'btn-warning',
137
- showIf: (row) => row.edad > 18,
125
+ isVisible: (row) => row.edad > 18,
138
126
  callback: (row) => this.edit(row),
139
127
  },
140
128
  {
@@ -79,7 +79,8 @@ class DataTable {
79
79
  columns = input.required(...(ngDevMode ? [{ debugName: "columns" }] : []));
80
80
  actions = input([], ...(ngDevMode ? [{ debugName: "actions" }] : []));
81
81
  filterPlaceholder = input('Buscar...', ...(ngDevMode ? [{ debugName: "filterPlaceholder" }] : []));
82
- showExportButtons = input(true, ...(ngDevMode ? [{ debugName: "showExportButtons" }] : []));
82
+ showExportButtons = input(false, ...(ngDevMode ? [{ debugName: "showExportButtons" }] : []));
83
+ positionActions = input('end', ...(ngDevMode ? [{ debugName: "positionActions" }] : []));
83
84
  // ------------------------------------
84
85
  // II. OUTPUTS (Usando la función output())
85
86
  // ------------------------------------
@@ -215,16 +216,12 @@ class DataTable {
215
216
  this.currentPage.set(1);
216
217
  }
217
218
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: DataTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
218
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: DataTable, isStandalone: true, selector: "dtbl-data-table", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, filterPlaceholder: { classPropertyName: "filterPlaceholder", publicName: "filterPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, showExportButtons: { classPropertyName: "showExportButtons", publicName: "showExportButtons", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionClicked: "actionClicked", exportRequested: "exportRequested" }, ngImport: i0, template: "<div class=\"container-fluid pt-3\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <input\r\n type=\"text\"\r\n class=\"form-control w-25\"\r\n [placeholder]=\"filterPlaceholder()\"\r\n [ngModel]=\"filterTerm()\"\r\n (ngModelChange)=\"onSearchChange($event)\"\r\n />\r\n\r\n @if (showExportButtons()) {\r\n <div class=\"export-buttons btn-group\" role=\"group\">\r\n <button class=\"btn btn-outline-success\" (click)=\"exportData('excel')\">\r\n <i class=\"bi bi-file-earmark-excel\"></i> Exportar a Excel\r\n </button>\r\n <button class=\"btn btn-outline-danger\" (click)=\"exportData('pdf')\">\r\n <i class=\"bi bi-file-earmark-pdf\"></i> Exportar a PDF\r\n </button>\r\n <button class=\"btn btn-outline-secondary\" (click)=\"exportData('print')\">\r\n <i class=\"bi bi-printer\"></i> Imprimir\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"table-responsive\">\r\n <table class=\"table table-hover table-bordered caption-top\">\r\n <caption>\r\n Mostrando\r\n {{\r\n paginatedData().length\r\n }}\r\n de\r\n {{\r\n sortedAndFilteredData().length\r\n }}\r\n resultados (Total:\r\n {{\r\n data().length\r\n }}).\r\n </caption>\r\n\r\n <thead>\r\n <tr>\r\n @for (col of columns(); track col.key) {\r\n <th\r\n [class.sortable]=\"col.isSortable\"\r\n (click)=\"col.isSortable && onSort(col.key)\"\r\n scope=\"col\"\r\n class=\"text-nowrap\"\r\n >\r\n <div class=\"d-flex align-items-center justify-content-between\">\r\n <span class=\"fw-bold\">{{ col.label }}</span>\r\n\r\n @if (col.isSortable) {\r\n @if (col.key === sortState().column) {\r\n <i\r\n class=\"fa-solid ms-1\"\r\n [class.fa-sort-up]=\"sortState().direction === 'asc'\"\r\n [class.fa-sort-down]=\"sortState().direction === 'desc'\"\r\n >\r\n </i>\r\n } @else {\r\n <i class=\"fa-solid fa-sort text-muted ms-1\" style=\"opacity: 0.5\"></i>\r\n }\r\n }\r\n </div>\r\n </th>\r\n }\r\n @if (actions().length > 0) {\r\n <th class=\"bg-dark text-center text-white\">Acciones</th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <tbody>\r\n @for (row of paginatedData(); track row.id || $index) {\r\n <tr>\r\n @for (col of columns(); track col.key) {\r\n <td class=\"text-nowrap\">\r\n @if (col.templateRef) {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n col.templateRef;\r\n context: { $implicit: row, column: col.key }\r\n \"\r\n ></ng-container>\r\n } @else {\r\n <!-- {{ formatCellValue(row, col) }} -->\r\n @let config = getConfig(col.key.toString());\r\n @switch (config?.dataType) {\r\n @case ('date') {\r\n {{ $any(row)[col.key] | safeDate }}\r\n }\r\n @case ('currency') {\r\n {{ $any(row)[col.key] | safeCurrency }}\r\n }\r\n @case ('number') {\r\n {{ $any(row)[col.key] | safeNumber }}\r\n }\r\n @default {\r\n {{ $any(row)[col.key] }}\r\n }\r\n }\r\n }\r\n </td>\r\n }\r\n @if (actions().length > 0) {\r\n <td class=\"text-center\">\r\n @for (action of actions(); track action.label) {\r\n @if (!action.isVisible || action.isVisible(row)) {\r\n <button\r\n [class]=\"'btn btn-sm mx-1 ' + action.styleClass\"\r\n (click)=\"action.callback(row)\"\r\n >\r\n <i [class]=\"action.icon\"></i>\r\n </button>\r\n }\r\n }\r\n </td>\r\n }\r\n </tr>\r\n } @empty {\r\n <tr>\r\n <td [attr.colspan]=\"columns().length\" class=\"text-center\">\r\n No hay datos disponibles para mostrar.\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n <div class=\"d-flex justify-content-between align-items-center mt-3\">\r\n <div class=\"d-flex align-items-center\">\r\n <label for=\"pageSizeSelect\" class=\"me-2 text-nowrap\">Art\u00EDculos por p\u00E1gina: </label>\r\n <select\r\n id=\"pageSizeSelect\"\r\n class=\"form-select form-select-sm w-auto\"\r\n (change)=\"onPageSizeChange($event)\"\r\n >\r\n <option value=\"10\" [selected]=\"pageSize() === 10\">10</option>\r\n <option value=\"25\" [selected]=\"pageSize() === 25\">25</option>\r\n <option value=\"50\" [selected]=\"pageSize() === 50\">50</option>\r\n <option value=\"100\" [selected]=\"pageSize() === 100\">100</option>\r\n </select>\r\n </div>\r\n\r\n <nav aria-label=\"Paginaci\u00F3n de tabla\">\r\n <ul class=\"pagination pagination-md mb-0\">\r\n <li class=\"page-item\" [class.disabled]=\"currentPage() === 1\">\r\n <button type=\"button\" class=\"page-link\" (click)=\"goToPage(currentPage() - 1)\"><<</button>\r\n </li>\r\n\r\n @for (pageNumber of pagesToShow(); track pageNumber) {\r\n <li class=\"page-item\" [class.active]=\"currentPage() === pageNumber\">\r\n <button type=\"button\" class=\"page-link\" (click)=\"goToPage(pageNumber)\">\r\n {{ pageNumber }}\r\n </button>\r\n </li>\r\n }\r\n\r\n <li class=\"page-item\" [class.disabled]=\"currentPage() === totalPages()\">\r\n <button type=\"button\" class=\"page-link\" (click)=\"goToPage(currentPage() + 1)\">>></button>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: SafeDatePipe, name: "safeDate" }, { kind: "pipe", type: SafeCurrencyPipe, name: "safeCurrency" }, { kind: "pipe", type: SafeNumberPipe, name: "safeNumber" }] });
219
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: DataTable, isStandalone: true, selector: "dtbl-data-table", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, filterPlaceholder: { classPropertyName: "filterPlaceholder", publicName: "filterPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, showExportButtons: { classPropertyName: "showExportButtons", publicName: "showExportButtons", isSignal: true, isRequired: false, transformFunction: null }, positionActions: { classPropertyName: "positionActions", publicName: "positionActions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionClicked: "actionClicked", exportRequested: "exportRequested" }, ngImport: i0, template: "<div class=\"container-fluid pt-3\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <input\r\n type=\"text\"\r\n class=\"form-control w-25\"\r\n [placeholder]=\"filterPlaceholder()\"\r\n [ngModel]=\"filterTerm()\"\r\n (ngModelChange)=\"onSearchChange($event)\"\r\n />\r\n\r\n @if (showExportButtons()) {\r\n <div class=\"export-buttons btn-group\" role=\"group\">\r\n <button class=\"btn btn-outline-success\" (click)=\"exportData('excel')\">\r\n <i class=\"fa fa-file-excel\"></i> Exportar a Excel\r\n </button>\r\n <button class=\"btn btn-outline-danger\" (click)=\"exportData('pdf')\">\r\n <i class=\"fa fa-file-pdf\"></i> Exportar a PDF\r\n </button>\r\n <button class=\"btn btn-outline-secondary\" (click)=\"exportData('print')\">\r\n <i class=\"fa fa-print\"></i> Imprimir\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"table-responsive\">\r\n <table class=\"table table-hover table-bordered caption-top\">\r\n <caption>\r\n Mostrando\r\n {{\r\n paginatedData().length\r\n }}\r\n de\r\n {{\r\n sortedAndFilteredData().length\r\n }}\r\n resultados (Total:\r\n {{\r\n data().length\r\n }}).\r\n </caption>\r\n\r\n <thead>\r\n <tr>\r\n @if (actions().length > 0 && positionActions() === 'start') {\r\n <th class=\"bg-dark text-center text-white\">Acciones</th>\r\n }\r\n @for (col of columns(); track col.key) {\r\n <th\r\n [class.sortable]=\"col.isSortable\"\r\n (click)=\"col.isSortable && onSort(col.key)\"\r\n scope=\"col\"\r\n class=\"text-nowrap\"\r\n >\r\n <div class=\"d-flex align-items-center justify-content-between\">\r\n <span class=\"fw-bold\">{{ col.label }}</span>\r\n\r\n @if (col.isSortable) {\r\n @if (col.key === sortState().column) {\r\n <i\r\n class=\"fa fa-solid ms-1\"\r\n [class.fa-sort-up]=\"sortState().direction === 'asc'\"\r\n [class.fa-sort-down]=\"sortState().direction === 'desc'\"\r\n >\r\n </i>\r\n } @else {\r\n <i class=\"fa fa-solid fa-sort text-muted ms-1\" style=\"opacity: 0.5\"></i>\r\n }\r\n }\r\n </div>\r\n </th>\r\n }\r\n @if (actions().length > 0 && positionActions() === 'end') {\r\n <th class=\"bg-dark text-center text-white\">Acciones</th>\r\n }\r\n\r\n </tr>\r\n </thead>\r\n\r\n <tbody>\r\n @for (row of paginatedData(); track row.id || $index) {\r\n <tr>\r\n @if (actions().length > 0 && positionActions() === 'start') {\r\n <td class=\"text-center\">\r\n @for (action of actions(); track action.label) {\r\n @if (!action.isVisible || action.isVisible(row)) {\r\n <button\r\n [class]=\"'btn btn-sm mx-1 ' + action.styleClass\"\r\n (click)=\"action.callback(row)\"\r\n >\r\n <i [class]=\"action.icon\"></i>\r\n </button>\r\n }\r\n }\r\n </td>\r\n }\r\n @for (col of columns(); track col.key) {\r\n <td class=\"text-nowrap\">\r\n @if (col.templateRef) {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n col.templateRef;\r\n context: { $implicit: row, column: col.key }\r\n \"\r\n ></ng-container>\r\n } @else {\r\n <!-- {{ formatCellValue(row, col) }} -->\r\n @let config = getConfig(col.key.toString());\r\n @switch (config?.dataType) {\r\n @case ('date') {\r\n {{ $any(row)[col.key] | safeDate }}\r\n }\r\n @case ('currency') {\r\n {{ $any(row)[col.key] | safeCurrency }}\r\n }\r\n @case ('number') {\r\n {{ $any(row)[col.key] | safeNumber }}\r\n }\r\n @default {\r\n {{ $any(row)[col.key] }}\r\n }\r\n }\r\n }\r\n </td>\r\n }\r\n @if (actions().length > 0 && positionActions() === 'end') {\r\n <td class=\"text-center\">\r\n @for (action of actions(); track action.label) {\r\n @if (!action.isVisible || action.isVisible(row)) {\r\n <button\r\n [class]=\"'btn btn-sm mx-1 ' + action.styleClass\"\r\n (click)=\"action.callback(row)\"\r\n >\r\n <i [class]=\"action.icon\"></i>\r\n </button>\r\n }\r\n }\r\n </td>\r\n }\r\n </tr>\r\n } @empty {\r\n <tr>\r\n <td [attr.colspan]=\"columns().length\" class=\"text-center\">\r\n No hay datos disponibles para mostrar.\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n <div class=\"d-flex justify-content-between align-items-center mt-3\">\r\n <div class=\"d-flex align-items-center\">\r\n <label for=\"pageSizeSelect\" class=\"me-2 text-nowrap\">Art\u00EDculos por p\u00E1gina: </label>\r\n <select\r\n id=\"pageSizeSelect\"\r\n class=\"form-select form-select-sm w-auto\"\r\n (change)=\"onPageSizeChange($event)\"\r\n >\r\n <option value=\"10\" [selected]=\"pageSize() === 10\">10</option>\r\n <option value=\"25\" [selected]=\"pageSize() === 25\">25</option>\r\n <option value=\"50\" [selected]=\"pageSize() === 50\">50</option>\r\n <option value=\"100\" [selected]=\"pageSize() === 100\">100</option>\r\n </select>\r\n </div>\r\n\r\n <nav aria-label=\"Paginaci\u00F3n de tabla\">\r\n <ul class=\"pagination pagination-md mb-0\">\r\n <li class=\"page-item\" [class.disabled]=\"currentPage() === 1\">\r\n <button type=\"button\" class=\"page-link\" (click)=\"goToPage(currentPage() - 1)\"><<</button>\r\n </li>\r\n\r\n @for (pageNumber of pagesToShow(); track pageNumber) {\r\n <li class=\"page-item\" [class.active]=\"currentPage() === pageNumber\">\r\n <button type=\"button\" class=\"page-link\" (click)=\"goToPage(pageNumber)\">\r\n {{ pageNumber }}\r\n </button>\r\n </li>\r\n }\r\n\r\n <li class=\"page-item\" [class.disabled]=\"currentPage() === totalPages()\">\r\n <button type=\"button\" class=\"page-link\" (click)=\"goToPage(currentPage() + 1)\">>></button>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: SafeDatePipe, name: "safeDate" }, { kind: "pipe", type: SafeCurrencyPipe, name: "safeCurrency" }, { kind: "pipe", type: SafeNumberPipe, name: "safeNumber" }] });
219
220
  }
220
221
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: DataTable, decorators: [{
221
222
  type: Component,
222
- args: [{ selector: 'dtbl-data-table', imports: [CommonModule, FormsModule, SafeDatePipe, SafeCurrencyPipe, SafeNumberPipe], template: "<div class=\"container-fluid pt-3\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <input\r\n type=\"text\"\r\n class=\"form-control w-25\"\r\n [placeholder]=\"filterPlaceholder()\"\r\n [ngModel]=\"filterTerm()\"\r\n (ngModelChange)=\"onSearchChange($event)\"\r\n />\r\n\r\n @if (showExportButtons()) {\r\n <div class=\"export-buttons btn-group\" role=\"group\">\r\n <button class=\"btn btn-outline-success\" (click)=\"exportData('excel')\">\r\n <i class=\"bi bi-file-earmark-excel\"></i> Exportar a Excel\r\n </button>\r\n <button class=\"btn btn-outline-danger\" (click)=\"exportData('pdf')\">\r\n <i class=\"bi bi-file-earmark-pdf\"></i> Exportar a PDF\r\n </button>\r\n <button class=\"btn btn-outline-secondary\" (click)=\"exportData('print')\">\r\n <i class=\"bi bi-printer\"></i> Imprimir\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"table-responsive\">\r\n <table class=\"table table-hover table-bordered caption-top\">\r\n <caption>\r\n Mostrando\r\n {{\r\n paginatedData().length\r\n }}\r\n de\r\n {{\r\n sortedAndFilteredData().length\r\n }}\r\n resultados (Total:\r\n {{\r\n data().length\r\n }}).\r\n </caption>\r\n\r\n <thead>\r\n <tr>\r\n @for (col of columns(); track col.key) {\r\n <th\r\n [class.sortable]=\"col.isSortable\"\r\n (click)=\"col.isSortable && onSort(col.key)\"\r\n scope=\"col\"\r\n class=\"text-nowrap\"\r\n >\r\n <div class=\"d-flex align-items-center justify-content-between\">\r\n <span class=\"fw-bold\">{{ col.label }}</span>\r\n\r\n @if (col.isSortable) {\r\n @if (col.key === sortState().column) {\r\n <i\r\n class=\"fa-solid ms-1\"\r\n [class.fa-sort-up]=\"sortState().direction === 'asc'\"\r\n [class.fa-sort-down]=\"sortState().direction === 'desc'\"\r\n >\r\n </i>\r\n } @else {\r\n <i class=\"fa-solid fa-sort text-muted ms-1\" style=\"opacity: 0.5\"></i>\r\n }\r\n }\r\n </div>\r\n </th>\r\n }\r\n @if (actions().length > 0) {\r\n <th class=\"bg-dark text-center text-white\">Acciones</th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <tbody>\r\n @for (row of paginatedData(); track row.id || $index) {\r\n <tr>\r\n @for (col of columns(); track col.key) {\r\n <td class=\"text-nowrap\">\r\n @if (col.templateRef) {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n col.templateRef;\r\n context: { $implicit: row, column: col.key }\r\n \"\r\n ></ng-container>\r\n } @else {\r\n <!-- {{ formatCellValue(row, col) }} -->\r\n @let config = getConfig(col.key.toString());\r\n @switch (config?.dataType) {\r\n @case ('date') {\r\n {{ $any(row)[col.key] | safeDate }}\r\n }\r\n @case ('currency') {\r\n {{ $any(row)[col.key] | safeCurrency }}\r\n }\r\n @case ('number') {\r\n {{ $any(row)[col.key] | safeNumber }}\r\n }\r\n @default {\r\n {{ $any(row)[col.key] }}\r\n }\r\n }\r\n }\r\n </td>\r\n }\r\n @if (actions().length > 0) {\r\n <td class=\"text-center\">\r\n @for (action of actions(); track action.label) {\r\n @if (!action.isVisible || action.isVisible(row)) {\r\n <button\r\n [class]=\"'btn btn-sm mx-1 ' + action.styleClass\"\r\n (click)=\"action.callback(row)\"\r\n >\r\n <i [class]=\"action.icon\"></i>\r\n </button>\r\n }\r\n }\r\n </td>\r\n }\r\n </tr>\r\n } @empty {\r\n <tr>\r\n <td [attr.colspan]=\"columns().length\" class=\"text-center\">\r\n No hay datos disponibles para mostrar.\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n <div class=\"d-flex justify-content-between align-items-center mt-3\">\r\n <div class=\"d-flex align-items-center\">\r\n <label for=\"pageSizeSelect\" class=\"me-2 text-nowrap\">Art\u00EDculos por p\u00E1gina: </label>\r\n <select\r\n id=\"pageSizeSelect\"\r\n class=\"form-select form-select-sm w-auto\"\r\n (change)=\"onPageSizeChange($event)\"\r\n >\r\n <option value=\"10\" [selected]=\"pageSize() === 10\">10</option>\r\n <option value=\"25\" [selected]=\"pageSize() === 25\">25</option>\r\n <option value=\"50\" [selected]=\"pageSize() === 50\">50</option>\r\n <option value=\"100\" [selected]=\"pageSize() === 100\">100</option>\r\n </select>\r\n </div>\r\n\r\n <nav aria-label=\"Paginaci\u00F3n de tabla\">\r\n <ul class=\"pagination pagination-md mb-0\">\r\n <li class=\"page-item\" [class.disabled]=\"currentPage() === 1\">\r\n <button type=\"button\" class=\"page-link\" (click)=\"goToPage(currentPage() - 1)\"><<</button>\r\n </li>\r\n\r\n @for (pageNumber of pagesToShow(); track pageNumber) {\r\n <li class=\"page-item\" [class.active]=\"currentPage() === pageNumber\">\r\n <button type=\"button\" class=\"page-link\" (click)=\"goToPage(pageNumber)\">\r\n {{ pageNumber }}\r\n </button>\r\n </li>\r\n }\r\n\r\n <li class=\"page-item\" [class.disabled]=\"currentPage() === totalPages()\">\r\n <button type=\"button\" class=\"page-link\" (click)=\"goToPage(currentPage() + 1)\">>></button>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</div>\r\n" }]
223
- }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], filterPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterPlaceholder", required: false }] }], showExportButtons: [{ type: i0.Input, args: [{ isSignal: true, alias: "showExportButtons", required: false }] }], actionClicked: [{ type: i0.Output, args: ["actionClicked"] }], exportRequested: [{ type: i0.Output, args: ["exportRequested"] }] } });
224
-
225
- /*
226
- * Public API Surface of data-table
227
- */
223
+ args: [{ selector: 'dtbl-data-table', imports: [CommonModule, FormsModule, SafeDatePipe, SafeCurrencyPipe, SafeNumberPipe], template: "<div class=\"container-fluid pt-3\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <input\r\n type=\"text\"\r\n class=\"form-control w-25\"\r\n [placeholder]=\"filterPlaceholder()\"\r\n [ngModel]=\"filterTerm()\"\r\n (ngModelChange)=\"onSearchChange($event)\"\r\n />\r\n\r\n @if (showExportButtons()) {\r\n <div class=\"export-buttons btn-group\" role=\"group\">\r\n <button class=\"btn btn-outline-success\" (click)=\"exportData('excel')\">\r\n <i class=\"fa fa-file-excel\"></i> Exportar a Excel\r\n </button>\r\n <button class=\"btn btn-outline-danger\" (click)=\"exportData('pdf')\">\r\n <i class=\"fa fa-file-pdf\"></i> Exportar a PDF\r\n </button>\r\n <button class=\"btn btn-outline-secondary\" (click)=\"exportData('print')\">\r\n <i class=\"fa fa-print\"></i> Imprimir\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"table-responsive\">\r\n <table class=\"table table-hover table-bordered caption-top\">\r\n <caption>\r\n Mostrando\r\n {{\r\n paginatedData().length\r\n }}\r\n de\r\n {{\r\n sortedAndFilteredData().length\r\n }}\r\n resultados (Total:\r\n {{\r\n data().length\r\n }}).\r\n </caption>\r\n\r\n <thead>\r\n <tr>\r\n @if (actions().length > 0 && positionActions() === 'start') {\r\n <th class=\"bg-dark text-center text-white\">Acciones</th>\r\n }\r\n @for (col of columns(); track col.key) {\r\n <th\r\n [class.sortable]=\"col.isSortable\"\r\n (click)=\"col.isSortable && onSort(col.key)\"\r\n scope=\"col\"\r\n class=\"text-nowrap\"\r\n >\r\n <div class=\"d-flex align-items-center justify-content-between\">\r\n <span class=\"fw-bold\">{{ col.label }}</span>\r\n\r\n @if (col.isSortable) {\r\n @if (col.key === sortState().column) {\r\n <i\r\n class=\"fa fa-solid ms-1\"\r\n [class.fa-sort-up]=\"sortState().direction === 'asc'\"\r\n [class.fa-sort-down]=\"sortState().direction === 'desc'\"\r\n >\r\n </i>\r\n } @else {\r\n <i class=\"fa fa-solid fa-sort text-muted ms-1\" style=\"opacity: 0.5\"></i>\r\n }\r\n }\r\n </div>\r\n </th>\r\n }\r\n @if (actions().length > 0 && positionActions() === 'end') {\r\n <th class=\"bg-dark text-center text-white\">Acciones</th>\r\n }\r\n\r\n </tr>\r\n </thead>\r\n\r\n <tbody>\r\n @for (row of paginatedData(); track row.id || $index) {\r\n <tr>\r\n @if (actions().length > 0 && positionActions() === 'start') {\r\n <td class=\"text-center\">\r\n @for (action of actions(); track action.label) {\r\n @if (!action.isVisible || action.isVisible(row)) {\r\n <button\r\n [class]=\"'btn btn-sm mx-1 ' + action.styleClass\"\r\n (click)=\"action.callback(row)\"\r\n >\r\n <i [class]=\"action.icon\"></i>\r\n </button>\r\n }\r\n }\r\n </td>\r\n }\r\n @for (col of columns(); track col.key) {\r\n <td class=\"text-nowrap\">\r\n @if (col.templateRef) {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n col.templateRef;\r\n context: { $implicit: row, column: col.key }\r\n \"\r\n ></ng-container>\r\n } @else {\r\n <!-- {{ formatCellValue(row, col) }} -->\r\n @let config = getConfig(col.key.toString());\r\n @switch (config?.dataType) {\r\n @case ('date') {\r\n {{ $any(row)[col.key] | safeDate }}\r\n }\r\n @case ('currency') {\r\n {{ $any(row)[col.key] | safeCurrency }}\r\n }\r\n @case ('number') {\r\n {{ $any(row)[col.key] | safeNumber }}\r\n }\r\n @default {\r\n {{ $any(row)[col.key] }}\r\n }\r\n }\r\n }\r\n </td>\r\n }\r\n @if (actions().length > 0 && positionActions() === 'end') {\r\n <td class=\"text-center\">\r\n @for (action of actions(); track action.label) {\r\n @if (!action.isVisible || action.isVisible(row)) {\r\n <button\r\n [class]=\"'btn btn-sm mx-1 ' + action.styleClass\"\r\n (click)=\"action.callback(row)\"\r\n >\r\n <i [class]=\"action.icon\"></i>\r\n </button>\r\n }\r\n }\r\n </td>\r\n }\r\n </tr>\r\n } @empty {\r\n <tr>\r\n <td [attr.colspan]=\"columns().length\" class=\"text-center\">\r\n No hay datos disponibles para mostrar.\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n <div class=\"d-flex justify-content-between align-items-center mt-3\">\r\n <div class=\"d-flex align-items-center\">\r\n <label for=\"pageSizeSelect\" class=\"me-2 text-nowrap\">Art\u00EDculos por p\u00E1gina: </label>\r\n <select\r\n id=\"pageSizeSelect\"\r\n class=\"form-select form-select-sm w-auto\"\r\n (change)=\"onPageSizeChange($event)\"\r\n >\r\n <option value=\"10\" [selected]=\"pageSize() === 10\">10</option>\r\n <option value=\"25\" [selected]=\"pageSize() === 25\">25</option>\r\n <option value=\"50\" [selected]=\"pageSize() === 50\">50</option>\r\n <option value=\"100\" [selected]=\"pageSize() === 100\">100</option>\r\n </select>\r\n </div>\r\n\r\n <nav aria-label=\"Paginaci\u00F3n de tabla\">\r\n <ul class=\"pagination pagination-md mb-0\">\r\n <li class=\"page-item\" [class.disabled]=\"currentPage() === 1\">\r\n <button type=\"button\" class=\"page-link\" (click)=\"goToPage(currentPage() - 1)\"><<</button>\r\n </li>\r\n\r\n @for (pageNumber of pagesToShow(); track pageNumber) {\r\n <li class=\"page-item\" [class.active]=\"currentPage() === pageNumber\">\r\n <button type=\"button\" class=\"page-link\" (click)=\"goToPage(pageNumber)\">\r\n {{ pageNumber }}\r\n </button>\r\n </li>\r\n }\r\n\r\n <li class=\"page-item\" [class.disabled]=\"currentPage() === totalPages()\">\r\n <button type=\"button\" class=\"page-link\" (click)=\"goToPage(currentPage() + 1)\">>></button>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</div>\r\n" }]
224
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], filterPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterPlaceholder", required: false }] }], showExportButtons: [{ type: i0.Input, args: [{ isSignal: true, alias: "showExportButtons", required: false }] }], positionActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "positionActions", required: false }] }], actionClicked: [{ type: i0.Output, args: ["actionClicked"] }], exportRequested: [{ type: i0.Output, args: ["exportRequested"] }] } });
228
225
 
229
226
  /**
230
227
  * Generated bundle index. Do not edit.
@@ -1 +1 @@
1
- {"version":3,"file":"ddiazr-data-table.mjs","sources":["../../../projects/data-table/src/lib/pipes/safe-date.pipe.ts","../../../projects/data-table/src/lib/pipes/safe-currency.pipe.ts","../../../projects/data-table/src/lib/pipes/safe-number.pipe.ts","../../../projects/data-table/src/lib/data-table.ts","../../../projects/data-table/src/lib/data-table.html","../../../projects/data-table/src/public-api.ts","../../../projects/data-table/src/ddiazr-data-table.ts"],"sourcesContent":["import { Pipe, PipeTransform } from \"@angular/core\";\r\n\r\n@Pipe({\r\n name: \"safeDate\",\r\n standalone: true,\r\n pure: true, // ✅ Muy importante para performance\r\n})\r\nexport class SafeDatePipe implements PipeTransform {\r\n transform(value: any): string {\r\n if (!value) return \"\";\r\n const date = new Date(value);\r\n if (isNaN(date.getTime())) return value;\r\n\r\n const day = String(date.getDate()).padStart(2, \"0\");\r\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\r\n const year = date.getFullYear();\r\n\r\n return `${day}/${month}/${year}`;\r\n }\r\n}\r\n","import { Pipe, PipeTransform } from \"@angular/core\";\r\n\r\n@Pipe({\r\n name: 'safeCurrency',\r\n standalone: true,\r\n pure: true\r\n})\r\nexport class SafeCurrencyPipe implements PipeTransform {\r\n transform(value: any): string {\r\n if (value == null || value === '') return '';\r\n const num = Number(value);\r\n if (isNaN(num)) return value;\r\n \r\n return 'Q' + num.toFixed(2).replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\r\n }\r\n}","import { Pipe, PipeTransform } from \"@angular/core\";\r\n\r\n@Pipe({\r\n name: \"safeNumber\",\r\n standalone: true,\r\n pure: true,\r\n})\r\nexport class SafeNumberPipe implements PipeTransform {\r\n transform(value: any): string {\r\n if (value == null || value === \"\") return \"\";\r\n const num = Number(value);\r\n if (isNaN(num)) return value;\r\n\r\n return num.toFixed(2).replace(/\\B(?=(\\d{3})+(?!\\d))/g, \",\");\r\n }\r\n}\r\n","import { CommonModule } from '@angular/common';\r\nimport { Component, computed, input, output, signal, WritableSignal } from '@angular/core';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { SortDirection, TableColumn, SortState, TableAction } from './interfaces/table.interface';\r\nimport { SafeDatePipe } from './pipes/safe-date.pipe';\r\nimport { SafeCurrencyPipe } from './pipes/safe-currency.pipe';\r\nimport { SafeNumberPipe } from './pipes/safe-number.pipe';\r\n@Component({\r\n selector: 'dtbl-data-table',\r\n imports: [CommonModule, FormsModule, SafeDatePipe, SafeCurrencyPipe, SafeNumberPipe],\r\n templateUrl: './data-table.html',\r\n styles: ``,\r\n})\r\nexport class DataTable<T extends { id?: any }> {\r\n // ------------------------------------\r\n // I. INPUT SIGNALS\r\n // ------------------------------------\r\n public data = input.required<T[]>();\r\n public columns = input.required<TableColumn<T>[]>();\r\n public actions = input<TableAction<T>[]>([]);\r\n public filterPlaceholder = input<string>('Buscar...');\r\n public showExportButtons = input<boolean>(true);\r\n\r\n // ------------------------------------\r\n // II. OUTPUTS (Usando la función output())\r\n // ------------------------------------\r\n public actionClicked = output<{ action: string; rowData: T }>();\r\n public exportRequested = output<'pdf' | 'excel' | 'print'>();\r\n\r\n // ------------------------------------\r\n // III. ESTADO INTERNO (Signals para Filtrado)\r\n // ------------------------------------\r\n\r\n public filterTerm: WritableSignal<string> = signal('');\r\n public sortState: WritableSignal<SortState<T>> = signal({\r\n column: null,\r\n direction: null,\r\n });\r\n\r\n public currentPage: WritableSignal<number> = signal(1); // Página actual, inicia en 1\r\n public pageSize: WritableSignal<number> = signal(10); // Elementos por página\r\n\r\n // 4. Datos filtrados (Computed Signal - LÓGICA DE BÚSQUEDA)\r\n public filteredData = computed(() => {\r\n const term = this.filterTerm().toLowerCase();\r\n const currentData = this.data();\r\n\r\n if (!term) return currentData;\r\n\r\n return currentData.filter((item) =>\r\n Object.values(item as object).some((value) => String(value).toLowerCase().includes(term)),\r\n );\r\n });\r\n\r\n public sortedAndFilteredData = computed(() => {\r\n const data = [...this.filteredData()]; // Copia para ordenar\r\n const state = this.sortState();\r\n\r\n if (!state.column || !state.direction) {\r\n return data; // Sin ordenamiento\r\n }\r\n\r\n const directionMultiplier = state.direction === 'asc' ? 1 : -1;\r\n const columnKey = state.column as keyof T;\r\n\r\n return data.sort((a, b) => {\r\n // Usamos localeCompare para ordenar strings correctamente, si no, comparación simple\r\n const aValue = a[columnKey];\r\n const bValue = b[columnKey];\r\n\r\n if (typeof aValue === 'string' && typeof bValue === 'string') {\r\n return aValue.localeCompare(bValue) * directionMultiplier;\r\n }\r\n\r\n if (aValue < bValue) {\r\n return -1 * directionMultiplier;\r\n }\r\n if (aValue > bValue) {\r\n return 1 * directionMultiplier;\r\n }\r\n return 0;\r\n });\r\n });\r\n\r\n public paginatedData = computed(() => {\r\n const data = this.sortedAndFilteredData();\r\n const size = this.pageSize();\r\n const page = this.currentPage();\r\n\r\n const start = (page - 1) * size;\r\n const end = start + size;\r\n\r\n // Retorna solo el slice (rebanada) de datos de la página actual\r\n return data.slice(start, end);\r\n });\r\n\r\n public totalPages = computed(() => {\r\n const totalItems = this.sortedAndFilteredData().length;\r\n const size = this.pageSize();\r\n return Math.ceil(totalItems / size);\r\n });\r\n\r\n public pagesToShow = computed<number[]>(() => {\r\n const total = this.totalPages();\r\n const current = this.currentPage();\r\n const maxPagesToShow = 5; // Máximo de botones numéricos a mostrar\r\n const pages: number[] = [];\r\n\r\n // Lógica simple para centrar los botones en la página actual\r\n let start = Math.max(1, current - Math.floor(maxPagesToShow / 2));\r\n let end = Math.min(total, start + maxPagesToShow - 1);\r\n\r\n // Ajuste si la tabla es pequeña\r\n if (end - start + 1 < maxPagesToShow) {\r\n start = Math.max(1, end - maxPagesToShow + 1);\r\n }\r\n\r\n for (let i = start; i <= end; i++) {\r\n pages.push(i);\r\n }\r\n return pages;\r\n });\r\n\r\n // ------------------------------------\r\n // IV. FUNCIONES\r\n // ------------------------------------\r\n onSort(columnKey: keyof T | 'actions' | 'select'): void {\r\n // Solo permitir ordenar si no es una columna de acción/selección\r\n if (columnKey === 'actions' || columnKey === 'select') return;\r\n\r\n this.sortState.update((current) => {\r\n let newDirection: SortDirection = 'asc';\r\n\r\n if (current.column === columnKey) {\r\n // Mismo column, se alterna la dirección\r\n newDirection = current.direction === 'asc' ? 'desc' : 'asc';\r\n }\r\n\r\n return {\r\n column: columnKey as keyof T,\r\n direction: newDirection,\r\n };\r\n });\r\n }\r\n\r\n /**\r\n * FUNCIÓN DE BÚSQUEDA\r\n * Actualiza el WritableSignal interno.\r\n */\r\n onSearchChange(term: string): void {\r\n this.filterTerm.set(term);\r\n }\r\n\r\n /**\r\n * FUNCIÓN DE ACCIONES\r\n * Emite el evento usando .emit() del Output Signal.\r\n */\r\n onActionClick(action: string, rowData: T): void {\r\n this.actionClicked.emit({ action, rowData });\r\n }\r\n\r\n /**\r\n * FUNCIÓN DE EXPORTACIÓN\r\n * Emite el evento de salida, delegando la lógica al padre.\r\n */\r\n exportData(format: 'pdf' | 'excel' | 'print'): void {\r\n this.exportRequested.emit(format);\r\n }\r\n\r\n getConfig(key: string): TableColumn<T> | undefined {\r\n return this.columns().find((c) => c.key === key);\r\n }\r\n\r\n goToPage(page: number): void {\r\n const total = this.totalPages();\r\n if (page >= 1 && page <= total) {\r\n this.currentPage.set(page);\r\n }\r\n }\r\n\r\n onPageSizeChange(event: Event): void {\r\n const target = event.target as HTMLSelectElement;\r\n const newSize = Number(target.value);\r\n\r\n this.pageSize.set(newSize);\r\n // Reiniciar a la página 1 después de cambiar el tamaño para evitar errores de índice\r\n this.currentPage.set(1);\r\n }\r\n}\r\n","<div class=\"container-fluid pt-3\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <input\r\n type=\"text\"\r\n class=\"form-control w-25\"\r\n [placeholder]=\"filterPlaceholder()\"\r\n [ngModel]=\"filterTerm()\"\r\n (ngModelChange)=\"onSearchChange($event)\"\r\n />\r\n\r\n @if (showExportButtons()) {\r\n <div class=\"export-buttons btn-group\" role=\"group\">\r\n <button class=\"btn btn-outline-success\" (click)=\"exportData('excel')\">\r\n <i class=\"bi bi-file-earmark-excel\"></i> Exportar a Excel\r\n </button>\r\n <button class=\"btn btn-outline-danger\" (click)=\"exportData('pdf')\">\r\n <i class=\"bi bi-file-earmark-pdf\"></i> Exportar a PDF\r\n </button>\r\n <button class=\"btn btn-outline-secondary\" (click)=\"exportData('print')\">\r\n <i class=\"bi bi-printer\"></i> Imprimir\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"table-responsive\">\r\n <table class=\"table table-hover table-bordered caption-top\">\r\n <caption>\r\n Mostrando\r\n {{\r\n paginatedData().length\r\n }}\r\n de\r\n {{\r\n sortedAndFilteredData().length\r\n }}\r\n resultados (Total:\r\n {{\r\n data().length\r\n }}).\r\n </caption>\r\n\r\n <thead>\r\n <tr>\r\n @for (col of columns(); track col.key) {\r\n <th\r\n [class.sortable]=\"col.isSortable\"\r\n (click)=\"col.isSortable && onSort(col.key)\"\r\n scope=\"col\"\r\n class=\"text-nowrap\"\r\n >\r\n <div class=\"d-flex align-items-center justify-content-between\">\r\n <span class=\"fw-bold\">{{ col.label }}</span>\r\n\r\n @if (col.isSortable) {\r\n @if (col.key === sortState().column) {\r\n <i\r\n class=\"fa-solid ms-1\"\r\n [class.fa-sort-up]=\"sortState().direction === 'asc'\"\r\n [class.fa-sort-down]=\"sortState().direction === 'desc'\"\r\n >\r\n </i>\r\n } @else {\r\n <i class=\"fa-solid fa-sort text-muted ms-1\" style=\"opacity: 0.5\"></i>\r\n }\r\n }\r\n </div>\r\n </th>\r\n }\r\n @if (actions().length > 0) {\r\n <th class=\"bg-dark text-center text-white\">Acciones</th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <tbody>\r\n @for (row of paginatedData(); track row.id || $index) {\r\n <tr>\r\n @for (col of columns(); track col.key) {\r\n <td class=\"text-nowrap\">\r\n @if (col.templateRef) {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n col.templateRef;\r\n context: { $implicit: row, column: col.key }\r\n \"\r\n ></ng-container>\r\n } @else {\r\n <!-- {{ formatCellValue(row, col) }} -->\r\n @let config = getConfig(col.key.toString());\r\n @switch (config?.dataType) {\r\n @case ('date') {\r\n {{ $any(row)[col.key] | safeDate }}\r\n }\r\n @case ('currency') {\r\n {{ $any(row)[col.key] | safeCurrency }}\r\n }\r\n @case ('number') {\r\n {{ $any(row)[col.key] | safeNumber }}\r\n }\r\n @default {\r\n {{ $any(row)[col.key] }}\r\n }\r\n }\r\n }\r\n </td>\r\n }\r\n @if (actions().length > 0) {\r\n <td class=\"text-center\">\r\n @for (action of actions(); track action.label) {\r\n @if (!action.isVisible || action.isVisible(row)) {\r\n <button\r\n [class]=\"'btn btn-sm mx-1 ' + action.styleClass\"\r\n (click)=\"action.callback(row)\"\r\n >\r\n <i [class]=\"action.icon\"></i>\r\n </button>\r\n }\r\n }\r\n </td>\r\n }\r\n </tr>\r\n } @empty {\r\n <tr>\r\n <td [attr.colspan]=\"columns().length\" class=\"text-center\">\r\n No hay datos disponibles para mostrar.\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n <div class=\"d-flex justify-content-between align-items-center mt-3\">\r\n <div class=\"d-flex align-items-center\">\r\n <label for=\"pageSizeSelect\" class=\"me-2 text-nowrap\">Artículos por página: </label>\r\n <select\r\n id=\"pageSizeSelect\"\r\n class=\"form-select form-select-sm w-auto\"\r\n (change)=\"onPageSizeChange($event)\"\r\n >\r\n <option value=\"10\" [selected]=\"pageSize() === 10\">10</option>\r\n <option value=\"25\" [selected]=\"pageSize() === 25\">25</option>\r\n <option value=\"50\" [selected]=\"pageSize() === 50\">50</option>\r\n <option value=\"100\" [selected]=\"pageSize() === 100\">100</option>\r\n </select>\r\n </div>\r\n\r\n <nav aria-label=\"Paginación de tabla\">\r\n <ul class=\"pagination pagination-md mb-0\">\r\n <li class=\"page-item\" [class.disabled]=\"currentPage() === 1\">\r\n <button type=\"button\" class=\"page-link\" (click)=\"goToPage(currentPage() - 1)\"><<</button>\r\n </li>\r\n\r\n @for (pageNumber of pagesToShow(); track pageNumber) {\r\n <li class=\"page-item\" [class.active]=\"currentPage() === pageNumber\">\r\n <button type=\"button\" class=\"page-link\" (click)=\"goToPage(pageNumber)\">\r\n {{ pageNumber }}\r\n </button>\r\n </li>\r\n }\r\n\r\n <li class=\"page-item\" [class.disabled]=\"currentPage() === totalPages()\">\r\n <button type=\"button\" class=\"page-link\" (click)=\"goToPage(currentPage() + 1)\">>></button>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</div>\r\n","/*\r\n * Public API Surface of data-table\r\n */\r\n\r\nexport * from './lib/data-table';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ddiazr-data-table.mjs","sources":["../../../projects/data-table/src/lib/pipes/safe-date.pipe.ts","../../../projects/data-table/src/lib/pipes/safe-currency.pipe.ts","../../../projects/data-table/src/lib/pipes/safe-number.pipe.ts","../../../projects/data-table/src/lib/data-table.ts","../../../projects/data-table/src/lib/data-table.html","../../../projects/data-table/src/ddiazr-data-table.ts"],"sourcesContent":["import { Pipe, PipeTransform } from \"@angular/core\";\r\n\r\n@Pipe({\r\n name: \"safeDate\",\r\n standalone: true,\r\n pure: true, // ✅ Muy importante para performance\r\n})\r\nexport class SafeDatePipe implements PipeTransform {\r\n transform(value: any): string {\r\n if (!value) return \"\";\r\n const date = new Date(value);\r\n if (isNaN(date.getTime())) return value;\r\n\r\n const day = String(date.getDate()).padStart(2, \"0\");\r\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\r\n const year = date.getFullYear();\r\n\r\n return `${day}/${month}/${year}`;\r\n }\r\n}\r\n","import { Pipe, PipeTransform } from \"@angular/core\";\r\n\r\n@Pipe({\r\n name: 'safeCurrency',\r\n standalone: true,\r\n pure: true\r\n})\r\nexport class SafeCurrencyPipe implements PipeTransform {\r\n transform(value: any): string {\r\n if (value == null || value === '') return '';\r\n const num = Number(value);\r\n if (isNaN(num)) return value;\r\n \r\n return 'Q' + num.toFixed(2).replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\r\n }\r\n}","import { Pipe, PipeTransform } from \"@angular/core\";\r\n\r\n@Pipe({\r\n name: \"safeNumber\",\r\n standalone: true,\r\n pure: true,\r\n})\r\nexport class SafeNumberPipe implements PipeTransform {\r\n transform(value: any): string {\r\n if (value == null || value === \"\") return \"\";\r\n const num = Number(value);\r\n if (isNaN(num)) return value;\r\n\r\n return num.toFixed(2).replace(/\\B(?=(\\d{3})+(?!\\d))/g, \",\");\r\n }\r\n}\r\n","import { CommonModule } from '@angular/common';\r\nimport { Component, computed, input, output, signal, WritableSignal } from '@angular/core';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { SortDirection, TableColumn, SortState, TableAction, Position } from './interfaces/table.interface';\r\nimport { SafeDatePipe } from './pipes/safe-date.pipe';\r\nimport { SafeCurrencyPipe } from './pipes/safe-currency.pipe';\r\nimport { SafeNumberPipe } from './pipes/safe-number.pipe';\r\n@Component({\r\n selector: 'dtbl-data-table',\r\n imports: [CommonModule, FormsModule, SafeDatePipe, SafeCurrencyPipe, SafeNumberPipe],\r\n templateUrl: './data-table.html',\r\n styles: ``,\r\n})\r\nexport class DataTable<T extends { id?: any }> {\r\n // ------------------------------------\r\n // I. INPUT SIGNALS\r\n // ------------------------------------\r\n public data = input.required<T[]>();\r\n public columns = input.required<TableColumn<T>[]>();\r\n public actions = input<TableAction<T>[]>([]);\r\n public filterPlaceholder = input<string>('Buscar...');\r\n public showExportButtons = input<boolean>(false);\r\n public positionActions = input<Position>('end');\r\n\r\n // ------------------------------------\r\n // II. OUTPUTS (Usando la función output())\r\n // ------------------------------------\r\n public actionClicked = output<{ action: string; rowData: T }>();\r\n public exportRequested = output<'pdf' | 'excel' | 'print'>();\r\n\r\n // ------------------------------------\r\n // III. ESTADO INTERNO (Signals para Filtrado)\r\n // ------------------------------------\r\n\r\n public filterTerm: WritableSignal<string> = signal('');\r\n public sortState: WritableSignal<SortState<T>> = signal({\r\n column: null,\r\n direction: null,\r\n });\r\n\r\n public currentPage: WritableSignal<number> = signal(1); // Página actual, inicia en 1\r\n public pageSize: WritableSignal<number> = signal(10); // Elementos por página\r\n\r\n // 4. Datos filtrados (Computed Signal - LÓGICA DE BÚSQUEDA)\r\n public filteredData = computed(() => {\r\n const term = this.filterTerm().toLowerCase();\r\n const currentData = this.data();\r\n\r\n if (!term) return currentData;\r\n\r\n return currentData.filter((item) =>\r\n Object.values(item as object).some((value) => String(value).toLowerCase().includes(term)),\r\n );\r\n });\r\n\r\n public sortedAndFilteredData = computed(() => {\r\n const data = [...this.filteredData()]; // Copia para ordenar\r\n const state = this.sortState();\r\n\r\n if (!state.column || !state.direction) {\r\n return data; // Sin ordenamiento\r\n }\r\n\r\n const directionMultiplier = state.direction === 'asc' ? 1 : -1;\r\n const columnKey = state.column as keyof T;\r\n\r\n return data.sort((a, b) => {\r\n // Usamos localeCompare para ordenar strings correctamente, si no, comparación simple\r\n const aValue = a[columnKey];\r\n const bValue = b[columnKey];\r\n\r\n if (typeof aValue === 'string' && typeof bValue === 'string') {\r\n return aValue.localeCompare(bValue) * directionMultiplier;\r\n }\r\n\r\n if (aValue < bValue) {\r\n return -1 * directionMultiplier;\r\n }\r\n if (aValue > bValue) {\r\n return 1 * directionMultiplier;\r\n }\r\n return 0;\r\n });\r\n });\r\n\r\n public paginatedData = computed(() => {\r\n const data = this.sortedAndFilteredData();\r\n const size = this.pageSize();\r\n const page = this.currentPage();\r\n\r\n const start = (page - 1) * size;\r\n const end = start + size;\r\n\r\n // Retorna solo el slice (rebanada) de datos de la página actual\r\n return data.slice(start, end);\r\n });\r\n\r\n public totalPages = computed(() => {\r\n const totalItems = this.sortedAndFilteredData().length;\r\n const size = this.pageSize();\r\n return Math.ceil(totalItems / size);\r\n });\r\n\r\n public pagesToShow = computed<number[]>(() => {\r\n const total = this.totalPages();\r\n const current = this.currentPage();\r\n const maxPagesToShow = 5; // Máximo de botones numéricos a mostrar\r\n const pages: number[] = [];\r\n\r\n // Lógica simple para centrar los botones en la página actual\r\n let start = Math.max(1, current - Math.floor(maxPagesToShow / 2));\r\n let end = Math.min(total, start + maxPagesToShow - 1);\r\n\r\n // Ajuste si la tabla es pequeña\r\n if (end - start + 1 < maxPagesToShow) {\r\n start = Math.max(1, end - maxPagesToShow + 1);\r\n }\r\n\r\n for (let i = start; i <= end; i++) {\r\n pages.push(i);\r\n }\r\n return pages;\r\n });\r\n\r\n // ------------------------------------\r\n // IV. FUNCIONES\r\n // ------------------------------------\r\n onSort(columnKey: keyof T | 'actions' | 'select'): void {\r\n // Solo permitir ordenar si no es una columna de acción/selección\r\n if (columnKey === 'actions' || columnKey === 'select') return;\r\n\r\n this.sortState.update((current) => {\r\n let newDirection: SortDirection = 'asc';\r\n\r\n if (current.column === columnKey) {\r\n // Mismo column, se alterna la dirección\r\n newDirection = current.direction === 'asc' ? 'desc' : 'asc';\r\n }\r\n\r\n return {\r\n column: columnKey as keyof T,\r\n direction: newDirection,\r\n };\r\n });\r\n }\r\n\r\n /**\r\n * FUNCIÓN DE BÚSQUEDA\r\n * Actualiza el WritableSignal interno.\r\n */\r\n onSearchChange(term: string): void {\r\n this.filterTerm.set(term);\r\n }\r\n\r\n /**\r\n * FUNCIÓN DE ACCIONES\r\n * Emite el evento usando .emit() del Output Signal.\r\n */\r\n onActionClick(action: string, rowData: T): void {\r\n this.actionClicked.emit({ action, rowData });\r\n }\r\n\r\n /**\r\n * FUNCIÓN DE EXPORTACIÓN\r\n * Emite el evento de salida, delegando la lógica al padre.\r\n */\r\n exportData(format: 'pdf' | 'excel' | 'print'): void {\r\n this.exportRequested.emit(format);\r\n }\r\n\r\n getConfig(key: string): TableColumn<T> | undefined {\r\n return this.columns().find((c) => c.key === key);\r\n }\r\n\r\n goToPage(page: number): void {\r\n const total = this.totalPages();\r\n if (page >= 1 && page <= total) {\r\n this.currentPage.set(page);\r\n }\r\n }\r\n\r\n onPageSizeChange(event: Event): void {\r\n const target = event.target as HTMLSelectElement;\r\n const newSize = Number(target.value);\r\n\r\n this.pageSize.set(newSize);\r\n // Reiniciar a la página 1 después de cambiar el tamaño para evitar errores de índice\r\n this.currentPage.set(1);\r\n }\r\n}\r\n","<div class=\"container-fluid pt-3\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <input\r\n type=\"text\"\r\n class=\"form-control w-25\"\r\n [placeholder]=\"filterPlaceholder()\"\r\n [ngModel]=\"filterTerm()\"\r\n (ngModelChange)=\"onSearchChange($event)\"\r\n />\r\n\r\n @if (showExportButtons()) {\r\n <div class=\"export-buttons btn-group\" role=\"group\">\r\n <button class=\"btn btn-outline-success\" (click)=\"exportData('excel')\">\r\n <i class=\"fa fa-file-excel\"></i> Exportar a Excel\r\n </button>\r\n <button class=\"btn btn-outline-danger\" (click)=\"exportData('pdf')\">\r\n <i class=\"fa fa-file-pdf\"></i> Exportar a PDF\r\n </button>\r\n <button class=\"btn btn-outline-secondary\" (click)=\"exportData('print')\">\r\n <i class=\"fa fa-print\"></i> Imprimir\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"table-responsive\">\r\n <table class=\"table table-hover table-bordered caption-top\">\r\n <caption>\r\n Mostrando\r\n {{\r\n paginatedData().length\r\n }}\r\n de\r\n {{\r\n sortedAndFilteredData().length\r\n }}\r\n resultados (Total:\r\n {{\r\n data().length\r\n }}).\r\n </caption>\r\n\r\n <thead>\r\n <tr>\r\n @if (actions().length > 0 && positionActions() === 'start') {\r\n <th class=\"bg-dark text-center text-white\">Acciones</th>\r\n }\r\n @for (col of columns(); track col.key) {\r\n <th\r\n [class.sortable]=\"col.isSortable\"\r\n (click)=\"col.isSortable && onSort(col.key)\"\r\n scope=\"col\"\r\n class=\"text-nowrap\"\r\n >\r\n <div class=\"d-flex align-items-center justify-content-between\">\r\n <span class=\"fw-bold\">{{ col.label }}</span>\r\n\r\n @if (col.isSortable) {\r\n @if (col.key === sortState().column) {\r\n <i\r\n class=\"fa fa-solid ms-1\"\r\n [class.fa-sort-up]=\"sortState().direction === 'asc'\"\r\n [class.fa-sort-down]=\"sortState().direction === 'desc'\"\r\n >\r\n </i>\r\n } @else {\r\n <i class=\"fa fa-solid fa-sort text-muted ms-1\" style=\"opacity: 0.5\"></i>\r\n }\r\n }\r\n </div>\r\n </th>\r\n }\r\n @if (actions().length > 0 && positionActions() === 'end') {\r\n <th class=\"bg-dark text-center text-white\">Acciones</th>\r\n }\r\n\r\n </tr>\r\n </thead>\r\n\r\n <tbody>\r\n @for (row of paginatedData(); track row.id || $index) {\r\n <tr>\r\n @if (actions().length > 0 && positionActions() === 'start') {\r\n <td class=\"text-center\">\r\n @for (action of actions(); track action.label) {\r\n @if (!action.isVisible || action.isVisible(row)) {\r\n <button\r\n [class]=\"'btn btn-sm mx-1 ' + action.styleClass\"\r\n (click)=\"action.callback(row)\"\r\n >\r\n <i [class]=\"action.icon\"></i>\r\n </button>\r\n }\r\n }\r\n </td>\r\n }\r\n @for (col of columns(); track col.key) {\r\n <td class=\"text-nowrap\">\r\n @if (col.templateRef) {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n col.templateRef;\r\n context: { $implicit: row, column: col.key }\r\n \"\r\n ></ng-container>\r\n } @else {\r\n <!-- {{ formatCellValue(row, col) }} -->\r\n @let config = getConfig(col.key.toString());\r\n @switch (config?.dataType) {\r\n @case ('date') {\r\n {{ $any(row)[col.key] | safeDate }}\r\n }\r\n @case ('currency') {\r\n {{ $any(row)[col.key] | safeCurrency }}\r\n }\r\n @case ('number') {\r\n {{ $any(row)[col.key] | safeNumber }}\r\n }\r\n @default {\r\n {{ $any(row)[col.key] }}\r\n }\r\n }\r\n }\r\n </td>\r\n }\r\n @if (actions().length > 0 && positionActions() === 'end') {\r\n <td class=\"text-center\">\r\n @for (action of actions(); track action.label) {\r\n @if (!action.isVisible || action.isVisible(row)) {\r\n <button\r\n [class]=\"'btn btn-sm mx-1 ' + action.styleClass\"\r\n (click)=\"action.callback(row)\"\r\n >\r\n <i [class]=\"action.icon\"></i>\r\n </button>\r\n }\r\n }\r\n </td>\r\n }\r\n </tr>\r\n } @empty {\r\n <tr>\r\n <td [attr.colspan]=\"columns().length\" class=\"text-center\">\r\n No hay datos disponibles para mostrar.\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n <div class=\"d-flex justify-content-between align-items-center mt-3\">\r\n <div class=\"d-flex align-items-center\">\r\n <label for=\"pageSizeSelect\" class=\"me-2 text-nowrap\">Artículos por página: </label>\r\n <select\r\n id=\"pageSizeSelect\"\r\n class=\"form-select form-select-sm w-auto\"\r\n (change)=\"onPageSizeChange($event)\"\r\n >\r\n <option value=\"10\" [selected]=\"pageSize() === 10\">10</option>\r\n <option value=\"25\" [selected]=\"pageSize() === 25\">25</option>\r\n <option value=\"50\" [selected]=\"pageSize() === 50\">50</option>\r\n <option value=\"100\" [selected]=\"pageSize() === 100\">100</option>\r\n </select>\r\n </div>\r\n\r\n <nav aria-label=\"Paginación de tabla\">\r\n <ul class=\"pagination pagination-md mb-0\">\r\n <li class=\"page-item\" [class.disabled]=\"currentPage() === 1\">\r\n <button type=\"button\" class=\"page-link\" (click)=\"goToPage(currentPage() - 1)\"><<</button>\r\n </li>\r\n\r\n @for (pageNumber of pagesToShow(); track pageNumber) {\r\n <li class=\"page-item\" [class.active]=\"currentPage() === pageNumber\">\r\n <button type=\"button\" class=\"page-link\" (click)=\"goToPage(pageNumber)\">\r\n {{ pageNumber }}\r\n </button>\r\n </li>\r\n }\r\n\r\n <li class=\"page-item\" [class.disabled]=\"currentPage() === totalPages()\">\r\n <button type=\"button\" class=\"page-link\" (click)=\"goToPage(currentPage() + 1)\">>></button>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ddiazr/data-table",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Tabla generica sirve para acciones, export PDF,EXCEl",
5
5
  "author": {
6
6
  "name": "Dany Díaz",
@@ -3,6 +3,7 @@ import { WritableSignal } from '@angular/core';
3
3
 
4
4
  type DataType = 'string' | 'number' | 'currency' | 'date' | 'boolean';
5
5
  type SortDirection = 'asc' | 'desc' | null;
6
+ type Position = 'end' | 'start';
6
7
  /**
7
8
  * Define la configuración de una columna en la tabla genérica.
8
9
  * @template T El tipo de dato de la fila (ej: User, Product).
@@ -41,6 +42,7 @@ declare class DataTable<T extends {
41
42
  actions: _angular_core.InputSignal<TableAction<T>[]>;
42
43
  filterPlaceholder: _angular_core.InputSignal<string>;
43
44
  showExportButtons: _angular_core.InputSignal<boolean>;
45
+ positionActions: _angular_core.InputSignal<Position>;
44
46
  actionClicked: _angular_core.OutputEmitterRef<{
45
47
  action: string;
46
48
  rowData: T;
@@ -75,7 +77,8 @@ declare class DataTable<T extends {
75
77
  goToPage(page: number): void;
76
78
  onPageSizeChange(event: Event): void;
77
79
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DataTable<any>, never>;
78
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DataTable<any>, "dtbl-data-table", never, { "data": { "alias": "data"; "required": true; "isSignal": true; }; "columns": { "alias": "columns"; "required": true; "isSignal": true; }; "actions": { "alias": "actions"; "required": false; "isSignal": true; }; "filterPlaceholder": { "alias": "filterPlaceholder"; "required": false; "isSignal": true; }; "showExportButtons": { "alias": "showExportButtons"; "required": false; "isSignal": true; }; }, { "actionClicked": "actionClicked"; "exportRequested": "exportRequested"; }, never, never, true, never>;
80
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DataTable<any>, "dtbl-data-table", never, { "data": { "alias": "data"; "required": true; "isSignal": true; }; "columns": { "alias": "columns"; "required": true; "isSignal": true; }; "actions": { "alias": "actions"; "required": false; "isSignal": true; }; "filterPlaceholder": { "alias": "filterPlaceholder"; "required": false; "isSignal": true; }; "showExportButtons": { "alias": "showExportButtons"; "required": false; "isSignal": true; }; "positionActions": { "alias": "positionActions"; "required": false; "isSignal": true; }; }, { "actionClicked": "actionClicked"; "exportRequested": "exportRequested"; }, never, never, true, never>;
79
81
  }
80
82
 
81
83
  export { DataTable };
84
+ export type { Position, SortDirection, SortState, TableAction, TableColumn };