@c80/ui 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +59 -49
  2. package/esm2022/lib/action-list/action-list.component.js +1 -1
  3. package/esm2022/lib/action-list/action-list.component.js.map +1 -1
  4. package/esm2022/lib/card-level/card-level.component.js +4 -15
  5. package/esm2022/lib/card-level/card-level.component.js.map +1 -1
  6. package/esm2022/lib/error-notification/error-notification.component.js +1 -1
  7. package/esm2022/lib/error-notification/error-notification.component.js.map +1 -1
  8. package/esm2022/lib/header/header.component.js +1 -1
  9. package/esm2022/lib/header/header.component.js.map +1 -1
  10. package/esm2022/lib/icon/icon.component.js +1 -12
  11. package/esm2022/lib/icon/icon.component.js.map +1 -1
  12. package/esm2022/lib/icon/theme.service.js +3 -0
  13. package/esm2022/lib/icon/theme.service.js.map +1 -1
  14. package/esm2022/lib/info-list/info-list.component.js +1 -1
  15. package/esm2022/lib/info-list/info-list.component.js.map +1 -1
  16. package/esm2022/lib/info-message/info-message.component.js +5 -10
  17. package/esm2022/lib/info-message/info-message.component.js.map +1 -1
  18. package/esm2022/lib/input-field/input-field.component.js +17 -15
  19. package/esm2022/lib/input-field/input-field.component.js.map +1 -1
  20. package/esm2022/lib/input-search/c80-input-search.component.js +1 -1
  21. package/esm2022/lib/input-search/c80-input-search.component.js.map +1 -1
  22. package/esm2022/lib/legal-disclaimer/legal-disclaimer.component.js +1 -1
  23. package/esm2022/lib/legal-disclaimer/legal-disclaimer.component.js.map +1 -1
  24. package/esm2022/lib/modal/modal.component.js +3 -5
  25. package/esm2022/lib/modal/modal.component.js.map +1 -1
  26. package/esm2022/lib/modal/modal.service.js +6 -0
  27. package/esm2022/lib/modal/modal.service.js.map +1 -1
  28. package/esm2022/lib/navigation-card/navigation-card.component.js +1 -1
  29. package/esm2022/lib/navigation-card/navigation-card.component.js.map +1 -1
  30. package/esm2022/lib/profile-stats/profile-stats.component.js +1 -1
  31. package/esm2022/lib/profile-stats/profile-stats.component.js.map +1 -1
  32. package/esm2022/lib/rating-display/rating-display.component.js +1 -1
  33. package/esm2022/lib/rating-display/rating-display.component.js.map +1 -1
  34. package/esm2022/lib/rating-stars/rating-stars.component.js +3 -4
  35. package/esm2022/lib/rating-stars/rating-stars.component.js.map +1 -1
  36. package/esm2022/lib/select/select.component.js +1 -12
  37. package/esm2022/lib/select/select.component.js.map +1 -1
  38. package/esm2022/lib/snackbar/snackbar.component.js +1 -3
  39. package/esm2022/lib/snackbar/snackbar.component.js.map +1 -1
  40. package/esm2022/lib/stat-card/stat-card.component.js +1 -2
  41. package/esm2022/lib/stat-card/stat-card.component.js.map +1 -1
  42. package/esm2022/lib/tab/c80-tab.component.js +4 -7
  43. package/esm2022/lib/tab/c80-tab.component.js.map +1 -1
  44. package/esm2022/lib/tab/directives/c80-tab-item.directive.js +0 -1
  45. package/esm2022/lib/tab/directives/c80-tab-item.directive.js.map +1 -1
  46. package/esm2022/lib/tab/directives/c80-tab-label.directive.js +0 -1
  47. package/esm2022/lib/tab/directives/c80-tab-label.directive.js.map +1 -1
  48. package/esm2022/lib/tab/index.js.map +1 -1
  49. package/esm2022/lib/table/table.component.js +3 -29
  50. package/esm2022/lib/table/table.component.js.map +1 -1
  51. package/lib/card-level/card-level.component.d.ts +1 -1
  52. package/lib/info-message/info-message.component.d.ts +2 -5
  53. package/lib/input-field/input-field.component.d.ts +14 -10
  54. package/lib/modal/modal.component.d.ts +0 -1
  55. package/lib/rating-stars/rating-stars.component.d.ts +0 -1
  56. package/lib/tab/c80-tab.component.d.ts +1 -2
  57. package/lib/tab/index.d.ts +0 -1
  58. package/package.json +1 -1
  59. package/esm2022/lib/tab/c80-tab.types.js +0 -1
  60. package/esm2022/lib/tab/c80-tab.types.js.map +0 -1
  61. package/lib/tab/c80-tab.types.d.ts +0 -4
@@ -1,5 +1,5 @@
1
1
  import { Component, ChangeDetectionStrategy, input, signal, computed, output, inject, effect, } from '@angular/core';
2
- import { IconComponent } from '../icon';
2
+ import { IconComponent, THEME_DARK_COLOR } from '../icon';
3
3
  import { TableColumnVisibilityService } from './table-column-visibility.service';
4
4
  import { TableDataUtilsService } from './table-data-utils.service';
5
5
  import { TableDataConverterService } from './table-data-converter.service';
@@ -133,7 +133,6 @@ import * as i0 from "@angular/core";
133
133
  * - customActions con custom → Botón personalizado emite evento
134
134
  */ export class TableComponent {
135
135
  // Servicios inyectados
136
- /* v8 ignore next 7 */
137
136
  modalService = inject(ModalService);
138
137
  visibilityService = inject(TableColumnVisibilityService);
139
138
  dataUtils = inject(TableDataUtilsService);
@@ -142,58 +141,40 @@ import * as i0 from "@angular/core";
142
141
  crudService = inject(TableCrudStateService);
143
142
  paginationService = inject(TablePaginationService);
144
143
  // Inputs
145
- /* v8 ignore next */
146
144
  data$ = input.required(...(ngDevMode ? [{ debugName: "data$" }] : /* istanbul ignore next */ []));
147
- /* v8 ignore next */
148
145
  columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
149
- /* v8 ignore next */
150
146
  inputValues$ = input(...(ngDevMode ? [undefined, { debugName: "inputValues$" }] : /* istanbul ignore next */ [])); // Observable para actualizar valores de inputs dinámicamente en creación/edición
151
- /* v8 ignore next */
152
147
  customActions = input([], ...(ngDevMode ? [{ debugName: "customActions" }] : /* istanbul ignore next */ [])); // Acciones personalizadas dinámicas
153
- /* v8 ignore next */
154
148
  size = input(0, ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ [])); // Tamaño de la tabla (0 = sin límite, > 0 aplica max-height)
155
- /* v8 ignore next */
156
149
  multiple = input(true, ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ [])); // Permite selección múltiple por defecto
157
- /* v8 ignore next */
158
150
  rowId = input('id', ...(ngDevMode ? [{ debugName: "rowId" }] : /* istanbul ignore next */ [])); // Accessor de la PK de cada fila (default 'id'); usar si la entidad no usa 'id'
159
- /* v8 ignore next */
160
151
  searchable = input(false, { ...(ngDevMode ? { debugName: "searchable" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); // Si es true, muestra barra de búsqueda
161
- /* v8 ignore next */
162
152
  allowSelection = input(false, { ...(ngDevMode ? { debugName: "allowSelection" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); // Si es true, permite selección de filas
163
- /* v8 ignore next */
164
153
  noConfirm = input(false, { ...(ngDevMode ? { debugName: "noConfirm" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); // Si es true, no muestra confirmaciones modales
165
- /* v8 ignore next */
166
154
  paginated = input(false, { ...(ngDevMode ? { debugName: "paginated" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); // Si es true, habilita paginación con limit/offset
167
- /* v8 ignore next */
168
155
  paginationConfig = input({ pageSize: 10 }, ...(ngDevMode ? [{ debugName: "paginationConfig" }] : /* istanbul ignore next */ [])); // Configuración de paginación (tamaño de página, total items)
169
156
  // Outputs - Acciones unificadas (Angular 18+ output API)
170
- /* v8 ignore next */
171
157
  actionClick = output(); // Output unificado para TODAS las acciones (CRUD + custom)
172
158
  // Outputs - Utilidades
173
- /* v8 ignore next 4 */
174
159
  searchTerm = output();
175
160
  errorEvent = output();
176
161
  selectable = output();
177
162
  paginationChange = output(); // Output para cambios de paginación (page, limit, offset)
178
163
  // Estado principal
179
- /* v8 ignore next 2 */
180
164
  data = signal([], ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
181
165
  searchValue = signal('', ...(ngDevMode ? [{ debugName: "searchValue" }] : /* istanbul ignore next */ []));
182
166
  // Estado de selección (delegado a servicio)
183
- /* v8 ignore next 4 */
184
167
  selectionState = this.selectionService.createSelectionState((item) => item[this.rowId()]);
185
168
  selectedItems = this.selectionState.selectedItems;
186
169
  selectAllChecked = this.selectionState.selectAllChecked;
187
170
  selectAllIndeterminate = this.selectionState.selectAllIndeterminate;
188
171
  // Estado CRUD (delegado a servicio)
189
- /* v8 ignore next 5 */
190
172
  crudState = this.crudService.createCrudState();
191
173
  creating = this.crudState.creating;
192
174
  newRow = this.crudState.newRow;
193
175
  editing = this.crudState.editing;
194
176
  editRow = this.crudState.editRow;
195
177
  // Estado de paginación (delegado a servicio)
196
- /* v8 ignore next 7 */
197
178
  paginationState = this.paginationService.createPaginationState(this.paginationConfig().pageSize ?? 10);
198
179
  currentPage = this.paginationState.currentPage;
199
180
  pageSize = this.paginationState.pageSize;
@@ -201,16 +182,13 @@ import * as i0 from "@angular/core";
201
182
  hasNextPage = this.paginationState.hasNextPage;
202
183
  hasPrevPage = this.paginationState.hasPrevPage;
203
184
  // Keys visibles computed automáticamente
204
- /* v8 ignore next 7 */
205
185
  keys = computed(() => this.visibilityService.updateVisibleKeys(this.columns(), { data: this.data(), creating: this.creating(), editing: this.editing() }), ...(ngDevMode ? [{ debugName: "keys" }] : /* istanbul ignore next */ []));
206
186
  // Computed - Detecta acciones CRUD y custom
207
- /* v8 ignore next 5 */
208
187
  hasAnyActions = computed(() => this.customActions().length > 0, ...(ngDevMode ? [{ debugName: "hasAnyActions" }] : /* istanbul ignore next */ []));
209
188
  hasCrudCreate = computed(() => this.customActions().some(a => a.name === 'create'), ...(ngDevMode ? [{ debugName: "hasCrudCreate" }] : /* istanbul ignore next */ []));
210
189
  hasCrudUpdate = computed(() => this.customActions().some(a => a.name === 'update'), ...(ngDevMode ? [{ debugName: "hasCrudUpdate" }] : /* istanbul ignore next */ []));
211
190
  hasCrudDelete = computed(() => this.customActions().some(a => a.name === 'delete'), ...(ngDevMode ? [{ debugName: "hasCrudDelete" }] : /* istanbul ignore next */ []));
212
191
  hasCrudCancel = computed(() => this.customActions().some(a => a.name === 'cancel'), ...(ngDevMode ? [{ debugName: "hasCrudCancel" }] : /* istanbul ignore next */ []));
213
- /* v8 ignore next 5 */
214
192
  shouldShowCreateButton = computed(() => {
215
193
  const createAction = this.customActions().find(a => a.name === 'create');
216
194
  if (!createAction)
@@ -218,14 +196,11 @@ import * as i0 from "@angular/core";
218
196
  return !createAction.condition || createAction.condition({}, this.data());
219
197
  }, ...(ngDevMode ? [{ debugName: "shouldShowCreateButton" }] : /* istanbul ignore next */ []));
220
198
  // Table max height computed
221
- /* v8 ignore next 3 */
222
199
  tableMaxHeight = computed(() => this.dataUtils.getTableMaxHeight(this.size()), ...(ngDevMode ? [{ debugName: "tableMaxHeight" }] : /* istanbul ignore next */ []));
223
- /* v8 ignore next 2 */
224
200
  dataSub;
225
201
  inputValuesSub;
226
202
  constructor() {
227
203
  // Sincronizar totalItems del paginationConfig con el estado de paginación
228
- /* v8 ignore next 4 */
229
204
  effect(() => {
230
205
  const config = this.paginationConfig();
231
206
  if (config.totalItems !== undefined && this.paginated()) {
@@ -236,7 +211,6 @@ import * as i0 from "@angular/core";
236
211
  // DESPUÉS de la construcción, así que el estado se inicializa con el default;
237
212
  // este effect reaplica el pageSize real del padre cuando cambia (sin resetear
238
213
  // la página por otros cambios del config como totalItems).
239
- /* v8 ignore next 8 */
240
214
  let lastPageSize;
241
215
  effect(() => {
242
216
  const size = this.paginationConfig().pageSize ?? 10;
@@ -554,13 +528,13 @@ import * as i0 from "@angular/core";
554
528
  return action.color;
555
529
  }
556
530
  // Para acciones sin color explícito, usar el color de dark mode
557
- return '#e9ecef';
531
+ return THEME_DARK_COLOR;
558
532
  }
559
533
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
560
534
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: TableComponent, isStandalone: true, selector: "c80-table", inputs: { data$: { classPropertyName: "data$", publicName: "data$", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, inputValues$: { classPropertyName: "inputValues$", publicName: "inputValues$", isSignal: true, isRequired: false, transformFunction: null }, customActions: { classPropertyName: "customActions", publicName: "customActions", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, rowId: { classPropertyName: "rowId", publicName: "rowId", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, allowSelection: { classPropertyName: "allowSelection", publicName: "allowSelection", isSignal: true, isRequired: false, transformFunction: null }, noConfirm: { classPropertyName: "noConfirm", publicName: "noConfirm", isSignal: true, isRequired: false, transformFunction: null }, paginated: { classPropertyName: "paginated", publicName: "paginated", isSignal: true, isRequired: false, transformFunction: null }, paginationConfig: { classPropertyName: "paginationConfig", publicName: "paginationConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionClick: "actionClick", searchTerm: "searchTerm", errorEvent: "errorEvent", selectable: "selectable", paginationChange: "paginationChange" }, ngImport: i0, template: "<div class=\"table-responsive\" [style.max-height]=\"tableMaxHeight()\" [style.overflow-y]=\"size() > 0 ? 'auto' : 'visible'\">\r\n <!-- Search Bar -->\r\n @if (searchable()) {\r\n <div class=\"search-container\">\r\n <div class=\"search-input-wrapper\">\r\n <div class=\"input-group\">\r\n <span class=\"input-group-text\">\r\n <c80-icon icon=\"search\" [size]=\".65\" [button]=\"false\" />\r\n </span>\r\n <input type=\"text\" class=\"form-control search-input\" placeholder=\"Buscar...\" [value]=\"searchValue()\" (input)=\"onSearchInput($event)\" aria-label=\"Buscar en la tabla\" />\r\n @if (searchValue()) {\r\n <button class=\"btn btn-outline-secondary btn-borrar\" type=\"button\" (click)=\"clearSearch()\" title=\"Limpiar b\u00FAsqueda\">\r\n <c80-icon icon=\"cancel\" [size]=\".6\" />\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <table class=\"table table-bordered table-hover align-middle\">\r\n <thead class=\"thead table-light sticky-header\">\r\n <tr>\r\n @if (allowSelection() && data().length !== 0) {\r\n <th class=\"text-center selection-column\">\r\n @if (multiple()) {\r\n <input type=\"checkbox\" [checked]=\"selectAllChecked()\" [indeterminate]=\"selectAllIndeterminate()\" (change)=\"toggleSelectAll()\" aria-label=\"Seleccionar todo\" />\r\n }\r\n </th>\r\n }\r\n @for (col of columns(); track col) {\r\n @if (isColumnVisibleInHeader(col)) {\r\n @if (col.type === 'boolean') {\r\n <th class=\"text-center boolean-column\">{{ col.label }}</th>\r\n }\r\n @else if (col.type === 'number' || col.type === 'integer') {\r\n <th class=\"text-center number-column\">{{ col.label }}</th>\r\n }\r\n @else if (col.type === 'date') {\r\n <th class=\"text-center date-column\">{{ col.label }}</th>\r\n }\r\n @else {\r\n <th>{{ col.label }}</th>\r\n }\r\n }\r\n }\r\n @if (hasAnyActions()) {\r\n <th class=\"table-actions-header\">\r\n <div class=\"actions-wrapper\">\r\n <span>Actions</span>\r\n @if (shouldShowCreateButton()) {\r\n <c80-icon button icon=\"add\" [disabled]=\"creating()\" title=\"Agregar\" [size]=\".6\" (iconClick)=\"startCreate()\" />\r\n }\r\n </div>\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (row of data(); track trackById(i, row); let i = $index) {\r\n <tr>\r\n @if (allowSelection() && data().length !== 0) {\r\n <td class=\"text-center selection-column\">\r\n <input type=\"checkbox\" [checked]=\"isItemSelected(row)\" (change)=\"toggleItemSelection(row)\" [attr.aria-label]=\"'Seleccionar fila ' + (i + 1)\" />\r\n </td>\r\n }\r\n @for (col of columns(); track col) {\r\n @if (isColumnVisibleForRow(col, row)) {\r\n @if (col.type === 'boolean') {\r\n <td class=\"text-center boolean-column\">\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n <input type=\"checkbox\" [checked]=\"!!editRow()?.[col.accessor]\" (change)=\"onEditInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\r\n }\r\n @else {\r\n @if (getCellValue(row, col.accessor) === true) {\r\n <c80-icon icon=\"check\" [size]=\".7\" />\r\n <br />\r\n }\r\n @else if (getCellValue(row, col.accessor) === false) {\r\n <c80-icon icon=\"cancel\" [size]=\".7\" />\r\n <br />\r\n }\r\n }\r\n </td>\r\n }\r\n @else if (col.type === 'number' || col.type === 'integer') {\r\n <td class=\"text-center number-column\">\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\r\n (input)=\"onEditInput($event, col.accessor, col)\" />\r\n }\r\n @else {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\r\n col.accessor), col) }}</span>\r\n }\r\n </td>\r\n }\r\n @else if (col.type === 'date') {\r\n <td class=\"text-center date-column\">\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n <input class=\"form-control form-control-sm\" type=\"datetime-local\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onEditInput($event, col.accessor, col)\" />\r\n }\r\n @else {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\r\n col.accessor), col) }}</span>\r\n }\r\n </td>\r\n }\r\n @else {\r\n <td>\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n @if (col.type === 'enum') {\r\n <select class=\"form-control form-control-sm\" [value]=\"editRow()?.[col.accessor] ?? ''\" (change)=\"onEditInput($event, col.accessor, col)\">\r\n <option value=\"\">{{ col.label }}</option>\r\n @for (option of getEnumOptions(col); track option.value) {\r\n <option [value]=\"option.value\">{{ option.label }}</option>\r\n }\r\n </select>\r\n }\r\n @else {\r\n <input class=\"form-control form-control-sm\" [type]=\"col.type === 'password' ? 'password' : 'text'\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onEditInput($event, col.accessor, col)\" />\r\n }\r\n }\r\n @else {\r\n @if (col.type === 'password') {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">******</span>\r\n }\r\n @else if (col.type === 'enum') {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{\r\n getEnumDisplayValue(getCellValue(row, col.accessor), col)\r\n }}</span>\r\n }\r\n @else if (getCellValue(row, col.accessor) === true) {\r\n <c80-icon icon=\"check\" [size]=\".7\" />\r\n }\r\n @else if (getCellValue(row, col.accessor) === false) {\r\n <c80-icon icon=\"cancel\" [size]=\".7\" />\r\n }\r\n @else {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\r\n col.accessor), col) }}</span>\r\n }\r\n }\r\n </td>\r\n }\r\n }\r\n }\r\n @if (hasAnyActions()) {\r\n <td class=\"text-end actions-cell\">\r\n <div class=\"actions-container\" [class.centered-actions]=\"editing() === row['id']\">\r\n @if (editing() === row['id']) {\r\n <!-- Modo edici\u00F3n: mostrar guardar y cancelar -->\r\n @if (hasCrudUpdate()) {\r\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\" [size]=\".7\" />\r\n }\r\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\" [size]=\".7\" />\r\n }\r\n @else {\r\n @for (action of customActions(); track action.name) {\r\n @if (shouldShowAction(action, row, data())) {\r\n <c80-icon button [icon]=\"action.icon\" [customColor]=\"getActionColor(action)\" [color]=\"action.name === 'delete' ? 'warn' : 'primary'\" [title]=\"getActionTooltip(action)\" (iconClick)=\"onDynamicAction(action, row)\" [size]=\".7\" />\r\n }\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (creating() && hasCrudCreate()) {\r\n <tr>\r\n @if (allowSelection() && data().length !== 0) {\r\n <td class=\"text-center selection-column\">\r\n <!-- Empty cell for alignment -->\r\n </td>\r\n }\r\n @for (col of columns(); track col) {\r\n @if (isColumnVisible(col)) {\r\n @if (col.type === 'boolean') {\r\n <td class=\"text-center\">\r\n @if (!col.readOnly) {\r\n <input type=\"checkbox\" [checked]=\"!!newRow()?.[col.accessor]\" (change)=\"onInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\r\n }\r\n @else {\r\n <!-- ReadOnly boolean column in create mode shows empty -->\r\n <span class=\"text-muted\">-</span>\r\n }\r\n </td>\r\n } @else if (col.type === 'number' || col.type === 'integer') {\r\n <td class=\"text-center number-column\">\r\n @if (!col.readOnly) {\r\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\r\n (input)=\"onInput($event, col.accessor, col)\" />\r\n }\r\n @else {\r\n <!-- ReadOnly number column in create mode shows empty -->\r\n <span class=\"text-muted\">-</span>\r\n }\r\n </td>\r\n } @else {\r\n <td>\r\n @if (!col.readOnly) {\r\n @if (col.type === 'enum') {\r\n <select class=\"form-control form-control-sm\" [value]=\"newRow()?.[col.accessor] ?? ''\" (change)=\"onInput($event, col.accessor, col)\">\r\n <option value=\"\">{{ col.label }}</option>\r\n @for (option of getEnumOptions(col); track option.value) {\r\n <option [value]=\"option.value\">{{ option.label }}</option>\r\n }\r\n </select>\r\n }\r\n @else {\r\n <input class=\"form-control form-control-sm\" type=\"text\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onInput($event, col.accessor, col)\" />\r\n }\r\n }\r\n @else {\r\n <!-- ReadOnly column in create mode shows empty -->\r\n <span class=\"text-muted\">-</span>\r\n }\r\n </td>\r\n }\r\n }\r\n }\r\n <td class=\"text-end actions-cell\">\r\n <div class=\"actions-container centered-actions\">\r\n @if (hasCrudCreate()) {\r\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveCreate()\" [size]=\".7\" />\r\n }\r\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelCreate()\" [size]=\".7\" />\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n @if (data().length === 0 && !creating()) {\r\n <div class=\"text-center text-muted py-3 small\">\r\n No hay datos para mostrar.\r\n </div>\r\n }\r\n\r\n <!-- Pagination Controls -->\r\n @if (paginated() && data().length > 0) {\r\n <div class=\"pagination-container\">\r\n <div class=\"pagination-info\">\r\n P\u00E1gina {{ currentPage() }} de {{ totalPages() }}\r\n </div>\r\n <div class=\"pagination-controls\">\r\n <button type=\"button\" class=\"btn btn-sm\" [disabled]=\"!hasPrevPage()\" (click)=\"onPrevPage()\" title=\"P\u00E1gina anterior\">\r\n <c80-icon icon=\"arrowLeft\" [size]=\".6\" [button]=\"false\" />\r\n </button>\r\n <button type=\"button\" class=\"btn btn-sm\" [disabled]=\"!hasNextPage()\" (click)=\"onNextPage()\" title=\"P\u00E1gina siguiente\">\r\n <c80-icon icon=\"arrowRight\" [size]=\".6\" [button]=\"false\" />\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n\r\n<c80-modal />", styles: ["@charset \"UTF-8\";input[type=checkbox]{width:1.3rem!important;height:1.3rem!important;accent-color:var(--color-icon-danger);background:var(--color-bg-primary);margin:0 .25rem;vertical-align:middle;cursor:pointer}.table-responsive{width:100%;overflow-x:auto}.table-responsive .search-container{margin-bottom:-.06rem}.table-responsive .search-container .search-input-wrapper .input-group .btn-borrar{border-bottom-right-radius:0;border-color:var(--color-border-default);height:32px}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text{background-color:var(--color-bg-secondary);border-color:var(--color-border-default);border-bottom-left-radius:0;color:var(--color-text-secondary);width:56.1px;height:32px;padding:.25rem .5rem}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text c80-icon{display:flex;align-items:center;justify-content:center}.table-responsive .search-container .search-input-wrapper .input-group .search-input{border-color:var(--color-border-default);border-bottom-right-radius:0;font-size:.75rem;height:32px;padding:.25rem .5rem;outline:none!important;background-color:var(--color-bg-primary);color:var(--color-text-primary)}.table-responsive .search-container .search-input-wrapper .input-group .search-input:focus{outline:none!important}.table-responsive .search-container .search-input-wrapper .input-group .search-input::placeholder{color:var(--color-text-muted);font-style:italic}.table-responsive .table{min-width:0px;margin-bottom:0;background-color:var(--color-bg-primary);color:var(--color-text-primary);border-color:var(--color-border-default)}.table-responsive .table.table-bordered,.table-responsive .table.table-bordered th,.table-responsive .table.table-bordered td{border-color:var(--color-border-default)}.table-responsive .table.table-hover tbody tr:hover{background-color:var(--color-bg-hover)!important;color:var(--color-text-primary)}.table-responsive .table.table-hover tbody tr:hover td{background-color:var(--color-bg-hover)}.table-responsive .table .sticky-header{position:sticky;top:0;z-index:10;background-color:var(--color-bg-secondary)!important}.table-responsive .table .sticky-header .table-actions-header{display:table-cell;vertical-align:middle;padding:.2rem .6rem!important;background-color:var(--color-bg-secondary)!important}.table-responsive .table .sticky-header .actions-wrapper{display:flex;align-items:center;justify-content:center;gap:.5rem;height:100%}.table-responsive .table .sticky-header th{max-height:31px!important;vertical-align:middle!important;padding:.2rem .6rem!important;font-size:small!important;background-color:var(--color-bg-secondary)!important;border-bottom:2px solid var(--color-border-default);color:var(--color-text-primary)}.table-responsive .table tbody{background-color:var(--color-bg-primary)}.table-responsive .table tbody td{height:35px!important;min-height:35px!important;max-height:35px!important;vertical-align:middle!important;padding:.2rem .8rem!important;font-size:small;color:var(--color-text-primary);background-color:var(--color-bg-primary);border-color:var(--color-border-default)}.table-responsive .table tbody tr{height:35px!important;min-height:35px!important;max-height:35px!important;cursor:pointer;background-color:var(--color-bg-primary)}.table-responsive .table tbody tr:hover{background-color:var(--color-bg-hover)!important}.table-responsive .table tbody tr:hover td{background-color:var(--color-bg-hover)}.table-responsive .table tbody .text-muted{color:var(--color-text-muted)!important}.table-responsive .table tbody input,.table-responsive .table tbody select{border:1px solid var(--color-border-default);height:100%!important;font-size:smaller!important;background-color:var(--color-bg-primary);color:var(--color-text-primary)}.table-responsive .table tbody input:focus,.table-responsive .table tbody select:focus{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus)}.table-responsive .table tbody input::placeholder,.table-responsive .table tbody select::placeholder{color:var(--color-text-muted)}.table-responsive .table tbody input[type=text],.table-responsive .table tbody input:not([type]){width:100%!important}.table-responsive .table tbody input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table tbody select{width:100%!important;padding:.25rem .5rem}.table-responsive .table thead th.boolean-column,.table-responsive .table tbody td.boolean-column,.table-responsive .table thead th.selection-column,.table-responsive .table tbody td.selection-column,.table-responsive .table thead th.table-actions-header,.table-responsive .table tbody td.table-actions-header{width:1%;white-space:nowrap}.table-responsive .table thead th.number-column,.table-responsive .table tbody td.number-column{width:1%;white-space:nowrap;text-align:center}.table-responsive .table thead th.number-column input[type=number],.table-responsive .table tbody td.number-column input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table thead th.date-column,.table-responsive .table tbody td.date-column{width:1%;white-space:nowrap;text-align:center}.table-responsive .table thead th.date-column input[type=datetime-local],.table-responsive .table tbody td.date-column input[type=datetime-local]{min-width:200px!important;width:200px!important;text-align:center}.table-responsive .table .actions-cell{white-space:nowrap;padding:0!important}.table-responsive .table .actions-container{display:flex;flex-direction:row;justify-content:flex-end;align-items:center;width:100%;height:100%}.table-responsive .table .actions-container.centered-actions{justify-content:center}.table-responsive .text-center.text-muted{color:var(--color-text-muted)!important}.table-responsive .btn-outline-secondary{background-color:var(--color-bg-primary);color:var(--color-text-primary);border-color:var(--color-border-default)}.table-responsive .btn-outline-secondary:hover{background-color:var(--color-bg-hover);border-color:var(--color-border-medium)}.table-responsive .btn-outline-secondary:focus{box-shadow:var(--shadow-focus)}.table-responsive .pagination-container{display:flex;justify-content:space-between;align-items:center;padding:.2rem .5rem;background-color:var(--color-bg-secondary);border:1px solid var(--color-border-default);border-top:none;border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.table-responsive .pagination-container .pagination-info{font-size:.875rem;color:var(--color-text-secondary);font-weight:500}.table-responsive .pagination-container .pagination-controls{display:flex;gap:.5rem}.table-responsive .pagination-container .pagination-controls button{min-width:36px;height:32px;padding:.25rem .5rem;display:flex;align-items:center;justify-content:center;background-color:var(--color-bg-primary);color:var(--color-text-primary);border:none}.table-responsive .pagination-container .pagination-controls button:hover:not(:disabled){background-color:var(--color-bg-hover);border:none}.table-responsive .pagination-container .pagination-controls button:disabled{opacity:.5;cursor:auto;background-color:var(--color-bg-primary);border:none}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "c80-icon", inputs: ["icon", "color", "customColor", "disabled", "size", "button", "border", "type", "textLeft", "textRight", "dark"], outputs: ["iconClick"] }, { kind: "component", type: ModalComponent, selector: "c80-modal" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
561
535
  }
562
536
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TableComponent, decorators: [{
563
537
  type: Component,
564
- args: [{ selector: 'c80-table', standalone: true, imports: [IconComponent, ModalComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"table-responsive\" [style.max-height]=\"tableMaxHeight()\" [style.overflow-y]=\"size() > 0 ? 'auto' : 'visible'\">\r\n <!-- Search Bar -->\r\n @if (searchable()) {\r\n <div class=\"search-container\">\r\n <div class=\"search-input-wrapper\">\r\n <div class=\"input-group\">\r\n <span class=\"input-group-text\">\r\n <c80-icon icon=\"search\" [size]=\".65\" [button]=\"false\" />\r\n </span>\r\n <input type=\"text\" class=\"form-control search-input\" placeholder=\"Buscar...\" [value]=\"searchValue()\" (input)=\"onSearchInput($event)\" aria-label=\"Buscar en la tabla\" />\r\n @if (searchValue()) {\r\n <button class=\"btn btn-outline-secondary btn-borrar\" type=\"button\" (click)=\"clearSearch()\" title=\"Limpiar b\u00FAsqueda\">\r\n <c80-icon icon=\"cancel\" [size]=\".6\" />\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <table class=\"table table-bordered table-hover align-middle\">\r\n <thead class=\"thead table-light sticky-header\">\r\n <tr>\r\n @if (allowSelection() && data().length !== 0) {\r\n <th class=\"text-center selection-column\">\r\n @if (multiple()) {\r\n <input type=\"checkbox\" [checked]=\"selectAllChecked()\" [indeterminate]=\"selectAllIndeterminate()\" (change)=\"toggleSelectAll()\" aria-label=\"Seleccionar todo\" />\r\n }\r\n </th>\r\n }\r\n @for (col of columns(); track col) {\r\n @if (isColumnVisibleInHeader(col)) {\r\n @if (col.type === 'boolean') {\r\n <th class=\"text-center boolean-column\">{{ col.label }}</th>\r\n }\r\n @else if (col.type === 'number' || col.type === 'integer') {\r\n <th class=\"text-center number-column\">{{ col.label }}</th>\r\n }\r\n @else if (col.type === 'date') {\r\n <th class=\"text-center date-column\">{{ col.label }}</th>\r\n }\r\n @else {\r\n <th>{{ col.label }}</th>\r\n }\r\n }\r\n }\r\n @if (hasAnyActions()) {\r\n <th class=\"table-actions-header\">\r\n <div class=\"actions-wrapper\">\r\n <span>Actions</span>\r\n @if (shouldShowCreateButton()) {\r\n <c80-icon button icon=\"add\" [disabled]=\"creating()\" title=\"Agregar\" [size]=\".6\" (iconClick)=\"startCreate()\" />\r\n }\r\n </div>\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (row of data(); track trackById(i, row); let i = $index) {\r\n <tr>\r\n @if (allowSelection() && data().length !== 0) {\r\n <td class=\"text-center selection-column\">\r\n <input type=\"checkbox\" [checked]=\"isItemSelected(row)\" (change)=\"toggleItemSelection(row)\" [attr.aria-label]=\"'Seleccionar fila ' + (i + 1)\" />\r\n </td>\r\n }\r\n @for (col of columns(); track col) {\r\n @if (isColumnVisibleForRow(col, row)) {\r\n @if (col.type === 'boolean') {\r\n <td class=\"text-center boolean-column\">\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n <input type=\"checkbox\" [checked]=\"!!editRow()?.[col.accessor]\" (change)=\"onEditInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\r\n }\r\n @else {\r\n @if (getCellValue(row, col.accessor) === true) {\r\n <c80-icon icon=\"check\" [size]=\".7\" />\r\n <br />\r\n }\r\n @else if (getCellValue(row, col.accessor) === false) {\r\n <c80-icon icon=\"cancel\" [size]=\".7\" />\r\n <br />\r\n }\r\n }\r\n </td>\r\n }\r\n @else if (col.type === 'number' || col.type === 'integer') {\r\n <td class=\"text-center number-column\">\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\r\n (input)=\"onEditInput($event, col.accessor, col)\" />\r\n }\r\n @else {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\r\n col.accessor), col) }}</span>\r\n }\r\n </td>\r\n }\r\n @else if (col.type === 'date') {\r\n <td class=\"text-center date-column\">\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n <input class=\"form-control form-control-sm\" type=\"datetime-local\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onEditInput($event, col.accessor, col)\" />\r\n }\r\n @else {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\r\n col.accessor), col) }}</span>\r\n }\r\n </td>\r\n }\r\n @else {\r\n <td>\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n @if (col.type === 'enum') {\r\n <select class=\"form-control form-control-sm\" [value]=\"editRow()?.[col.accessor] ?? ''\" (change)=\"onEditInput($event, col.accessor, col)\">\r\n <option value=\"\">{{ col.label }}</option>\r\n @for (option of getEnumOptions(col); track option.value) {\r\n <option [value]=\"option.value\">{{ option.label }}</option>\r\n }\r\n </select>\r\n }\r\n @else {\r\n <input class=\"form-control form-control-sm\" [type]=\"col.type === 'password' ? 'password' : 'text'\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onEditInput($event, col.accessor, col)\" />\r\n }\r\n }\r\n @else {\r\n @if (col.type === 'password') {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">******</span>\r\n }\r\n @else if (col.type === 'enum') {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{\r\n getEnumDisplayValue(getCellValue(row, col.accessor), col)\r\n }}</span>\r\n }\r\n @else if (getCellValue(row, col.accessor) === true) {\r\n <c80-icon icon=\"check\" [size]=\".7\" />\r\n }\r\n @else if (getCellValue(row, col.accessor) === false) {\r\n <c80-icon icon=\"cancel\" [size]=\".7\" />\r\n }\r\n @else {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\r\n col.accessor), col) }}</span>\r\n }\r\n }\r\n </td>\r\n }\r\n }\r\n }\r\n @if (hasAnyActions()) {\r\n <td class=\"text-end actions-cell\">\r\n <div class=\"actions-container\" [class.centered-actions]=\"editing() === row['id']\">\r\n @if (editing() === row['id']) {\r\n <!-- Modo edici\u00F3n: mostrar guardar y cancelar -->\r\n @if (hasCrudUpdate()) {\r\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\" [size]=\".7\" />\r\n }\r\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\" [size]=\".7\" />\r\n }\r\n @else {\r\n @for (action of customActions(); track action.name) {\r\n @if (shouldShowAction(action, row, data())) {\r\n <c80-icon button [icon]=\"action.icon\" [customColor]=\"getActionColor(action)\" [color]=\"action.name === 'delete' ? 'warn' : 'primary'\" [title]=\"getActionTooltip(action)\" (iconClick)=\"onDynamicAction(action, row)\" [size]=\".7\" />\r\n }\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (creating() && hasCrudCreate()) {\r\n <tr>\r\n @if (allowSelection() && data().length !== 0) {\r\n <td class=\"text-center selection-column\">\r\n <!-- Empty cell for alignment -->\r\n </td>\r\n }\r\n @for (col of columns(); track col) {\r\n @if (isColumnVisible(col)) {\r\n @if (col.type === 'boolean') {\r\n <td class=\"text-center\">\r\n @if (!col.readOnly) {\r\n <input type=\"checkbox\" [checked]=\"!!newRow()?.[col.accessor]\" (change)=\"onInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\r\n }\r\n @else {\r\n <!-- ReadOnly boolean column in create mode shows empty -->\r\n <span class=\"text-muted\">-</span>\r\n }\r\n </td>\r\n } @else if (col.type === 'number' || col.type === 'integer') {\r\n <td class=\"text-center number-column\">\r\n @if (!col.readOnly) {\r\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\r\n (input)=\"onInput($event, col.accessor, col)\" />\r\n }\r\n @else {\r\n <!-- ReadOnly number column in create mode shows empty -->\r\n <span class=\"text-muted\">-</span>\r\n }\r\n </td>\r\n } @else {\r\n <td>\r\n @if (!col.readOnly) {\r\n @if (col.type === 'enum') {\r\n <select class=\"form-control form-control-sm\" [value]=\"newRow()?.[col.accessor] ?? ''\" (change)=\"onInput($event, col.accessor, col)\">\r\n <option value=\"\">{{ col.label }}</option>\r\n @for (option of getEnumOptions(col); track option.value) {\r\n <option [value]=\"option.value\">{{ option.label }}</option>\r\n }\r\n </select>\r\n }\r\n @else {\r\n <input class=\"form-control form-control-sm\" type=\"text\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onInput($event, col.accessor, col)\" />\r\n }\r\n }\r\n @else {\r\n <!-- ReadOnly column in create mode shows empty -->\r\n <span class=\"text-muted\">-</span>\r\n }\r\n </td>\r\n }\r\n }\r\n }\r\n <td class=\"text-end actions-cell\">\r\n <div class=\"actions-container centered-actions\">\r\n @if (hasCrudCreate()) {\r\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveCreate()\" [size]=\".7\" />\r\n }\r\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelCreate()\" [size]=\".7\" />\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n @if (data().length === 0 && !creating()) {\r\n <div class=\"text-center text-muted py-3 small\">\r\n No hay datos para mostrar.\r\n </div>\r\n }\r\n\r\n <!-- Pagination Controls -->\r\n @if (paginated() && data().length > 0) {\r\n <div class=\"pagination-container\">\r\n <div class=\"pagination-info\">\r\n P\u00E1gina {{ currentPage() }} de {{ totalPages() }}\r\n </div>\r\n <div class=\"pagination-controls\">\r\n <button type=\"button\" class=\"btn btn-sm\" [disabled]=\"!hasPrevPage()\" (click)=\"onPrevPage()\" title=\"P\u00E1gina anterior\">\r\n <c80-icon icon=\"arrowLeft\" [size]=\".6\" [button]=\"false\" />\r\n </button>\r\n <button type=\"button\" class=\"btn btn-sm\" [disabled]=\"!hasNextPage()\" (click)=\"onNextPage()\" title=\"P\u00E1gina siguiente\">\r\n <c80-icon icon=\"arrowRight\" [size]=\".6\" [button]=\"false\" />\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n\r\n<c80-modal />", styles: ["@charset \"UTF-8\";input[type=checkbox]{width:1.3rem!important;height:1.3rem!important;accent-color:var(--color-icon-danger);background:var(--color-bg-primary);margin:0 .25rem;vertical-align:middle;cursor:pointer}.table-responsive{width:100%;overflow-x:auto}.table-responsive .search-container{margin-bottom:-.06rem}.table-responsive .search-container .search-input-wrapper .input-group .btn-borrar{border-bottom-right-radius:0;border-color:var(--color-border-default);height:32px}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text{background-color:var(--color-bg-secondary);border-color:var(--color-border-default);border-bottom-left-radius:0;color:var(--color-text-secondary);width:56.1px;height:32px;padding:.25rem .5rem}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text c80-icon{display:flex;align-items:center;justify-content:center}.table-responsive .search-container .search-input-wrapper .input-group .search-input{border-color:var(--color-border-default);border-bottom-right-radius:0;font-size:.75rem;height:32px;padding:.25rem .5rem;outline:none!important;background-color:var(--color-bg-primary);color:var(--color-text-primary)}.table-responsive .search-container .search-input-wrapper .input-group .search-input:focus{outline:none!important}.table-responsive .search-container .search-input-wrapper .input-group .search-input::placeholder{color:var(--color-text-muted);font-style:italic}.table-responsive .table{min-width:0px;margin-bottom:0;background-color:var(--color-bg-primary);color:var(--color-text-primary);border-color:var(--color-border-default)}.table-responsive .table.table-bordered,.table-responsive .table.table-bordered th,.table-responsive .table.table-bordered td{border-color:var(--color-border-default)}.table-responsive .table.table-hover tbody tr:hover{background-color:var(--color-bg-hover)!important;color:var(--color-text-primary)}.table-responsive .table.table-hover tbody tr:hover td{background-color:var(--color-bg-hover)}.table-responsive .table .sticky-header{position:sticky;top:0;z-index:10;background-color:var(--color-bg-secondary)!important}.table-responsive .table .sticky-header .table-actions-header{display:table-cell;vertical-align:middle;padding:.2rem .6rem!important;background-color:var(--color-bg-secondary)!important}.table-responsive .table .sticky-header .actions-wrapper{display:flex;align-items:center;justify-content:center;gap:.5rem;height:100%}.table-responsive .table .sticky-header th{max-height:31px!important;vertical-align:middle!important;padding:.2rem .6rem!important;font-size:small!important;background-color:var(--color-bg-secondary)!important;border-bottom:2px solid var(--color-border-default);color:var(--color-text-primary)}.table-responsive .table tbody{background-color:var(--color-bg-primary)}.table-responsive .table tbody td{height:35px!important;min-height:35px!important;max-height:35px!important;vertical-align:middle!important;padding:.2rem .8rem!important;font-size:small;color:var(--color-text-primary);background-color:var(--color-bg-primary);border-color:var(--color-border-default)}.table-responsive .table tbody tr{height:35px!important;min-height:35px!important;max-height:35px!important;cursor:pointer;background-color:var(--color-bg-primary)}.table-responsive .table tbody tr:hover{background-color:var(--color-bg-hover)!important}.table-responsive .table tbody tr:hover td{background-color:var(--color-bg-hover)}.table-responsive .table tbody .text-muted{color:var(--color-text-muted)!important}.table-responsive .table tbody input,.table-responsive .table tbody select{border:1px solid var(--color-border-default);height:100%!important;font-size:smaller!important;background-color:var(--color-bg-primary);color:var(--color-text-primary)}.table-responsive .table tbody input:focus,.table-responsive .table tbody select:focus{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus)}.table-responsive .table tbody input::placeholder,.table-responsive .table tbody select::placeholder{color:var(--color-text-muted)}.table-responsive .table tbody input[type=text],.table-responsive .table tbody input:not([type]){width:100%!important}.table-responsive .table tbody input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table tbody select{width:100%!important;padding:.25rem .5rem}.table-responsive .table thead th.boolean-column,.table-responsive .table tbody td.boolean-column,.table-responsive .table thead th.selection-column,.table-responsive .table tbody td.selection-column,.table-responsive .table thead th.table-actions-header,.table-responsive .table tbody td.table-actions-header{width:1%;white-space:nowrap}.table-responsive .table thead th.number-column,.table-responsive .table tbody td.number-column{width:1%;white-space:nowrap;text-align:center}.table-responsive .table thead th.number-column input[type=number],.table-responsive .table tbody td.number-column input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table thead th.date-column,.table-responsive .table tbody td.date-column{width:1%;white-space:nowrap;text-align:center}.table-responsive .table thead th.date-column input[type=datetime-local],.table-responsive .table tbody td.date-column input[type=datetime-local]{min-width:200px!important;width:200px!important;text-align:center}.table-responsive .table .actions-cell{white-space:nowrap;padding:0!important}.table-responsive .table .actions-container{display:flex;flex-direction:row;justify-content:flex-end;align-items:center;width:100%;height:100%}.table-responsive .table .actions-container.centered-actions{justify-content:center}.table-responsive .text-center.text-muted{color:var(--color-text-muted)!important}.table-responsive .btn-outline-secondary{background-color:var(--color-bg-primary);color:var(--color-text-primary);border-color:var(--color-border-default)}.table-responsive .btn-outline-secondary:hover{background-color:var(--color-bg-hover);border-color:var(--color-border-medium)}.table-responsive .btn-outline-secondary:focus{box-shadow:var(--shadow-focus)}.table-responsive .pagination-container{display:flex;justify-content:space-between;align-items:center;padding:.2rem .5rem;background-color:var(--color-bg-secondary);border:1px solid var(--color-border-default);border-top:none;border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.table-responsive .pagination-container .pagination-info{font-size:.875rem;color:var(--color-text-secondary);font-weight:500}.table-responsive .pagination-container .pagination-controls{display:flex;gap:.5rem}.table-responsive .pagination-container .pagination-controls button{min-width:36px;height:32px;padding:.25rem .5rem;display:flex;align-items:center;justify-content:center;background-color:var(--color-bg-primary);color:var(--color-text-primary);border:none}.table-responsive .pagination-container .pagination-controls button:hover:not(:disabled){background-color:var(--color-bg-hover);border:none}.table-responsive .pagination-container .pagination-controls button:disabled{opacity:.5;cursor:auto;background-color:var(--color-bg-primary);border:none}\n"] }]
538
+ args: [{ selector: 'c80-table', imports: [IconComponent, ModalComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"table-responsive\" [style.max-height]=\"tableMaxHeight()\" [style.overflow-y]=\"size() > 0 ? 'auto' : 'visible'\">\r\n <!-- Search Bar -->\r\n @if (searchable()) {\r\n <div class=\"search-container\">\r\n <div class=\"search-input-wrapper\">\r\n <div class=\"input-group\">\r\n <span class=\"input-group-text\">\r\n <c80-icon icon=\"search\" [size]=\".65\" [button]=\"false\" />\r\n </span>\r\n <input type=\"text\" class=\"form-control search-input\" placeholder=\"Buscar...\" [value]=\"searchValue()\" (input)=\"onSearchInput($event)\" aria-label=\"Buscar en la tabla\" />\r\n @if (searchValue()) {\r\n <button class=\"btn btn-outline-secondary btn-borrar\" type=\"button\" (click)=\"clearSearch()\" title=\"Limpiar b\u00FAsqueda\">\r\n <c80-icon icon=\"cancel\" [size]=\".6\" />\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <table class=\"table table-bordered table-hover align-middle\">\r\n <thead class=\"thead table-light sticky-header\">\r\n <tr>\r\n @if (allowSelection() && data().length !== 0) {\r\n <th class=\"text-center selection-column\">\r\n @if (multiple()) {\r\n <input type=\"checkbox\" [checked]=\"selectAllChecked()\" [indeterminate]=\"selectAllIndeterminate()\" (change)=\"toggleSelectAll()\" aria-label=\"Seleccionar todo\" />\r\n }\r\n </th>\r\n }\r\n @for (col of columns(); track col) {\r\n @if (isColumnVisibleInHeader(col)) {\r\n @if (col.type === 'boolean') {\r\n <th class=\"text-center boolean-column\">{{ col.label }}</th>\r\n }\r\n @else if (col.type === 'number' || col.type === 'integer') {\r\n <th class=\"text-center number-column\">{{ col.label }}</th>\r\n }\r\n @else if (col.type === 'date') {\r\n <th class=\"text-center date-column\">{{ col.label }}</th>\r\n }\r\n @else {\r\n <th>{{ col.label }}</th>\r\n }\r\n }\r\n }\r\n @if (hasAnyActions()) {\r\n <th class=\"table-actions-header\">\r\n <div class=\"actions-wrapper\">\r\n <span>Actions</span>\r\n @if (shouldShowCreateButton()) {\r\n <c80-icon button icon=\"add\" [disabled]=\"creating()\" title=\"Agregar\" [size]=\".6\" (iconClick)=\"startCreate()\" />\r\n }\r\n </div>\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (row of data(); track trackById(i, row); let i = $index) {\r\n <tr>\r\n @if (allowSelection() && data().length !== 0) {\r\n <td class=\"text-center selection-column\">\r\n <input type=\"checkbox\" [checked]=\"isItemSelected(row)\" (change)=\"toggleItemSelection(row)\" [attr.aria-label]=\"'Seleccionar fila ' + (i + 1)\" />\r\n </td>\r\n }\r\n @for (col of columns(); track col) {\r\n @if (isColumnVisibleForRow(col, row)) {\r\n @if (col.type === 'boolean') {\r\n <td class=\"text-center boolean-column\">\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n <input type=\"checkbox\" [checked]=\"!!editRow()?.[col.accessor]\" (change)=\"onEditInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\r\n }\r\n @else {\r\n @if (getCellValue(row, col.accessor) === true) {\r\n <c80-icon icon=\"check\" [size]=\".7\" />\r\n <br />\r\n }\r\n @else if (getCellValue(row, col.accessor) === false) {\r\n <c80-icon icon=\"cancel\" [size]=\".7\" />\r\n <br />\r\n }\r\n }\r\n </td>\r\n }\r\n @else if (col.type === 'number' || col.type === 'integer') {\r\n <td class=\"text-center number-column\">\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\r\n (input)=\"onEditInput($event, col.accessor, col)\" />\r\n }\r\n @else {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\r\n col.accessor), col) }}</span>\r\n }\r\n </td>\r\n }\r\n @else if (col.type === 'date') {\r\n <td class=\"text-center date-column\">\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n <input class=\"form-control form-control-sm\" type=\"datetime-local\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onEditInput($event, col.accessor, col)\" />\r\n }\r\n @else {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\r\n col.accessor), col) }}</span>\r\n }\r\n </td>\r\n }\r\n @else {\r\n <td>\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n @if (col.type === 'enum') {\r\n <select class=\"form-control form-control-sm\" [value]=\"editRow()?.[col.accessor] ?? ''\" (change)=\"onEditInput($event, col.accessor, col)\">\r\n <option value=\"\">{{ col.label }}</option>\r\n @for (option of getEnumOptions(col); track option.value) {\r\n <option [value]=\"option.value\">{{ option.label }}</option>\r\n }\r\n </select>\r\n }\r\n @else {\r\n <input class=\"form-control form-control-sm\" [type]=\"col.type === 'password' ? 'password' : 'text'\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onEditInput($event, col.accessor, col)\" />\r\n }\r\n }\r\n @else {\r\n @if (col.type === 'password') {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">******</span>\r\n }\r\n @else if (col.type === 'enum') {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{\r\n getEnumDisplayValue(getCellValue(row, col.accessor), col)\r\n }}</span>\r\n }\r\n @else if (getCellValue(row, col.accessor) === true) {\r\n <c80-icon icon=\"check\" [size]=\".7\" />\r\n }\r\n @else if (getCellValue(row, col.accessor) === false) {\r\n <c80-icon icon=\"cancel\" [size]=\".7\" />\r\n }\r\n @else {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\r\n col.accessor), col) }}</span>\r\n }\r\n }\r\n </td>\r\n }\r\n }\r\n }\r\n @if (hasAnyActions()) {\r\n <td class=\"text-end actions-cell\">\r\n <div class=\"actions-container\" [class.centered-actions]=\"editing() === row['id']\">\r\n @if (editing() === row['id']) {\r\n <!-- Modo edici\u00F3n: mostrar guardar y cancelar -->\r\n @if (hasCrudUpdate()) {\r\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\" [size]=\".7\" />\r\n }\r\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\" [size]=\".7\" />\r\n }\r\n @else {\r\n @for (action of customActions(); track action.name) {\r\n @if (shouldShowAction(action, row, data())) {\r\n <c80-icon button [icon]=\"action.icon\" [customColor]=\"getActionColor(action)\" [color]=\"action.name === 'delete' ? 'warn' : 'primary'\" [title]=\"getActionTooltip(action)\" (iconClick)=\"onDynamicAction(action, row)\" [size]=\".7\" />\r\n }\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (creating() && hasCrudCreate()) {\r\n <tr>\r\n @if (allowSelection() && data().length !== 0) {\r\n <td class=\"text-center selection-column\">\r\n <!-- Empty cell for alignment -->\r\n </td>\r\n }\r\n @for (col of columns(); track col) {\r\n @if (isColumnVisible(col)) {\r\n @if (col.type === 'boolean') {\r\n <td class=\"text-center\">\r\n @if (!col.readOnly) {\r\n <input type=\"checkbox\" [checked]=\"!!newRow()?.[col.accessor]\" (change)=\"onInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\r\n }\r\n @else {\r\n <!-- ReadOnly boolean column in create mode shows empty -->\r\n <span class=\"text-muted\">-</span>\r\n }\r\n </td>\r\n } @else if (col.type === 'number' || col.type === 'integer') {\r\n <td class=\"text-center number-column\">\r\n @if (!col.readOnly) {\r\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\r\n (input)=\"onInput($event, col.accessor, col)\" />\r\n }\r\n @else {\r\n <!-- ReadOnly number column in create mode shows empty -->\r\n <span class=\"text-muted\">-</span>\r\n }\r\n </td>\r\n } @else {\r\n <td>\r\n @if (!col.readOnly) {\r\n @if (col.type === 'enum') {\r\n <select class=\"form-control form-control-sm\" [value]=\"newRow()?.[col.accessor] ?? ''\" (change)=\"onInput($event, col.accessor, col)\">\r\n <option value=\"\">{{ col.label }}</option>\r\n @for (option of getEnumOptions(col); track option.value) {\r\n <option [value]=\"option.value\">{{ option.label }}</option>\r\n }\r\n </select>\r\n }\r\n @else {\r\n <input class=\"form-control form-control-sm\" type=\"text\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onInput($event, col.accessor, col)\" />\r\n }\r\n }\r\n @else {\r\n <!-- ReadOnly column in create mode shows empty -->\r\n <span class=\"text-muted\">-</span>\r\n }\r\n </td>\r\n }\r\n }\r\n }\r\n <td class=\"text-end actions-cell\">\r\n <div class=\"actions-container centered-actions\">\r\n @if (hasCrudCreate()) {\r\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveCreate()\" [size]=\".7\" />\r\n }\r\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelCreate()\" [size]=\".7\" />\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n @if (data().length === 0 && !creating()) {\r\n <div class=\"text-center text-muted py-3 small\">\r\n No hay datos para mostrar.\r\n </div>\r\n }\r\n\r\n <!-- Pagination Controls -->\r\n @if (paginated() && data().length > 0) {\r\n <div class=\"pagination-container\">\r\n <div class=\"pagination-info\">\r\n P\u00E1gina {{ currentPage() }} de {{ totalPages() }}\r\n </div>\r\n <div class=\"pagination-controls\">\r\n <button type=\"button\" class=\"btn btn-sm\" [disabled]=\"!hasPrevPage()\" (click)=\"onPrevPage()\" title=\"P\u00E1gina anterior\">\r\n <c80-icon icon=\"arrowLeft\" [size]=\".6\" [button]=\"false\" />\r\n </button>\r\n <button type=\"button\" class=\"btn btn-sm\" [disabled]=\"!hasNextPage()\" (click)=\"onNextPage()\" title=\"P\u00E1gina siguiente\">\r\n <c80-icon icon=\"arrowRight\" [size]=\".6\" [button]=\"false\" />\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n\r\n<c80-modal />", styles: ["@charset \"UTF-8\";input[type=checkbox]{width:1.3rem!important;height:1.3rem!important;accent-color:var(--color-icon-danger);background:var(--color-bg-primary);margin:0 .25rem;vertical-align:middle;cursor:pointer}.table-responsive{width:100%;overflow-x:auto}.table-responsive .search-container{margin-bottom:-.06rem}.table-responsive .search-container .search-input-wrapper .input-group .btn-borrar{border-bottom-right-radius:0;border-color:var(--color-border-default);height:32px}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text{background-color:var(--color-bg-secondary);border-color:var(--color-border-default);border-bottom-left-radius:0;color:var(--color-text-secondary);width:56.1px;height:32px;padding:.25rem .5rem}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text c80-icon{display:flex;align-items:center;justify-content:center}.table-responsive .search-container .search-input-wrapper .input-group .search-input{border-color:var(--color-border-default);border-bottom-right-radius:0;font-size:.75rem;height:32px;padding:.25rem .5rem;outline:none!important;background-color:var(--color-bg-primary);color:var(--color-text-primary)}.table-responsive .search-container .search-input-wrapper .input-group .search-input:focus{outline:none!important}.table-responsive .search-container .search-input-wrapper .input-group .search-input::placeholder{color:var(--color-text-muted);font-style:italic}.table-responsive .table{min-width:0px;margin-bottom:0;background-color:var(--color-bg-primary);color:var(--color-text-primary);border-color:var(--color-border-default)}.table-responsive .table.table-bordered,.table-responsive .table.table-bordered th,.table-responsive .table.table-bordered td{border-color:var(--color-border-default)}.table-responsive .table.table-hover tbody tr:hover{background-color:var(--color-bg-hover)!important;color:var(--color-text-primary)}.table-responsive .table.table-hover tbody tr:hover td{background-color:var(--color-bg-hover)}.table-responsive .table .sticky-header{position:sticky;top:0;z-index:10;background-color:var(--color-bg-secondary)!important}.table-responsive .table .sticky-header .table-actions-header{display:table-cell;vertical-align:middle;padding:.2rem .6rem!important;background-color:var(--color-bg-secondary)!important}.table-responsive .table .sticky-header .actions-wrapper{display:flex;align-items:center;justify-content:center;gap:.5rem;height:100%}.table-responsive .table .sticky-header th{max-height:31px!important;vertical-align:middle!important;padding:.2rem .6rem!important;font-size:small!important;background-color:var(--color-bg-secondary)!important;border-bottom:2px solid var(--color-border-default);color:var(--color-text-primary)}.table-responsive .table tbody{background-color:var(--color-bg-primary)}.table-responsive .table tbody td{height:35px!important;min-height:35px!important;max-height:35px!important;vertical-align:middle!important;padding:.2rem .8rem!important;font-size:small;color:var(--color-text-primary);background-color:var(--color-bg-primary);border-color:var(--color-border-default)}.table-responsive .table tbody tr{height:35px!important;min-height:35px!important;max-height:35px!important;cursor:pointer;background-color:var(--color-bg-primary)}.table-responsive .table tbody tr:hover{background-color:var(--color-bg-hover)!important}.table-responsive .table tbody tr:hover td{background-color:var(--color-bg-hover)}.table-responsive .table tbody .text-muted{color:var(--color-text-muted)!important}.table-responsive .table tbody input,.table-responsive .table tbody select{border:1px solid var(--color-border-default);height:100%!important;font-size:smaller!important;background-color:var(--color-bg-primary);color:var(--color-text-primary)}.table-responsive .table tbody input:focus,.table-responsive .table tbody select:focus{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus)}.table-responsive .table tbody input::placeholder,.table-responsive .table tbody select::placeholder{color:var(--color-text-muted)}.table-responsive .table tbody input[type=text],.table-responsive .table tbody input:not([type]){width:100%!important}.table-responsive .table tbody input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table tbody select{width:100%!important;padding:.25rem .5rem}.table-responsive .table thead th.boolean-column,.table-responsive .table tbody td.boolean-column,.table-responsive .table thead th.selection-column,.table-responsive .table tbody td.selection-column,.table-responsive .table thead th.table-actions-header,.table-responsive .table tbody td.table-actions-header{width:1%;white-space:nowrap}.table-responsive .table thead th.number-column,.table-responsive .table tbody td.number-column{width:1%;white-space:nowrap;text-align:center}.table-responsive .table thead th.number-column input[type=number],.table-responsive .table tbody td.number-column input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table thead th.date-column,.table-responsive .table tbody td.date-column{width:1%;white-space:nowrap;text-align:center}.table-responsive .table thead th.date-column input[type=datetime-local],.table-responsive .table tbody td.date-column input[type=datetime-local]{min-width:200px!important;width:200px!important;text-align:center}.table-responsive .table .actions-cell{white-space:nowrap;padding:0!important}.table-responsive .table .actions-container{display:flex;flex-direction:row;justify-content:flex-end;align-items:center;width:100%;height:100%}.table-responsive .table .actions-container.centered-actions{justify-content:center}.table-responsive .text-center.text-muted{color:var(--color-text-muted)!important}.table-responsive .btn-outline-secondary{background-color:var(--color-bg-primary);color:var(--color-text-primary);border-color:var(--color-border-default)}.table-responsive .btn-outline-secondary:hover{background-color:var(--color-bg-hover);border-color:var(--color-border-medium)}.table-responsive .btn-outline-secondary:focus{box-shadow:var(--shadow-focus)}.table-responsive .pagination-container{display:flex;justify-content:space-between;align-items:center;padding:.2rem .5rem;background-color:var(--color-bg-secondary);border:1px solid var(--color-border-default);border-top:none;border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.table-responsive .pagination-container .pagination-info{font-size:.875rem;color:var(--color-text-secondary);font-weight:500}.table-responsive .pagination-container .pagination-controls{display:flex;gap:.5rem}.table-responsive .pagination-container .pagination-controls button{min-width:36px;height:32px;padding:.25rem .5rem;display:flex;align-items:center;justify-content:center;background-color:var(--color-bg-primary);color:var(--color-text-primary);border:none}.table-responsive .pagination-container .pagination-controls button:hover:not(:disabled){background-color:var(--color-bg-hover);border:none}.table-responsive .pagination-container .pagination-controls button:disabled{opacity:.5;cursor:auto;background-color:var(--color-bg-primary);border:none}\n"] }]
565
539
  }], ctorParameters: () => [], propDecorators: { data$: [{ type: i0.Input, args: [{ isSignal: true, alias: "data$", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], inputValues$: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputValues$", required: false }] }], customActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "customActions", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], rowId: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowId", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], allowSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowSelection", required: false }] }], noConfirm: [{ type: i0.Input, args: [{ isSignal: true, alias: "noConfirm", required: false }] }], paginated: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginated", required: false }] }], paginationConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginationConfig", required: false }] }], actionClick: [{ type: i0.Output, args: ["actionClick"] }], searchTerm: [{ type: i0.Output, args: ["searchTerm"] }], errorEvent: [{ type: i0.Output, args: ["errorEvent"] }], selectable: [{ type: i0.Output, args: ["selectable"] }], paginationChange: [{ type: i0.Output, args: ["paginationChange"] }] } });
566
540
  //# sourceMappingURL=table.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"table.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table.component.ts","../../../../../libs/ui/src/lib/table/table.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\r\n type OnInit,\r\n type OnDestroy,\r\n Component,\r\n ChangeDetectionStrategy,\r\n input,\r\n signal,\r\n computed,\r\n output,\r\n inject,\r\n effect,\r\n} from '@angular/core';\r\nimport type { Observable, Subscription } from 'rxjs';\r\nimport { IconComponent } from '../icon';\r\nimport { TableColumnVisibilityService } from './table-column-visibility.service';\r\nimport { TableDataUtilsService } from './table-data-utils.service';\r\nimport { TableDataConverterService } from './table-data-converter.service';\r\nimport { TableSelectionService } from './table-selection.service';\r\nimport { TableCrudStateService } from './table-crud-state.service';\r\nimport { TablePaginationService } from './table-pagination.service';\r\nimport type { TableColDef, CustomTableAction, PaginationChangeEvent, PaginationConfig } from './table.types';\r\nimport { ModalComponent, ModalService } from '../modal';\r\nimport {\r\n booleanAttribute,\r\n getErrorMessage,\r\n getInputValue,\r\n trackById,\r\n shouldShowAction,\r\n getActionTooltip,\r\n} from './table.utils';\r\n\r\n/**\r\n * C80TableComponent - Componente de tabla avanzado con funcionalidades CRUD\r\n *\r\n * COMPORTAMIENTO DE VISIBILIDAD DE COLUMNAS:\r\n * ========================================\r\n *\r\n * 1. PRIORIDAD MÁXIMA - visible: false\r\n * - La columna se oculta SIEMPRE, sin excepciones\r\n * - Ni en modo creación ni en modo edición se muestra\r\n *\r\n * 2. OCULTACIÓN AUTOMÁTICA - hideIfAllValuesAreNull: true\r\n * - La columna se oculta solo si TODOS los valores actuales están vacíos\r\n * - Valores considerados vacíos: null, undefined, '', [], {}\r\n * - Valores NO vacíos: 0, false (son valores válidos)\r\n * - EXCEPCIONES IMPORTANTES:\r\n * * En modo creación (creating=true) estas columnas SÍ se muestran\r\n * * En modo edición de una fila específica se muestran SOLO si esa fila tiene valor\r\n *\r\n * 3. POR DEFECTO - Columnas normales\r\n * - Se muestran siempre (visualización, creación y edición)\r\n *\r\n * VALORES POR DEFECTO EN CREACIÓN:\r\n * ===============================\r\n *\r\n * - Propiedad `default?: unknown` permite definir valores por defecto para modo creación\r\n * - Solo se aplica cuando se inicia el modo creación (startCreate)\r\n * - Puede ser cualquier tipo: string, number, boolean, etc.\r\n * - Si no se especifica `default`, se usa cadena vacía ('')\r\n *\r\n * VALORES DINÁMICOS EN CREACIÓN Y EDICIÓN:\r\n * =======================================\r\n *\r\n * - Input `inputValues$?: Observable<Partial<T>>` permite actualizar valores dinámicamente\r\n * - Solo se aplica durante modo creación (creating=true) o edición (editing!=null)\r\n * - Los valores se aplican automáticamente cuando el Observable emite\r\n * - Permite cambios múltiples durante el mismo modo de creación/edición\r\n * - Los nuevos valores sobrescriben los existentes (spread operator)\r\n *\r\n * TIPOS DE DATOS SOPORTADOS:\r\n * =========================\r\n *\r\n * - 'string': Texto normal (default)\r\n * - 'number': Números decimales (preserva decimales: 5.3 → 5.3)\r\n * - 'integer': Números enteros (convierte a entero: 5.3 → 5)\r\n * - 'boolean': Verdadero/Falso (checkbox)\r\n * - 'password': Texto oculto (input type=\"password\")\r\n * - 'enum': Lista de opciones predefinidas (select)\r\n *\r\n * SISTEMA DE ACCIONES UNIFICADO (customActions):\r\n * =============================================\r\n *\r\n * Input: `customActions: CustomTableAction[]` - Array de acciones dinámicas\r\n * Output: `(actionClick)` - Evento unificado que emite { action: string, row: T }\r\n *\r\n * ACCIONES CRUD PREDEFINIDAS (TABLE_CRUD_ACTIONS):\r\n * ------------------------------------------------\r\n * - CREATE: Solo aparece como botón \"+\" en header (no en filas)\r\n * - UPDATE: Activa modo edición (muestra inputs), botón \"✓\" guarda cambios\r\n * - DELETE: Muestra confirmación y emite evento delete\r\n * - CANCEL: Muestra confirmación y emite evento cancel (opcional)\r\n *\r\n * ACCIONES PERSONALIZADAS (Custom Actions):\r\n * -----------------------------------------\r\n * Interfaz: { name: string, icon: IconType, condition?: (row) => boolean, tooltip?: string }\r\n * - name: ID único de la acción\r\n * - icon: Icono del botón (ej: 'settings', 'upload', 'refresh')\r\n * - condition: Función opcional para mostrar/ocultar según estado de fila\r\n * - tooltip: Texto al hacer hover (default: name)\r\n *\r\n * MANEJO EN COMPONENTE:\r\n * --------------------\r\n * ```typescript\r\n * // 1. Definir acciones en constants:\r\n * export const ENTITY_TABLE_ACTIONS: CustomTableAction[] = [\r\n * TABLE_CRUD_ACTIONS.CREATE,\r\n * TABLE_CRUD_ACTIONS.UPDATE,\r\n * { name: 'custom-action', icon: 'settings', tooltip: 'Configurar' },\r\n * TABLE_CRUD_ACTIONS.DELETE\r\n * ];\r\n *\r\n * // 2. En el componente:\r\n * readonly tableActions = ENTITY_TABLE_ACTIONS;\r\n *\r\n * handleAction({ action, row }) {\r\n * const entity = row as unknown as EntityType;\r\n * switch (action) {\r\n * case 'create': this.onCreate(row); break;\r\n * case 'update': this.onUpdate(entity); break;\r\n * case 'delete': this.onDelete(entity.id); break;\r\n * case 'custom-action': this.onCustom(entity); break;\r\n * }\r\n * }\r\n * ```\r\n *\r\n * ACCIONES CON CONDICIÓN:\r\n * ----------------------\r\n * ```typescript\r\n * {\r\n * name: 'enable',\r\n * icon: 'toggleOn',\r\n * tooltip: 'Habilitar',\r\n * condition: (row) => row['enabled'] === false\r\n * }\r\n * ```\r\n *\r\n * CONSTANTES REUTILIZABLES:\r\n * ------------------------\r\n * - TABLE_CRUD_ACTIONS: Objeto con CREATE, UPDATE, DELETE, CANCEL\r\n * - BASIC_CRUD_ACTIONS: Array con [CREATE, UPDATE, DELETE]\r\n * Importar desde: `@shared` o `@shared/constants`\r\n *\r\n * EJEMPLOS COMPLETOS:\r\n * ------------------\r\n * - { accessor: 'id', visible: false } → NUNCA se muestra\r\n * - { accessor: 'motorPos', hideIfAllValuesAreNull: true, default: 0, type: 'integer' } → Entero (5.7 → 5)\r\n * - { accessor: 'weight', type: 'number', default: 2.5 } → Decimal preservado (5.7 → 5.7)\r\n * - { accessor: 'status', default: 'active' } → Se autorellena con 'active' en creación\r\n * - { accessor: 'name' } → Siempre visible, sin valor por defecto (cadena vacía)\r\n * - inputValues$ emite { motorPos: 5, weight: 2.3 } → actualiza inputs dinámicamente\r\n * - customActions con CREATE → Muestra botón \"+\" en header\r\n * - customActions con UPDATE → Botón \"edit\" activa modo edición\r\n * - customActions con custom → Botón personalizado emite evento\r\n */@Component({\r\n selector: 'c80-table',\r\n standalone: true,\r\n imports: [IconComponent, ModalComponent],\r\n templateUrl: './table.component.html',\r\n styleUrl: './table.component.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush\r\n})\r\nexport class TableComponent<T extends Record<string, unknown>> implements OnInit, OnDestroy {\r\n // Servicios inyectados\r\n /* v8 ignore next 7 */\r\n private readonly modalService = inject(ModalService);\r\n private readonly visibilityService = inject(TableColumnVisibilityService);\r\n private readonly dataUtils = inject(TableDataUtilsService);\r\n private readonly dataConverter = inject(TableDataConverterService);\r\n private readonly selectionService = inject(TableSelectionService);\r\n private readonly crudService = inject(TableCrudStateService);\r\n private readonly paginationService = inject(TablePaginationService);\r\n\r\n // Inputs\r\n /* v8 ignore next */\r\n readonly data$ = input.required<Observable<T[]>>();\r\n /* v8 ignore next */\r\n readonly columns = input<TableColDef[]>([]);\r\n /* v8 ignore next */\r\n readonly inputValues$ = input<Observable<Partial<T>>>(); // Observable para actualizar valores de inputs dinámicamente en creación/edición\r\n /* v8 ignore next */\r\n readonly customActions = input<CustomTableAction[]>([]); // Acciones personalizadas dinámicas\r\n /* v8 ignore next */\r\n readonly size = input(0); // Tamaño de la tabla (0 = sin límite, > 0 aplica max-height)\r\n /* v8 ignore next */\r\n readonly multiple = input(true); // Permite selección múltiple por defecto\r\n /* v8 ignore next */\r\n readonly rowId = input('id'); // Accessor de la PK de cada fila (default 'id'); usar si la entidad no usa 'id'\r\n /* v8 ignore next */\r\n readonly searchable = input(false, { transform: booleanAttribute }); // Si es true, muestra barra de búsqueda\r\n /* v8 ignore next */\r\n readonly allowSelection = input(false, { transform: booleanAttribute }); // Si es true, permite selección de filas\r\n /* v8 ignore next */\r\n readonly noConfirm = input(false, { transform: booleanAttribute }); // Si es true, no muestra confirmaciones modales\r\n /* v8 ignore next */\r\n readonly paginated = input(false, { transform: booleanAttribute }); // Si es true, habilita paginación con limit/offset\r\n /* v8 ignore next */\r\n readonly paginationConfig = input<PaginationConfig>({ pageSize: 10 }); // Configuración de paginación (tamaño de página, total items)\r\n\r\n // Outputs - Acciones unificadas (Angular 18+ output API)\r\n /* v8 ignore next */\r\n readonly actionClick = output<{ action: string; row: T }>(); // Output unificado para TODAS las acciones (CRUD + custom)\r\n\r\n // Outputs - Utilidades\r\n /* v8 ignore next 4 */\r\n readonly searchTerm = output<string>();\r\n readonly errorEvent = output<string>();\r\n readonly selectable = output<T[]>();\r\n readonly paginationChange = output<PaginationChangeEvent>(); // Output para cambios de paginación (page, limit, offset)\r\n\r\n // Estado principal\r\n /* v8 ignore next 2 */\r\n readonly data = signal<T[]>([]);\r\n readonly searchValue = signal<string>('');\r\n\r\n // Estado de selección (delegado a servicio)\r\n /* v8 ignore next 4 */\r\n private readonly selectionState = this.selectionService.createSelectionState<T>(\r\n (item) => item[this.rowId()] as string\r\n );\r\n readonly selectedItems = this.selectionState.selectedItems;\r\n readonly selectAllChecked = this.selectionState.selectAllChecked;\r\n readonly selectAllIndeterminate = this.selectionState.selectAllIndeterminate;\r\n\r\n // Estado CRUD (delegado a servicio)\r\n /* v8 ignore next 5 */\r\n private readonly crudState = this.crudService.createCrudState<T>();\r\n readonly creating = this.crudState.creating;\r\n readonly newRow = this.crudState.newRow;\r\n readonly editing = this.crudState.editing;\r\n readonly editRow = this.crudState.editRow;\r\n\r\n // Estado de paginación (delegado a servicio)\r\n /* v8 ignore next 7 */\r\n private readonly paginationState = this.paginationService.createPaginationState(\r\n this.paginationConfig().pageSize ?? 10\r\n );\r\n readonly currentPage = this.paginationState.currentPage;\r\n readonly pageSize = this.paginationState.pageSize;\r\n readonly totalPages = this.paginationState.totalPages;\r\n readonly hasNextPage = this.paginationState.hasNextPage;\r\n readonly hasPrevPage = this.paginationState.hasPrevPage;\r\n\r\n // Keys visibles computed automáticamente\r\n /* v8 ignore next 7 */\r\n readonly keys = computed(() =>\r\n this.visibilityService.updateVisibleKeys(\r\n this.columns(),\r\n { data: this.data(), creating: this.creating(), editing: this.editing() }\r\n )\r\n );\r\n\r\n // Computed - Detecta acciones CRUD y custom\r\n /* v8 ignore next 5 */\r\n readonly hasAnyActions = computed(() => this.customActions().length > 0);\r\n readonly hasCrudCreate = computed(() => this.customActions().some(a => a.name === 'create'));\r\n readonly hasCrudUpdate = computed(() => this.customActions().some(a => a.name === 'update'));\r\n readonly hasCrudDelete = computed(() => this.customActions().some(a => a.name === 'delete'));\r\n readonly hasCrudCancel = computed(() => this.customActions().some(a => a.name === 'cancel'));\r\n\r\n /* v8 ignore next 5 */\r\n readonly shouldShowCreateButton = computed(() => {\r\n const createAction = this.customActions().find(a => a.name === 'create');\r\n if (!createAction) return false;\r\n return !createAction.condition || createAction.condition({} as Record<string, unknown>, this.data());\r\n });\r\n\r\n // Table max height computed\r\n /* v8 ignore next 3 */\r\n readonly tableMaxHeight = computed(() =>\r\n this.dataUtils.getTableMaxHeight(this.size())\r\n );\r\n\r\n /* v8 ignore next 2 */\r\n private dataSub?: Subscription;\r\n private inputValuesSub?: Subscription;\r\n\r\n constructor() {\r\n // Sincronizar totalItems del paginationConfig con el estado de paginación\r\n /* v8 ignore next 4 */\r\n effect(() => {\r\n const config = this.paginationConfig();\r\n if (config.totalItems !== undefined && this.paginated()) {\r\n this.paginationState.setTotalItems(config.totalItems);\r\n }\r\n });\r\n\r\n // Sincronizar pageSize del paginationConfig: los signal inputs se ligan\r\n // DESPUÉS de la construcción, así que el estado se inicializa con el default;\r\n // este effect reaplica el pageSize real del padre cuando cambia (sin resetear\r\n // la página por otros cambios del config como totalItems).\r\n /* v8 ignore next 8 */\r\n let lastPageSize: number | undefined;\r\n effect(() => {\r\n const size = this.paginationConfig().pageSize ?? 10;\r\n if (size !== lastPageSize) {\r\n lastPageSize = size;\r\n this.paginationState.setPageSize(size);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Maneja input de creación/edición de forma unificada\r\n */\r\n private handleInput(options: {\r\n event: Event;\r\n key: string;\r\n col: TableColDef | undefined;\r\n isEdit: boolean;\r\n }): void {\r\n const { event, key, col, isEdit } = options;\r\n const updateFn = isEdit\r\n ? this.crudState.updateEditRow.bind(this.crudState)\r\n : this.crudState.updateNewRow.bind(this.crudState);\r\n\r\n const value = getInputValue(event, col);\r\n if (value !== undefined) {\r\n updateFn(key, value);\r\n }\r\n }\r\n\r\n /**\r\n * Maneja confirmación modal de forma genérica\r\n */\r\n private async handleConfirmAction(options: {\r\n title: string;\r\n message: string;\r\n confirmText: string;\r\n action: () => void;\r\n }): Promise<void> {\r\n const { title, message, confirmText, action } = options;\r\n if (this.noConfirm()) {\r\n action();\r\n return;\r\n }\r\n\r\n const confirmed = await this.modalService.confirm({\r\n title,\r\n message,\r\n confirmText,\r\n cancelText: 'Cancelar'\r\n });\r\n\r\n if (confirmed) {\r\n action();\r\n }\r\n }\r\n\r\n\r\n\r\n ngOnInit(): void {\r\n const data$ = this.data$();\r\n if (!data$) return;\r\n this.dataSub = data$.subscribe({\r\n next: (items) => {\r\n this.dataUtils.applySorting(items, this.columns());\r\n this.data.set(items);\r\n this.preserveSelection();\r\n },\r\n error: (err: unknown) =>\r\n this.errorEvent.emit(getErrorMessage(err)),\r\n });\r\n\r\n // Suscribirse a inputValues$ para actualizar valores dinámicamente en creación/edición\r\n const inputValues$ = this.inputValues$();\r\n if (inputValues$) {\r\n this.inputValuesSub = inputValues$.subscribe({\r\n next: (partialValues) => {\r\n this.crudState.applyInputValues(partialValues);\r\n },\r\n error: (err: unknown) =>\r\n console.warn('Error en inputValues$:', getErrorMessage(err)),\r\n });\r\n }\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.dataSub?.unsubscribe();\r\n this.inputValuesSub?.unsubscribe();\r\n\r\n // Close any open modal when component is destroyed\r\n this.modalService.closeModal();\r\n }\r\n\r\n onInput(event: Event, key: string, col?: TableColDef): void {\r\n this.handleInput({ event, key, col, isEdit: false });\r\n }\r\n\r\n onEditInput(event: Event, key: string, col?: TableColDef): void {\r\n this.handleInput({ event, key, col, isEdit: true });\r\n }\r\n\r\n async onDelete(row: T): Promise<void> {\r\n await this.handleConfirmAction({\r\n title: 'Confirmar eliminación',\r\n message: '¿Está seguro de que desea eliminar este elemento? Esta acción no se puede deshacer.',\r\n confirmText: 'Eliminar',\r\n action: () => this.actionClick.emit({ action: 'delete', row })\r\n });\r\n }\r\n\r\n async onCancel(row: T): Promise<void> {\r\n await this.handleConfirmAction({\r\n title: 'Confirmar cancelación',\r\n message: '¿Está seguro de que desea cancelar este elemento?',\r\n confirmText: 'Cancelar elemento',\r\n action: () => this.actionClick.emit({ action: 'cancel', row })\r\n });\r\n }\r\n\r\n startCreate(): void {\r\n this.crudState.startCreate({ columns: this.columns(), data: this.data() });\r\n }\r\n\r\n cancelCreate(): void {\r\n this.crudState.cancelCreate();\r\n }\r\n\r\n saveCreate(): void {\r\n const current = this.newRow();\r\n if (current) {\r\n const convertedRow = this.convertRowTypes(current);\r\n const filteredRow = this.filterReadOnlyFields(convertedRow);\r\n this.actionClick.emit({ action: 'create', row: filteredRow as T });\r\n this.cancelCreate();\r\n }\r\n }\r\n\r\n onEdit(row: T): void {\r\n this.crudState.startEdit({ row, columns: this.columns(), data: this.data() });\r\n }\r\n\r\n cancelEdit(): void {\r\n this.crudState.cancelEdit();\r\n }\r\n\r\n saveEdit(row: T): void {\r\n const changes = this.editRow();\r\n if (changes) {\r\n const convertedChanges = this.convertRowTypes(changes);\r\n const filteredChanges = this.filterReadOnlyFields(convertedChanges);\r\n // Solo enviar los cambios filtrados junto con la PK\r\n const key = this.rowId();\r\n const updatePayload = {\r\n [key]: (row as Record<string, unknown>)[key],\r\n ...filteredChanges\r\n } as unknown as T;\r\n this.actionClick.emit({ action: 'update', row: updatePayload });\r\n this.cancelEdit();\r\n }\r\n }\r\n\r\n /**\r\n * Filtra los campos readOnly de los cambios para evitar enviarlos en las actualizaciones\r\n */\r\n private filterReadOnlyFields(changes: Partial<T>): Partial<T> {\r\n const columnsMap = new Map(this.columns().map(col => [col.accessor, col]));\r\n const filtered: Partial<T> = {};\r\n\r\n for (const [key, value] of Object.entries(changes)) {\r\n const col = columnsMap.get(key);\r\n // Solo incluir campos que no son readOnly\r\n if (!col?.readOnly) {\r\n (filtered as Record<string, unknown>)[key] = value;\r\n }\r\n }\r\n\r\n return filtered;\r\n } /**\r\n * Convierte todos los valores de una fila según los tipos definidos en las columnas\r\n * Asegura que los datos emitidos tengan el tipo correcto (integer, number, boolean, etc.)\r\n */\r\n private convertRowTypes(row: Partial<T>): Partial<T> {\r\n const converted: Record<string, unknown> = {};\r\n const columnsMap = new Map(this.columns().map(col => [col.accessor, col]));\r\n\r\n for (const [key, value] of Object.entries(row)) {\r\n const col = columnsMap.get(key);\r\n if (col) {\r\n converted[key] = this.dataConverter.convertCellValue(value, col);\r\n } else {\r\n converted[key] = value;\r\n }\r\n }\r\n\r\n return converted as Partial<T>;\r\n }\r\n\r\n /**\r\n * TrackBy function for ngFor to avoid DOM re-creation (NG0956 warning).\r\n */\r\n readonly trackById = (index: number, row: T): string | number =>\r\n trackById(index, row, this.rowId());\r\n\r\n /**\r\n * Verifica si una acción personalizada debe mostrarse para una fila específica\r\n */\r\n readonly shouldShowAction = shouldShowAction<T>;\r\n\r\n /**\r\n * Obtiene el tooltip de una acción\r\n */\r\n readonly getActionTooltip = getActionTooltip;\r\n\r\n /**\r\n * Maneja el click en una acción personalizada dinámica\r\n * UPDATE activa el modo edición, otras acciones emiten directamente\r\n * Si la acción tiene configuración de confirmación, muestra modal antes de ejecutar\r\n */\r\n onDynamicAction(action: CustomTableAction, row: T): void {\r\n if (action.name === 'update') {\r\n this.onEdit(row);\r\n return;\r\n }\r\n\r\n if (action.name === 'delete') {\r\n void this.onDelete(row);\r\n return;\r\n }\r\n\r\n if (action.name === 'cancel') {\r\n void this.onCancel(row);\r\n return;\r\n }\r\n\r\n // Si la acción tiene confirmación configurada, mostrar modal\r\n if (action.confirmation) {\r\n void this.handleActionWithConfirmation(action, row);\r\n return;\r\n }\r\n\r\n // Sin confirmación, emitir directamente\r\n this.actionClick.emit({ action: action.name, row });\r\n }\r\n\r\n /**\r\n * Maneja acciones que requieren confirmación del usuario\r\n */\r\n private async handleActionWithConfirmation(action: CustomTableAction, row: T): Promise<void> {\r\n if (!action.confirmation) return;\r\n\r\n const confirmed = await this.modalService.confirm({\r\n title: action.confirmation.title,\r\n message: action.confirmation.message,\r\n confirmText: action.confirmation.confirmText ?? 'Confirmar',\r\n cancelText: action.confirmation.cancelText ?? 'Cancelar'\r\n });\r\n\r\n if (confirmed) {\r\n this.actionClick.emit({ action: action.name, row });\r\n }\r\n }\r\n\r\n /**\r\n * Handles search input changes with debouncing\r\n */\r\n onSearchInput(event: Event): void {\r\n const target = event.target as HTMLInputElement;\r\n const value = target.value;\r\n this.searchValue.set(value);\r\n this.searchTerm.emit(value);\r\n }\r\n\r\n /**\r\n * Clears the search input\r\n */\r\n clearSearch(): void {\r\n this.searchValue.set('');\r\n this.searchTerm.emit('');\r\n }\r\n\r\n // Referencias readonly a métodos de servicios (evita wrappers innecesarios)\r\n readonly getCellValue = this.dataUtils.getCellValue.bind(this.dataUtils);\r\n readonly getDisplayValue = this.dataUtils.getDisplayValue.bind(this.dataUtils);\r\n readonly getEnumDisplayValue = this.dataUtils.getEnumDisplayValue.bind(this.dataUtils);\r\n readonly getEnumOptions = this.dataUtils.getEnumOptions.bind(this.dataUtils);\r\n readonly getCellColor = this.dataUtils.getCellColor.bind(this.dataUtils);\r\n\r\n /**\r\n * Selection methods\r\n */\r\n clearSelection(): void {\r\n this.selectionState.clearSelection();\r\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\r\n }\r\n\r\n /**\r\n * Mantiene la selección existente después de actualizar los datos,\r\n * eliminando solo los IDs que ya no existen en los nuevos datos\r\n */\r\n private preserveSelection(): void {\r\n this.selectionState.preserveSelection(this.data());\r\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\r\n }\r\n\r\n toggleSelectAll(): void {\r\n this.selectionState.toggleSelectAll(this.data());\r\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\r\n }\r\n\r\n toggleItemSelection(item: T): void {\r\n this.selectionState.toggleItemSelection(item, this.multiple());\r\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\r\n }\r\n\r\n isItemSelected(item: T): boolean {\r\n return this.selectionState.isItemSelected(item);\r\n }\r\n\r\n\r\n\r\n // Métodos de visibilidad delegados a servicio\r\n isColumnVisible(column: TableColDef): boolean {\r\n return this.visibilityService.isColumnVisible(column, this.data(), {\r\n creating: this.creating(),\r\n row: this.newRow() ?? undefined\r\n });\r\n }\r\n\r\n isColumnVisibleInHeader(column: TableColDef): boolean {\r\n return this.visibilityService.isColumnVisibleInHeader(\r\n column,\r\n { data: this.data(), creating: this.creating(), editing: this.editing() }\r\n );\r\n }\r\n\r\n isColumnVisibleForRow(column: TableColDef, row: T): boolean {\r\n return this.visibilityService.isColumnVisibleForRow(\r\n column,\r\n { row, data: this.data(), editing: this.editing() }\r\n );\r\n }\r\n\r\n // Métodos de paginación\r\n onPageChange(page: number): void {\r\n this.paginationState.setPage(page);\r\n this.emitPaginationChange();\r\n }\r\n\r\n onNextPage(): void {\r\n this.paginationState.nextPage();\r\n this.emitPaginationChange();\r\n }\r\n\r\n onPrevPage(): void {\r\n this.paginationState.prevPage();\r\n this.emitPaginationChange();\r\n }\r\n\r\n private emitPaginationChange(): void {\r\n const event: PaginationChangeEvent = {\r\n page: this.currentPage(),\r\n limit: this.pageSize(),\r\n offset: this.paginationState.offset()\r\n };\r\n this.paginationChange.emit(event);\r\n }\r\n\r\n /**\r\n * Actualiza el total de items para calcular páginas\r\n * Debe ser llamado por el componente padre después de recibir datos\r\n */\r\n updateTotalItems(total: number): void {\r\n this.paginationState.setTotalItems(total);\r\n }\r\n\r\n /**\r\n * Obtiene el color de una acción considerando el tema actual.\r\n * Si la acción tiene color explícito, lo usa. Si no, aplica color por tema.\r\n */\r\n getActionColor(action: CustomTableAction): string | undefined {\r\n // Delete siempre en rojo (color warn de Material)\r\n if (action.name === 'delete') {\r\n return undefined; // Deja que el atributo [color]=\"warn\" lo maneje\r\n }\r\n\r\n // Si la acción tiene color explícito (rojo/verde para toggles), respetarlo\r\n if (action.color) {\r\n return action.color;\r\n }\r\n\r\n // Para acciones sin color explícito, usar el color de dark mode\r\n return '#e9ecef';\r\n }\r\n}\r\n","<div class=\"table-responsive\" [style.max-height]=\"tableMaxHeight()\" [style.overflow-y]=\"size() > 0 ? 'auto' : 'visible'\">\r\n <!-- Search Bar -->\r\n @if (searchable()) {\r\n <div class=\"search-container\">\r\n <div class=\"search-input-wrapper\">\r\n <div class=\"input-group\">\r\n <span class=\"input-group-text\">\r\n <c80-icon icon=\"search\" [size]=\".65\" [button]=\"false\" />\r\n </span>\r\n <input type=\"text\" class=\"form-control search-input\" placeholder=\"Buscar...\" [value]=\"searchValue()\" (input)=\"onSearchInput($event)\" aria-label=\"Buscar en la tabla\" />\r\n @if (searchValue()) {\r\n <button class=\"btn btn-outline-secondary btn-borrar\" type=\"button\" (click)=\"clearSearch()\" title=\"Limpiar búsqueda\">\r\n <c80-icon icon=\"cancel\" [size]=\".6\" />\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <table class=\"table table-bordered table-hover align-middle\">\r\n <thead class=\"thead table-light sticky-header\">\r\n <tr>\r\n @if (allowSelection() && data().length !== 0) {\r\n <th class=\"text-center selection-column\">\r\n @if (multiple()) {\r\n <input type=\"checkbox\" [checked]=\"selectAllChecked()\" [indeterminate]=\"selectAllIndeterminate()\" (change)=\"toggleSelectAll()\" aria-label=\"Seleccionar todo\" />\r\n }\r\n </th>\r\n }\r\n @for (col of columns(); track col) {\r\n @if (isColumnVisibleInHeader(col)) {\r\n @if (col.type === 'boolean') {\r\n <th class=\"text-center boolean-column\">{{ col.label }}</th>\r\n }\r\n @else if (col.type === 'number' || col.type === 'integer') {\r\n <th class=\"text-center number-column\">{{ col.label }}</th>\r\n }\r\n @else if (col.type === 'date') {\r\n <th class=\"text-center date-column\">{{ col.label }}</th>\r\n }\r\n @else {\r\n <th>{{ col.label }}</th>\r\n }\r\n }\r\n }\r\n @if (hasAnyActions()) {\r\n <th class=\"table-actions-header\">\r\n <div class=\"actions-wrapper\">\r\n <span>Actions</span>\r\n @if (shouldShowCreateButton()) {\r\n <c80-icon button icon=\"add\" [disabled]=\"creating()\" title=\"Agregar\" [size]=\".6\" (iconClick)=\"startCreate()\" />\r\n }\r\n </div>\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (row of data(); track trackById(i, row); let i = $index) {\r\n <tr>\r\n @if (allowSelection() && data().length !== 0) {\r\n <td class=\"text-center selection-column\">\r\n <input type=\"checkbox\" [checked]=\"isItemSelected(row)\" (change)=\"toggleItemSelection(row)\" [attr.aria-label]=\"'Seleccionar fila ' + (i + 1)\" />\r\n </td>\r\n }\r\n @for (col of columns(); track col) {\r\n @if (isColumnVisibleForRow(col, row)) {\r\n @if (col.type === 'boolean') {\r\n <td class=\"text-center boolean-column\">\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n <input type=\"checkbox\" [checked]=\"!!editRow()?.[col.accessor]\" (change)=\"onEditInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\r\n }\r\n @else {\r\n @if (getCellValue(row, col.accessor) === true) {\r\n <c80-icon icon=\"check\" [size]=\".7\" />\r\n <br />\r\n }\r\n @else if (getCellValue(row, col.accessor) === false) {\r\n <c80-icon icon=\"cancel\" [size]=\".7\" />\r\n <br />\r\n }\r\n }\r\n </td>\r\n }\r\n @else if (col.type === 'number' || col.type === 'integer') {\r\n <td class=\"text-center number-column\">\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\r\n (input)=\"onEditInput($event, col.accessor, col)\" />\r\n }\r\n @else {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\r\n col.accessor), col) }}</span>\r\n }\r\n </td>\r\n }\r\n @else if (col.type === 'date') {\r\n <td class=\"text-center date-column\">\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n <input class=\"form-control form-control-sm\" type=\"datetime-local\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onEditInput($event, col.accessor, col)\" />\r\n }\r\n @else {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\r\n col.accessor), col) }}</span>\r\n }\r\n </td>\r\n }\r\n @else {\r\n <td>\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n @if (col.type === 'enum') {\r\n <select class=\"form-control form-control-sm\" [value]=\"editRow()?.[col.accessor] ?? ''\" (change)=\"onEditInput($event, col.accessor, col)\">\r\n <option value=\"\">{{ col.label }}</option>\r\n @for (option of getEnumOptions(col); track option.value) {\r\n <option [value]=\"option.value\">{{ option.label }}</option>\r\n }\r\n </select>\r\n }\r\n @else {\r\n <input class=\"form-control form-control-sm\" [type]=\"col.type === 'password' ? 'password' : 'text'\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onEditInput($event, col.accessor, col)\" />\r\n }\r\n }\r\n @else {\r\n @if (col.type === 'password') {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">******</span>\r\n }\r\n @else if (col.type === 'enum') {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{\r\n getEnumDisplayValue(getCellValue(row, col.accessor), col)\r\n }}</span>\r\n }\r\n @else if (getCellValue(row, col.accessor) === true) {\r\n <c80-icon icon=\"check\" [size]=\".7\" />\r\n }\r\n @else if (getCellValue(row, col.accessor) === false) {\r\n <c80-icon icon=\"cancel\" [size]=\".7\" />\r\n }\r\n @else {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\r\n col.accessor), col) }}</span>\r\n }\r\n }\r\n </td>\r\n }\r\n }\r\n }\r\n @if (hasAnyActions()) {\r\n <td class=\"text-end actions-cell\">\r\n <div class=\"actions-container\" [class.centered-actions]=\"editing() === row['id']\">\r\n @if (editing() === row['id']) {\r\n <!-- Modo edición: mostrar guardar y cancelar -->\r\n @if (hasCrudUpdate()) {\r\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\" [size]=\".7\" />\r\n }\r\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\" [size]=\".7\" />\r\n }\r\n @else {\r\n @for (action of customActions(); track action.name) {\r\n @if (shouldShowAction(action, row, data())) {\r\n <c80-icon button [icon]=\"action.icon\" [customColor]=\"getActionColor(action)\" [color]=\"action.name === 'delete' ? 'warn' : 'primary'\" [title]=\"getActionTooltip(action)\" (iconClick)=\"onDynamicAction(action, row)\" [size]=\".7\" />\r\n }\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (creating() && hasCrudCreate()) {\r\n <tr>\r\n @if (allowSelection() && data().length !== 0) {\r\n <td class=\"text-center selection-column\">\r\n <!-- Empty cell for alignment -->\r\n </td>\r\n }\r\n @for (col of columns(); track col) {\r\n @if (isColumnVisible(col)) {\r\n @if (col.type === 'boolean') {\r\n <td class=\"text-center\">\r\n @if (!col.readOnly) {\r\n <input type=\"checkbox\" [checked]=\"!!newRow()?.[col.accessor]\" (change)=\"onInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\r\n }\r\n @else {\r\n <!-- ReadOnly boolean column in create mode shows empty -->\r\n <span class=\"text-muted\">-</span>\r\n }\r\n </td>\r\n } @else if (col.type === 'number' || col.type === 'integer') {\r\n <td class=\"text-center number-column\">\r\n @if (!col.readOnly) {\r\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\r\n (input)=\"onInput($event, col.accessor, col)\" />\r\n }\r\n @else {\r\n <!-- ReadOnly number column in create mode shows empty -->\r\n <span class=\"text-muted\">-</span>\r\n }\r\n </td>\r\n } @else {\r\n <td>\r\n @if (!col.readOnly) {\r\n @if (col.type === 'enum') {\r\n <select class=\"form-control form-control-sm\" [value]=\"newRow()?.[col.accessor] ?? ''\" (change)=\"onInput($event, col.accessor, col)\">\r\n <option value=\"\">{{ col.label }}</option>\r\n @for (option of getEnumOptions(col); track option.value) {\r\n <option [value]=\"option.value\">{{ option.label }}</option>\r\n }\r\n </select>\r\n }\r\n @else {\r\n <input class=\"form-control form-control-sm\" type=\"text\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onInput($event, col.accessor, col)\" />\r\n }\r\n }\r\n @else {\r\n <!-- ReadOnly column in create mode shows empty -->\r\n <span class=\"text-muted\">-</span>\r\n }\r\n </td>\r\n }\r\n }\r\n }\r\n <td class=\"text-end actions-cell\">\r\n <div class=\"actions-container centered-actions\">\r\n @if (hasCrudCreate()) {\r\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveCreate()\" [size]=\".7\" />\r\n }\r\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelCreate()\" [size]=\".7\" />\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n @if (data().length === 0 && !creating()) {\r\n <div class=\"text-center text-muted py-3 small\">\r\n No hay datos para mostrar.\r\n </div>\r\n }\r\n\r\n <!-- Pagination Controls -->\r\n @if (paginated() && data().length > 0) {\r\n <div class=\"pagination-container\">\r\n <div class=\"pagination-info\">\r\n Página {{ currentPage() }} de {{ totalPages() }}\r\n </div>\r\n <div class=\"pagination-controls\">\r\n <button type=\"button\" class=\"btn btn-sm\" [disabled]=\"!hasPrevPage()\" (click)=\"onPrevPage()\" title=\"Página anterior\">\r\n <c80-icon icon=\"arrowLeft\" [size]=\".6\" [button]=\"false\" />\r\n </button>\r\n <button type=\"button\" class=\"btn btn-sm\" [disabled]=\"!hasNextPage()\" (click)=\"onNextPage()\" title=\"Página siguiente\">\r\n <c80-icon icon=\"arrowRight\" [size]=\".6\" [button]=\"false\" />\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n\r\n<c80-modal />"]}
1
+ {"version":3,"file":"table.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table.component.ts","../../../../../libs/ui/src/lib/table/table.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\r\n type OnInit,\r\n type OnDestroy,\r\n Component,\r\n ChangeDetectionStrategy,\r\n input,\r\n signal,\r\n computed,\r\n output,\r\n inject,\r\n effect,\r\n} from '@angular/core';\r\nimport type { Observable, Subscription } from 'rxjs';\r\nimport { IconComponent, THEME_DARK_COLOR } from '../icon';\r\nimport { TableColumnVisibilityService } from './table-column-visibility.service';\r\nimport { TableDataUtilsService } from './table-data-utils.service';\r\nimport { TableDataConverterService } from './table-data-converter.service';\r\nimport { TableSelectionService } from './table-selection.service';\r\nimport { TableCrudStateService } from './table-crud-state.service';\r\nimport { TablePaginationService } from './table-pagination.service';\r\nimport type { TableColDef, CustomTableAction, PaginationChangeEvent, PaginationConfig } from './table.types';\r\nimport { ModalComponent, ModalService } from '../modal';\r\nimport {\r\n booleanAttribute,\r\n getErrorMessage,\r\n getInputValue,\r\n trackById,\r\n shouldShowAction,\r\n getActionTooltip,\r\n} from './table.utils';\r\n\r\n/**\r\n * C80TableComponent - Componente de tabla avanzado con funcionalidades CRUD\r\n *\r\n * COMPORTAMIENTO DE VISIBILIDAD DE COLUMNAS:\r\n * ========================================\r\n *\r\n * 1. PRIORIDAD MÁXIMA - visible: false\r\n * - La columna se oculta SIEMPRE, sin excepciones\r\n * - Ni en modo creación ni en modo edición se muestra\r\n *\r\n * 2. OCULTACIÓN AUTOMÁTICA - hideIfAllValuesAreNull: true\r\n * - La columna se oculta solo si TODOS los valores actuales están vacíos\r\n * - Valores considerados vacíos: null, undefined, '', [], {}\r\n * - Valores NO vacíos: 0, false (son valores válidos)\r\n * - EXCEPCIONES IMPORTANTES:\r\n * * En modo creación (creating=true) estas columnas SÍ se muestran\r\n * * En modo edición de una fila específica se muestran SOLO si esa fila tiene valor\r\n *\r\n * 3. POR DEFECTO - Columnas normales\r\n * - Se muestran siempre (visualización, creación y edición)\r\n *\r\n * VALORES POR DEFECTO EN CREACIÓN:\r\n * ===============================\r\n *\r\n * - Propiedad `default?: unknown` permite definir valores por defecto para modo creación\r\n * - Solo se aplica cuando se inicia el modo creación (startCreate)\r\n * - Puede ser cualquier tipo: string, number, boolean, etc.\r\n * - Si no se especifica `default`, se usa cadena vacía ('')\r\n *\r\n * VALORES DINÁMICOS EN CREACIÓN Y EDICIÓN:\r\n * =======================================\r\n *\r\n * - Input `inputValues$?: Observable<Partial<T>>` permite actualizar valores dinámicamente\r\n * - Solo se aplica durante modo creación (creating=true) o edición (editing!=null)\r\n * - Los valores se aplican automáticamente cuando el Observable emite\r\n * - Permite cambios múltiples durante el mismo modo de creación/edición\r\n * - Los nuevos valores sobrescriben los existentes (spread operator)\r\n *\r\n * TIPOS DE DATOS SOPORTADOS:\r\n * =========================\r\n *\r\n * - 'string': Texto normal (default)\r\n * - 'number': Números decimales (preserva decimales: 5.3 → 5.3)\r\n * - 'integer': Números enteros (convierte a entero: 5.3 → 5)\r\n * - 'boolean': Verdadero/Falso (checkbox)\r\n * - 'password': Texto oculto (input type=\"password\")\r\n * - 'enum': Lista de opciones predefinidas (select)\r\n *\r\n * SISTEMA DE ACCIONES UNIFICADO (customActions):\r\n * =============================================\r\n *\r\n * Input: `customActions: CustomTableAction[]` - Array de acciones dinámicas\r\n * Output: `(actionClick)` - Evento unificado que emite { action: string, row: T }\r\n *\r\n * ACCIONES CRUD PREDEFINIDAS (TABLE_CRUD_ACTIONS):\r\n * ------------------------------------------------\r\n * - CREATE: Solo aparece como botón \"+\" en header (no en filas)\r\n * - UPDATE: Activa modo edición (muestra inputs), botón \"✓\" guarda cambios\r\n * - DELETE: Muestra confirmación y emite evento delete\r\n * - CANCEL: Muestra confirmación y emite evento cancel (opcional)\r\n *\r\n * ACCIONES PERSONALIZADAS (Custom Actions):\r\n * -----------------------------------------\r\n * Interfaz: { name: string, icon: IconType, condition?: (row) => boolean, tooltip?: string }\r\n * - name: ID único de la acción\r\n * - icon: Icono del botón (ej: 'settings', 'upload', 'refresh')\r\n * - condition: Función opcional para mostrar/ocultar según estado de fila\r\n * - tooltip: Texto al hacer hover (default: name)\r\n *\r\n * MANEJO EN COMPONENTE:\r\n * --------------------\r\n * ```typescript\r\n * // 1. Definir acciones en constants:\r\n * export const ENTITY_TABLE_ACTIONS: CustomTableAction[] = [\r\n * TABLE_CRUD_ACTIONS.CREATE,\r\n * TABLE_CRUD_ACTIONS.UPDATE,\r\n * { name: 'custom-action', icon: 'settings', tooltip: 'Configurar' },\r\n * TABLE_CRUD_ACTIONS.DELETE\r\n * ];\r\n *\r\n * // 2. En el componente:\r\n * readonly tableActions = ENTITY_TABLE_ACTIONS;\r\n *\r\n * handleAction({ action, row }) {\r\n * const entity = row as unknown as EntityType;\r\n * switch (action) {\r\n * case 'create': this.onCreate(row); break;\r\n * case 'update': this.onUpdate(entity); break;\r\n * case 'delete': this.onDelete(entity.id); break;\r\n * case 'custom-action': this.onCustom(entity); break;\r\n * }\r\n * }\r\n * ```\r\n *\r\n * ACCIONES CON CONDICIÓN:\r\n * ----------------------\r\n * ```typescript\r\n * {\r\n * name: 'enable',\r\n * icon: 'toggleOn',\r\n * tooltip: 'Habilitar',\r\n * condition: (row) => row['enabled'] === false\r\n * }\r\n * ```\r\n *\r\n * CONSTANTES REUTILIZABLES:\r\n * ------------------------\r\n * - TABLE_CRUD_ACTIONS: Objeto con CREATE, UPDATE, DELETE, CANCEL\r\n * - BASIC_CRUD_ACTIONS: Array con [CREATE, UPDATE, DELETE]\r\n * Importar desde: `@shared` o `@shared/constants`\r\n *\r\n * EJEMPLOS COMPLETOS:\r\n * ------------------\r\n * - { accessor: 'id', visible: false } → NUNCA se muestra\r\n * - { accessor: 'motorPos', hideIfAllValuesAreNull: true, default: 0, type: 'integer' } → Entero (5.7 → 5)\r\n * - { accessor: 'weight', type: 'number', default: 2.5 } → Decimal preservado (5.7 → 5.7)\r\n * - { accessor: 'status', default: 'active' } → Se autorellena con 'active' en creación\r\n * - { accessor: 'name' } → Siempre visible, sin valor por defecto (cadena vacía)\r\n * - inputValues$ emite { motorPos: 5, weight: 2.3 } → actualiza inputs dinámicamente\r\n * - customActions con CREATE → Muestra botón \"+\" en header\r\n * - customActions con UPDATE → Botón \"edit\" activa modo edición\r\n * - customActions con custom → Botón personalizado emite evento\r\n */@Component({\r\n selector: 'c80-table',\r\n imports: [IconComponent, ModalComponent],\r\n templateUrl: './table.component.html',\r\n styleUrl: './table.component.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush\r\n})\r\nexport class TableComponent<T extends Record<string, unknown>> implements OnInit, OnDestroy {\r\n // Servicios inyectados\r\n private readonly modalService = inject(ModalService);\r\n private readonly visibilityService = inject(TableColumnVisibilityService);\r\n private readonly dataUtils = inject(TableDataUtilsService);\r\n private readonly dataConverter = inject(TableDataConverterService);\r\n private readonly selectionService = inject(TableSelectionService);\r\n private readonly crudService = inject(TableCrudStateService);\r\n private readonly paginationService = inject(TablePaginationService);\r\n\r\n // Inputs\r\n readonly data$ = input.required<Observable<T[]>>();\r\n readonly columns = input<TableColDef[]>([]);\r\n readonly inputValues$ = input<Observable<Partial<T>>>(); // Observable para actualizar valores de inputs dinámicamente en creación/edición\r\n readonly customActions = input<CustomTableAction[]>([]); // Acciones personalizadas dinámicas\r\n readonly size = input(0); // Tamaño de la tabla (0 = sin límite, > 0 aplica max-height)\r\n readonly multiple = input(true); // Permite selección múltiple por defecto\r\n readonly rowId = input('id'); // Accessor de la PK de cada fila (default 'id'); usar si la entidad no usa 'id'\r\n readonly searchable = input(false, { transform: booleanAttribute }); // Si es true, muestra barra de búsqueda\r\n readonly allowSelection = input(false, { transform: booleanAttribute }); // Si es true, permite selección de filas\r\n readonly noConfirm = input(false, { transform: booleanAttribute }); // Si es true, no muestra confirmaciones modales\r\n readonly paginated = input(false, { transform: booleanAttribute }); // Si es true, habilita paginación con limit/offset\r\n readonly paginationConfig = input<PaginationConfig>({ pageSize: 10 }); // Configuración de paginación (tamaño de página, total items)\r\n\r\n // Outputs - Acciones unificadas (Angular 18+ output API)\r\n readonly actionClick = output<{ action: string; row: T }>(); // Output unificado para TODAS las acciones (CRUD + custom)\r\n\r\n // Outputs - Utilidades\r\n readonly searchTerm = output<string>();\r\n readonly errorEvent = output<string>();\r\n readonly selectable = output<T[]>();\r\n readonly paginationChange = output<PaginationChangeEvent>(); // Output para cambios de paginación (page, limit, offset)\r\n\r\n // Estado principal\r\n readonly data = signal<T[]>([]);\r\n readonly searchValue = signal<string>('');\r\n\r\n // Estado de selección (delegado a servicio)\r\n private readonly selectionState = this.selectionService.createSelectionState<T>(\r\n (item) => item[this.rowId()] as string\r\n );\r\n readonly selectedItems = this.selectionState.selectedItems;\r\n readonly selectAllChecked = this.selectionState.selectAllChecked;\r\n readonly selectAllIndeterminate = this.selectionState.selectAllIndeterminate;\r\n\r\n // Estado CRUD (delegado a servicio)\r\n private readonly crudState = this.crudService.createCrudState<T>();\r\n readonly creating = this.crudState.creating;\r\n readonly newRow = this.crudState.newRow;\r\n readonly editing = this.crudState.editing;\r\n readonly editRow = this.crudState.editRow;\r\n\r\n // Estado de paginación (delegado a servicio)\r\n private readonly paginationState = this.paginationService.createPaginationState(\r\n this.paginationConfig().pageSize ?? 10\r\n );\r\n readonly currentPage = this.paginationState.currentPage;\r\n readonly pageSize = this.paginationState.pageSize;\r\n readonly totalPages = this.paginationState.totalPages;\r\n readonly hasNextPage = this.paginationState.hasNextPage;\r\n readonly hasPrevPage = this.paginationState.hasPrevPage;\r\n\r\n // Keys visibles computed automáticamente\r\n readonly keys = computed(() =>\r\n this.visibilityService.updateVisibleKeys(\r\n this.columns(),\r\n { data: this.data(), creating: this.creating(), editing: this.editing() }\r\n )\r\n );\r\n\r\n // Computed - Detecta acciones CRUD y custom\r\n readonly hasAnyActions = computed(() => this.customActions().length > 0);\r\n readonly hasCrudCreate = computed(() => this.customActions().some(a => a.name === 'create'));\r\n readonly hasCrudUpdate = computed(() => this.customActions().some(a => a.name === 'update'));\r\n readonly hasCrudDelete = computed(() => this.customActions().some(a => a.name === 'delete'));\r\n readonly hasCrudCancel = computed(() => this.customActions().some(a => a.name === 'cancel'));\r\n\r\n readonly shouldShowCreateButton = computed(() => {\r\n const createAction = this.customActions().find(a => a.name === 'create');\r\n if (!createAction) return false;\r\n return !createAction.condition || createAction.condition({} as Record<string, unknown>, this.data());\r\n });\r\n\r\n // Table max height computed\r\n readonly tableMaxHeight = computed(() =>\r\n this.dataUtils.getTableMaxHeight(this.size())\r\n );\r\n\r\n private dataSub?: Subscription;\r\n private inputValuesSub?: Subscription;\r\n\r\n constructor() {\r\n // Sincronizar totalItems del paginationConfig con el estado de paginación\r\n effect(() => {\r\n const config = this.paginationConfig();\r\n if (config.totalItems !== undefined && this.paginated()) {\r\n this.paginationState.setTotalItems(config.totalItems);\r\n }\r\n });\r\n\r\n // Sincronizar pageSize del paginationConfig: los signal inputs se ligan\r\n // DESPUÉS de la construcción, así que el estado se inicializa con el default;\r\n // este effect reaplica el pageSize real del padre cuando cambia (sin resetear\r\n // la página por otros cambios del config como totalItems).\r\n let lastPageSize: number | undefined;\r\n effect(() => {\r\n const size = this.paginationConfig().pageSize ?? 10;\r\n if (size !== lastPageSize) {\r\n lastPageSize = size;\r\n this.paginationState.setPageSize(size);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Maneja input de creación/edición de forma unificada\r\n */\r\n private handleInput(options: {\r\n event: Event;\r\n key: string;\r\n col: TableColDef | undefined;\r\n isEdit: boolean;\r\n }): void {\r\n const { event, key, col, isEdit } = options;\r\n const updateFn = isEdit\r\n ? this.crudState.updateEditRow.bind(this.crudState)\r\n : this.crudState.updateNewRow.bind(this.crudState);\r\n\r\n const value = getInputValue(event, col);\r\n if (value !== undefined) {\r\n updateFn(key, value);\r\n }\r\n }\r\n\r\n /**\r\n * Maneja confirmación modal de forma genérica\r\n */\r\n private async handleConfirmAction(options: {\r\n title: string;\r\n message: string;\r\n confirmText: string;\r\n action: () => void;\r\n }): Promise<void> {\r\n const { title, message, confirmText, action } = options;\r\n if (this.noConfirm()) {\r\n action();\r\n return;\r\n }\r\n\r\n const confirmed = await this.modalService.confirm({\r\n title,\r\n message,\r\n confirmText,\r\n cancelText: 'Cancelar'\r\n });\r\n\r\n if (confirmed) {\r\n action();\r\n }\r\n }\r\n\r\n\r\n\r\n ngOnInit(): void {\r\n const data$ = this.data$();\r\n if (!data$) return;\r\n this.dataSub = data$.subscribe({\r\n next: (items) => {\r\n this.dataUtils.applySorting(items, this.columns());\r\n this.data.set(items);\r\n this.preserveSelection();\r\n },\r\n error: (err: unknown) =>\r\n this.errorEvent.emit(getErrorMessage(err)),\r\n });\r\n\r\n // Suscribirse a inputValues$ para actualizar valores dinámicamente en creación/edición\r\n const inputValues$ = this.inputValues$();\r\n if (inputValues$) {\r\n this.inputValuesSub = inputValues$.subscribe({\r\n next: (partialValues) => {\r\n this.crudState.applyInputValues(partialValues);\r\n },\r\n error: (err: unknown) =>\r\n console.warn('Error en inputValues$:', getErrorMessage(err)),\r\n });\r\n }\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.dataSub?.unsubscribe();\r\n this.inputValuesSub?.unsubscribe();\r\n\r\n // Close any open modal when component is destroyed\r\n this.modalService.closeModal();\r\n }\r\n\r\n onInput(event: Event, key: string, col?: TableColDef): void {\r\n this.handleInput({ event, key, col, isEdit: false });\r\n }\r\n\r\n onEditInput(event: Event, key: string, col?: TableColDef): void {\r\n this.handleInput({ event, key, col, isEdit: true });\r\n }\r\n\r\n async onDelete(row: T): Promise<void> {\r\n await this.handleConfirmAction({\r\n title: 'Confirmar eliminación',\r\n message: '¿Está seguro de que desea eliminar este elemento? Esta acción no se puede deshacer.',\r\n confirmText: 'Eliminar',\r\n action: () => this.actionClick.emit({ action: 'delete', row })\r\n });\r\n }\r\n\r\n async onCancel(row: T): Promise<void> {\r\n await this.handleConfirmAction({\r\n title: 'Confirmar cancelación',\r\n message: '¿Está seguro de que desea cancelar este elemento?',\r\n confirmText: 'Cancelar elemento',\r\n action: () => this.actionClick.emit({ action: 'cancel', row })\r\n });\r\n }\r\n\r\n startCreate(): void {\r\n this.crudState.startCreate({ columns: this.columns(), data: this.data() });\r\n }\r\n\r\n cancelCreate(): void {\r\n this.crudState.cancelCreate();\r\n }\r\n\r\n saveCreate(): void {\r\n const current = this.newRow();\r\n if (current) {\r\n const convertedRow = this.convertRowTypes(current);\r\n const filteredRow = this.filterReadOnlyFields(convertedRow);\r\n this.actionClick.emit({ action: 'create', row: filteredRow as T });\r\n this.cancelCreate();\r\n }\r\n }\r\n\r\n onEdit(row: T): void {\r\n this.crudState.startEdit({ row, columns: this.columns(), data: this.data() });\r\n }\r\n\r\n cancelEdit(): void {\r\n this.crudState.cancelEdit();\r\n }\r\n\r\n saveEdit(row: T): void {\r\n const changes = this.editRow();\r\n if (changes) {\r\n const convertedChanges = this.convertRowTypes(changes);\r\n const filteredChanges = this.filterReadOnlyFields(convertedChanges);\r\n // Solo enviar los cambios filtrados junto con la PK\r\n const key = this.rowId();\r\n const updatePayload = {\r\n [key]: (row as Record<string, unknown>)[key],\r\n ...filteredChanges\r\n } as unknown as T;\r\n this.actionClick.emit({ action: 'update', row: updatePayload });\r\n this.cancelEdit();\r\n }\r\n }\r\n\r\n /**\r\n * Filtra los campos readOnly de los cambios para evitar enviarlos en las actualizaciones\r\n */\r\n private filterReadOnlyFields(changes: Partial<T>): Partial<T> {\r\n const columnsMap = new Map(this.columns().map(col => [col.accessor, col]));\r\n const filtered: Partial<T> = {};\r\n\r\n for (const [key, value] of Object.entries(changes)) {\r\n const col = columnsMap.get(key);\r\n // Solo incluir campos que no son readOnly\r\n if (!col?.readOnly) {\r\n (filtered as Record<string, unknown>)[key] = value;\r\n }\r\n }\r\n\r\n return filtered;\r\n } /**\r\n * Convierte todos los valores de una fila según los tipos definidos en las columnas\r\n * Asegura que los datos emitidos tengan el tipo correcto (integer, number, boolean, etc.)\r\n */\r\n private convertRowTypes(row: Partial<T>): Partial<T> {\r\n const converted: Record<string, unknown> = {};\r\n const columnsMap = new Map(this.columns().map(col => [col.accessor, col]));\r\n\r\n for (const [key, value] of Object.entries(row)) {\r\n const col = columnsMap.get(key);\r\n if (col) {\r\n converted[key] = this.dataConverter.convertCellValue(value, col);\r\n } else {\r\n converted[key] = value;\r\n }\r\n }\r\n\r\n return converted as Partial<T>;\r\n }\r\n\r\n /**\r\n * TrackBy function for ngFor to avoid DOM re-creation (NG0956 warning).\r\n */\r\n readonly trackById = (index: number, row: T): string | number =>\r\n trackById(index, row, this.rowId());\r\n\r\n /**\r\n * Verifica si una acción personalizada debe mostrarse para una fila específica\r\n */\r\n readonly shouldShowAction = shouldShowAction<T>;\r\n\r\n /**\r\n * Obtiene el tooltip de una acción\r\n */\r\n readonly getActionTooltip = getActionTooltip;\r\n\r\n /**\r\n * Maneja el click en una acción personalizada dinámica\r\n * UPDATE activa el modo edición, otras acciones emiten directamente\r\n * Si la acción tiene configuración de confirmación, muestra modal antes de ejecutar\r\n */\r\n onDynamicAction(action: CustomTableAction, row: T): void {\r\n if (action.name === 'update') {\r\n this.onEdit(row);\r\n return;\r\n }\r\n\r\n if (action.name === 'delete') {\r\n void this.onDelete(row);\r\n return;\r\n }\r\n\r\n if (action.name === 'cancel') {\r\n void this.onCancel(row);\r\n return;\r\n }\r\n\r\n // Si la acción tiene confirmación configurada, mostrar modal\r\n if (action.confirmation) {\r\n void this.handleActionWithConfirmation(action, row);\r\n return;\r\n }\r\n\r\n // Sin confirmación, emitir directamente\r\n this.actionClick.emit({ action: action.name, row });\r\n }\r\n\r\n /**\r\n * Maneja acciones que requieren confirmación del usuario\r\n */\r\n private async handleActionWithConfirmation(action: CustomTableAction, row: T): Promise<void> {\r\n if (!action.confirmation) return;\r\n\r\n const confirmed = await this.modalService.confirm({\r\n title: action.confirmation.title,\r\n message: action.confirmation.message,\r\n confirmText: action.confirmation.confirmText ?? 'Confirmar',\r\n cancelText: action.confirmation.cancelText ?? 'Cancelar'\r\n });\r\n\r\n if (confirmed) {\r\n this.actionClick.emit({ action: action.name, row });\r\n }\r\n }\r\n\r\n /**\r\n * Handles search input changes with debouncing\r\n */\r\n onSearchInput(event: Event): void {\r\n const target = event.target as HTMLInputElement;\r\n const value = target.value;\r\n this.searchValue.set(value);\r\n this.searchTerm.emit(value);\r\n }\r\n\r\n /**\r\n * Clears the search input\r\n */\r\n clearSearch(): void {\r\n this.searchValue.set('');\r\n this.searchTerm.emit('');\r\n }\r\n\r\n // Referencias readonly a métodos de servicios (evita wrappers innecesarios)\r\n readonly getCellValue = this.dataUtils.getCellValue.bind(this.dataUtils);\r\n readonly getDisplayValue = this.dataUtils.getDisplayValue.bind(this.dataUtils);\r\n readonly getEnumDisplayValue = this.dataUtils.getEnumDisplayValue.bind(this.dataUtils);\r\n readonly getEnumOptions = this.dataUtils.getEnumOptions.bind(this.dataUtils);\r\n readonly getCellColor = this.dataUtils.getCellColor.bind(this.dataUtils);\r\n\r\n /**\r\n * Selection methods\r\n */\r\n clearSelection(): void {\r\n this.selectionState.clearSelection();\r\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\r\n }\r\n\r\n /**\r\n * Mantiene la selección existente después de actualizar los datos,\r\n * eliminando solo los IDs que ya no existen en los nuevos datos\r\n */\r\n private preserveSelection(): void {\r\n this.selectionState.preserveSelection(this.data());\r\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\r\n }\r\n\r\n toggleSelectAll(): void {\r\n this.selectionState.toggleSelectAll(this.data());\r\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\r\n }\r\n\r\n toggleItemSelection(item: T): void {\r\n this.selectionState.toggleItemSelection(item, this.multiple());\r\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\r\n }\r\n\r\n isItemSelected(item: T): boolean {\r\n return this.selectionState.isItemSelected(item);\r\n }\r\n\r\n\r\n\r\n // Métodos de visibilidad delegados a servicio\r\n isColumnVisible(column: TableColDef): boolean {\r\n return this.visibilityService.isColumnVisible(column, this.data(), {\r\n creating: this.creating(),\r\n row: this.newRow() ?? undefined\r\n });\r\n }\r\n\r\n isColumnVisibleInHeader(column: TableColDef): boolean {\r\n return this.visibilityService.isColumnVisibleInHeader(\r\n column,\r\n { data: this.data(), creating: this.creating(), editing: this.editing() }\r\n );\r\n }\r\n\r\n isColumnVisibleForRow(column: TableColDef, row: T): boolean {\r\n return this.visibilityService.isColumnVisibleForRow(\r\n column,\r\n { row, data: this.data(), editing: this.editing() }\r\n );\r\n }\r\n\r\n // Métodos de paginación\r\n onPageChange(page: number): void {\r\n this.paginationState.setPage(page);\r\n this.emitPaginationChange();\r\n }\r\n\r\n onNextPage(): void {\r\n this.paginationState.nextPage();\r\n this.emitPaginationChange();\r\n }\r\n\r\n onPrevPage(): void {\r\n this.paginationState.prevPage();\r\n this.emitPaginationChange();\r\n }\r\n\r\n private emitPaginationChange(): void {\r\n const event: PaginationChangeEvent = {\r\n page: this.currentPage(),\r\n limit: this.pageSize(),\r\n offset: this.paginationState.offset()\r\n };\r\n this.paginationChange.emit(event);\r\n }\r\n\r\n /**\r\n * Actualiza el total de items para calcular páginas\r\n * Debe ser llamado por el componente padre después de recibir datos\r\n */\r\n updateTotalItems(total: number): void {\r\n this.paginationState.setTotalItems(total);\r\n }\r\n\r\n /**\r\n * Obtiene el color de una acción considerando el tema actual.\r\n * Si la acción tiene color explícito, lo usa. Si no, aplica color por tema.\r\n */\r\n getActionColor(action: CustomTableAction): string | undefined {\r\n // Delete siempre en rojo (color warn de Material)\r\n if (action.name === 'delete') {\r\n return undefined; // Deja que el atributo [color]=\"warn\" lo maneje\r\n }\r\n\r\n // Si la acción tiene color explícito (rojo/verde para toggles), respetarlo\r\n if (action.color) {\r\n return action.color;\r\n }\r\n\r\n // Para acciones sin color explícito, usar el color de dark mode\r\n return THEME_DARK_COLOR;\r\n }\r\n}\r\n","<div class=\"table-responsive\" [style.max-height]=\"tableMaxHeight()\" [style.overflow-y]=\"size() > 0 ? 'auto' : 'visible'\">\r\n <!-- Search Bar -->\r\n @if (searchable()) {\r\n <div class=\"search-container\">\r\n <div class=\"search-input-wrapper\">\r\n <div class=\"input-group\">\r\n <span class=\"input-group-text\">\r\n <c80-icon icon=\"search\" [size]=\".65\" [button]=\"false\" />\r\n </span>\r\n <input type=\"text\" class=\"form-control search-input\" placeholder=\"Buscar...\" [value]=\"searchValue()\" (input)=\"onSearchInput($event)\" aria-label=\"Buscar en la tabla\" />\r\n @if (searchValue()) {\r\n <button class=\"btn btn-outline-secondary btn-borrar\" type=\"button\" (click)=\"clearSearch()\" title=\"Limpiar búsqueda\">\r\n <c80-icon icon=\"cancel\" [size]=\".6\" />\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <table class=\"table table-bordered table-hover align-middle\">\r\n <thead class=\"thead table-light sticky-header\">\r\n <tr>\r\n @if (allowSelection() && data().length !== 0) {\r\n <th class=\"text-center selection-column\">\r\n @if (multiple()) {\r\n <input type=\"checkbox\" [checked]=\"selectAllChecked()\" [indeterminate]=\"selectAllIndeterminate()\" (change)=\"toggleSelectAll()\" aria-label=\"Seleccionar todo\" />\r\n }\r\n </th>\r\n }\r\n @for (col of columns(); track col) {\r\n @if (isColumnVisibleInHeader(col)) {\r\n @if (col.type === 'boolean') {\r\n <th class=\"text-center boolean-column\">{{ col.label }}</th>\r\n }\r\n @else if (col.type === 'number' || col.type === 'integer') {\r\n <th class=\"text-center number-column\">{{ col.label }}</th>\r\n }\r\n @else if (col.type === 'date') {\r\n <th class=\"text-center date-column\">{{ col.label }}</th>\r\n }\r\n @else {\r\n <th>{{ col.label }}</th>\r\n }\r\n }\r\n }\r\n @if (hasAnyActions()) {\r\n <th class=\"table-actions-header\">\r\n <div class=\"actions-wrapper\">\r\n <span>Actions</span>\r\n @if (shouldShowCreateButton()) {\r\n <c80-icon button icon=\"add\" [disabled]=\"creating()\" title=\"Agregar\" [size]=\".6\" (iconClick)=\"startCreate()\" />\r\n }\r\n </div>\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (row of data(); track trackById(i, row); let i = $index) {\r\n <tr>\r\n @if (allowSelection() && data().length !== 0) {\r\n <td class=\"text-center selection-column\">\r\n <input type=\"checkbox\" [checked]=\"isItemSelected(row)\" (change)=\"toggleItemSelection(row)\" [attr.aria-label]=\"'Seleccionar fila ' + (i + 1)\" />\r\n </td>\r\n }\r\n @for (col of columns(); track col) {\r\n @if (isColumnVisibleForRow(col, row)) {\r\n @if (col.type === 'boolean') {\r\n <td class=\"text-center boolean-column\">\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n <input type=\"checkbox\" [checked]=\"!!editRow()?.[col.accessor]\" (change)=\"onEditInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\r\n }\r\n @else {\r\n @if (getCellValue(row, col.accessor) === true) {\r\n <c80-icon icon=\"check\" [size]=\".7\" />\r\n <br />\r\n }\r\n @else if (getCellValue(row, col.accessor) === false) {\r\n <c80-icon icon=\"cancel\" [size]=\".7\" />\r\n <br />\r\n }\r\n }\r\n </td>\r\n }\r\n @else if (col.type === 'number' || col.type === 'integer') {\r\n <td class=\"text-center number-column\">\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\r\n (input)=\"onEditInput($event, col.accessor, col)\" />\r\n }\r\n @else {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\r\n col.accessor), col) }}</span>\r\n }\r\n </td>\r\n }\r\n @else if (col.type === 'date') {\r\n <td class=\"text-center date-column\">\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n <input class=\"form-control form-control-sm\" type=\"datetime-local\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onEditInput($event, col.accessor, col)\" />\r\n }\r\n @else {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\r\n col.accessor), col) }}</span>\r\n }\r\n </td>\r\n }\r\n @else {\r\n <td>\r\n @if (editing() === row['id'] && !col.readOnly) {\r\n @if (col.type === 'enum') {\r\n <select class=\"form-control form-control-sm\" [value]=\"editRow()?.[col.accessor] ?? ''\" (change)=\"onEditInput($event, col.accessor, col)\">\r\n <option value=\"\">{{ col.label }}</option>\r\n @for (option of getEnumOptions(col); track option.value) {\r\n <option [value]=\"option.value\">{{ option.label }}</option>\r\n }\r\n </select>\r\n }\r\n @else {\r\n <input class=\"form-control form-control-sm\" [type]=\"col.type === 'password' ? 'password' : 'text'\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onEditInput($event, col.accessor, col)\" />\r\n }\r\n }\r\n @else {\r\n @if (col.type === 'password') {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">******</span>\r\n }\r\n @else if (col.type === 'enum') {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{\r\n getEnumDisplayValue(getCellValue(row, col.accessor), col)\r\n }}</span>\r\n }\r\n @else if (getCellValue(row, col.accessor) === true) {\r\n <c80-icon icon=\"check\" [size]=\".7\" />\r\n }\r\n @else if (getCellValue(row, col.accessor) === false) {\r\n <c80-icon icon=\"cancel\" [size]=\".7\" />\r\n }\r\n @else {\r\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\r\n col.accessor), col) }}</span>\r\n }\r\n }\r\n </td>\r\n }\r\n }\r\n }\r\n @if (hasAnyActions()) {\r\n <td class=\"text-end actions-cell\">\r\n <div class=\"actions-container\" [class.centered-actions]=\"editing() === row['id']\">\r\n @if (editing() === row['id']) {\r\n <!-- Modo edición: mostrar guardar y cancelar -->\r\n @if (hasCrudUpdate()) {\r\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\" [size]=\".7\" />\r\n }\r\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\" [size]=\".7\" />\r\n }\r\n @else {\r\n @for (action of customActions(); track action.name) {\r\n @if (shouldShowAction(action, row, data())) {\r\n <c80-icon button [icon]=\"action.icon\" [customColor]=\"getActionColor(action)\" [color]=\"action.name === 'delete' ? 'warn' : 'primary'\" [title]=\"getActionTooltip(action)\" (iconClick)=\"onDynamicAction(action, row)\" [size]=\".7\" />\r\n }\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (creating() && hasCrudCreate()) {\r\n <tr>\r\n @if (allowSelection() && data().length !== 0) {\r\n <td class=\"text-center selection-column\">\r\n <!-- Empty cell for alignment -->\r\n </td>\r\n }\r\n @for (col of columns(); track col) {\r\n @if (isColumnVisible(col)) {\r\n @if (col.type === 'boolean') {\r\n <td class=\"text-center\">\r\n @if (!col.readOnly) {\r\n <input type=\"checkbox\" [checked]=\"!!newRow()?.[col.accessor]\" (change)=\"onInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\r\n }\r\n @else {\r\n <!-- ReadOnly boolean column in create mode shows empty -->\r\n <span class=\"text-muted\">-</span>\r\n }\r\n </td>\r\n } @else if (col.type === 'number' || col.type === 'integer') {\r\n <td class=\"text-center number-column\">\r\n @if (!col.readOnly) {\r\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\r\n (input)=\"onInput($event, col.accessor, col)\" />\r\n }\r\n @else {\r\n <!-- ReadOnly number column in create mode shows empty -->\r\n <span class=\"text-muted\">-</span>\r\n }\r\n </td>\r\n } @else {\r\n <td>\r\n @if (!col.readOnly) {\r\n @if (col.type === 'enum') {\r\n <select class=\"form-control form-control-sm\" [value]=\"newRow()?.[col.accessor] ?? ''\" (change)=\"onInput($event, col.accessor, col)\">\r\n <option value=\"\">{{ col.label }}</option>\r\n @for (option of getEnumOptions(col); track option.value) {\r\n <option [value]=\"option.value\">{{ option.label }}</option>\r\n }\r\n </select>\r\n }\r\n @else {\r\n <input class=\"form-control form-control-sm\" type=\"text\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onInput($event, col.accessor, col)\" />\r\n }\r\n }\r\n @else {\r\n <!-- ReadOnly column in create mode shows empty -->\r\n <span class=\"text-muted\">-</span>\r\n }\r\n </td>\r\n }\r\n }\r\n }\r\n <td class=\"text-end actions-cell\">\r\n <div class=\"actions-container centered-actions\">\r\n @if (hasCrudCreate()) {\r\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveCreate()\" [size]=\".7\" />\r\n }\r\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelCreate()\" [size]=\".7\" />\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n @if (data().length === 0 && !creating()) {\r\n <div class=\"text-center text-muted py-3 small\">\r\n No hay datos para mostrar.\r\n </div>\r\n }\r\n\r\n <!-- Pagination Controls -->\r\n @if (paginated() && data().length > 0) {\r\n <div class=\"pagination-container\">\r\n <div class=\"pagination-info\">\r\n Página {{ currentPage() }} de {{ totalPages() }}\r\n </div>\r\n <div class=\"pagination-controls\">\r\n <button type=\"button\" class=\"btn btn-sm\" [disabled]=\"!hasPrevPage()\" (click)=\"onPrevPage()\" title=\"Página anterior\">\r\n <c80-icon icon=\"arrowLeft\" [size]=\".6\" [button]=\"false\" />\r\n </button>\r\n <button type=\"button\" class=\"btn btn-sm\" [disabled]=\"!hasNextPage()\" (click)=\"onNextPage()\" title=\"Página siguiente\">\r\n <c80-icon icon=\"arrowRight\" [size]=\".6\" [button]=\"false\" />\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n\r\n<c80-modal />"]}
@@ -6,7 +6,7 @@ import * as i0 from "@angular/core";
6
6
  export declare class CardLevelComponent {
7
7
  cardLevelData: import("@angular/core").InputSignal<CardLevelData>;
8
8
  size: import("@angular/core").InputSignal<number>;
9
- readonly generatedId: import("@angular/core").Signal<string>;
9
+ readonly generatedId: string;
10
10
  readonly cardWidth: import("@angular/core").Signal<string>;
11
11
  isBidirectional: import("@angular/core").Signal<boolean>;
12
12
  bidirectionalFillPercent: import("@angular/core").Signal<number>;
@@ -7,11 +7,8 @@ export declare class InfoMessageComponent {
7
7
  message: import("@angular/core").InputSignal<string>;
8
8
  level: import("@angular/core").InputSignal<InfoNotificationLevel>;
9
9
  linkConfig: import("@angular/core").InputSignal<InfoMessageLink | undefined>;
10
- /**
11
- * Retorna el ícono según el nivel
12
- * @returns Nombre del ícono a mostrar
13
- */
14
- protected get icon(): string;
10
+ /** Ícono según el nivel del mensaje. */
11
+ protected readonly icon: import("@angular/core").Signal<"warning" | "infoCircle">;
15
12
  static ɵfac: i0.ɵɵFactoryDeclaration<InfoMessageComponent, never>;
16
13
  static ɵcmp: i0.ɵɵComponentDeclaration<InfoMessageComponent, "c80-info-message", never, { "message": { "alias": "message"; "required": true; "isSignal": true; }; "level": { "alias": "level"; "required": false; "isSignal": true; }; "linkConfig": { "alias": "linkConfig"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
17
14
  }