@c80/ui 1.1.2 → 2.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 (76) hide show
  1. package/esm2022/lib/action-list/action-list.component.js +5 -5
  2. package/esm2022/lib/action-list/action-list.component.js.map +1 -1
  3. package/esm2022/lib/action-list/action-list.types.js +0 -1
  4. package/esm2022/lib/card-level/card-level.component.js +12 -12
  5. package/esm2022/lib/card-level/card-level.component.js.map +1 -1
  6. package/esm2022/lib/card-level/card-level.interface.js +0 -1
  7. package/esm2022/lib/error-notification/error-notification.component.js +5 -5
  8. package/esm2022/lib/error-notification/error-notification.component.js.map +1 -1
  9. package/esm2022/lib/error-notification/error-notification.types.js +0 -1
  10. package/esm2022/lib/header/header.component.js +5 -5
  11. package/esm2022/lib/header/header.component.js.map +1 -1
  12. package/esm2022/lib/header/header.types.js +0 -1
  13. package/esm2022/lib/icon/icon.component.js +26 -26
  14. package/esm2022/lib/icon/icon.component.js.map +1 -1
  15. package/esm2022/lib/icon/icon.definitions.js.map +1 -1
  16. package/esm2022/lib/icon/icon.types.js +0 -1
  17. package/esm2022/lib/icon/theme.service.js +4 -4
  18. package/esm2022/lib/icon/theme.service.js.map +1 -1
  19. package/esm2022/lib/info-list/info-list.component.js +4 -4
  20. package/esm2022/lib/info-list/info-list.component.js.map +1 -1
  21. package/esm2022/lib/info-list/info-list.types.js +0 -1
  22. package/esm2022/lib/info-message/info-message.component.js +6 -6
  23. package/esm2022/lib/info-message/info-message.component.js.map +1 -1
  24. package/esm2022/lib/info-message/info-message.types.js +0 -1
  25. package/esm2022/lib/input-field/input-field.component.js +11 -11
  26. package/esm2022/lib/input-field/input-field.component.js.map +1 -1
  27. package/esm2022/lib/input-search/c80-input-search.component.js +5 -5
  28. package/esm2022/lib/input-search/c80-input-search.component.js.map +1 -1
  29. package/esm2022/lib/legal-disclaimer/legal-disclaimer.component.js +4 -4
  30. package/esm2022/lib/legal-disclaimer/legal-disclaimer.component.js.map +1 -1
  31. package/esm2022/lib/modal/modal.component.js +4 -4
  32. package/esm2022/lib/modal/modal.component.js.map +1 -1
  33. package/esm2022/lib/modal/modal.service.js +5 -5
  34. package/esm2022/lib/modal/modal.service.js.map +1 -1
  35. package/esm2022/lib/modal/modal.types.js +0 -1
  36. package/esm2022/lib/navigation-card/navigation-card.component.js +5 -5
  37. package/esm2022/lib/navigation-card/navigation-card.component.js.map +1 -1
  38. package/esm2022/lib/navigation-card/navigation-card.types.js +0 -1
  39. package/esm2022/lib/profile-stats/profile-stats.component.js +4 -4
  40. package/esm2022/lib/profile-stats/profile-stats.component.js.map +1 -1
  41. package/esm2022/lib/profile-stats/profile-stats.types.js +0 -1
  42. package/esm2022/lib/rating-display/rating-display.component.js +7 -7
  43. package/esm2022/lib/rating-display/rating-display.component.js.map +1 -1
  44. package/esm2022/lib/rating-stars/rating-stars.component.js +8 -8
  45. package/esm2022/lib/rating-stars/rating-stars.component.js.map +1 -1
  46. package/esm2022/lib/select/select.component.js +17 -17
  47. package/esm2022/lib/select/select.component.js.map +1 -1
  48. package/esm2022/lib/select/select.types.js +0 -1
  49. package/esm2022/lib/snackbar/snackbar.component.js +6 -6
  50. package/esm2022/lib/snackbar/snackbar.component.js.map +1 -1
  51. package/esm2022/lib/snackbar/snackbar.service.js +3 -3
  52. package/esm2022/lib/snackbar/snackbar.types.js +0 -1
  53. package/esm2022/lib/spinner/spinner.component.js +7 -7
  54. package/esm2022/lib/spinner/spinner.component.js.map +1 -1
  55. package/esm2022/lib/stat-card/stat-card.component.js +5 -5
  56. package/esm2022/lib/stat-card/stat-card.component.js.map +1 -1
  57. package/esm2022/lib/stat-card/stat-card.types.js +0 -1
  58. package/esm2022/lib/tab/c80-tab.component.js +6 -6
  59. package/esm2022/lib/tab/c80-tab.component.js.map +1 -1
  60. package/esm2022/lib/tab/c80-tab.types.js +0 -1
  61. package/esm2022/lib/tab/directives/c80-tab-item.directive.js +3 -3
  62. package/esm2022/lib/tab/directives/c80-tab-label.directive.js +3 -3
  63. package/esm2022/lib/table/table-column-visibility.service.js +3 -3
  64. package/esm2022/lib/table/table-crud-state.service.js +7 -7
  65. package/esm2022/lib/table/table-crud-state.service.js.map +1 -1
  66. package/esm2022/lib/table/table-data-converter.service.js +3 -3
  67. package/esm2022/lib/table/table-data-utils.service.js +3 -3
  68. package/esm2022/lib/table/table-dto-mapper.service.js +3 -3
  69. package/esm2022/lib/table/table-pagination.service.js +10 -10
  70. package/esm2022/lib/table/table-pagination.service.js.map +1 -1
  71. package/esm2022/lib/table/table-selection.service.js +6 -6
  72. package/esm2022/lib/table/table-selection.service.js.map +1 -1
  73. package/esm2022/lib/table/table.component.js +26 -26
  74. package/esm2022/lib/table/table.component.js.map +1 -1
  75. package/esm2022/lib/table/table.types.js +0 -1
  76. package/package.json +4 -3
@@ -143,29 +143,29 @@ import * as i0 from "@angular/core";
143
143
  paginationService = inject(TablePaginationService);
144
144
  // Inputs
145
145
  /* v8 ignore next */
146
- data$ = input.required(...(ngDevMode ? [{ debugName: "data$" }] : []));
146
+ data$ = input.required(...(ngDevMode ? [{ debugName: "data$" }] : /* istanbul ignore next */ []));
147
147
  /* v8 ignore next */
148
- columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
148
+ columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
149
149
  /* v8 ignore next */
150
- inputValues$ = input(...(ngDevMode ? [undefined, { debugName: "inputValues$" }] : [])); // Observable para actualizar valores de inputs dinámicamente en creación/edición
150
+ inputValues$ = input(...(ngDevMode ? [undefined, { debugName: "inputValues$" }] : /* istanbul ignore next */ [])); // Observable para actualizar valores de inputs dinámicamente en creación/edición
151
151
  /* v8 ignore next */
152
- customActions = input([], ...(ngDevMode ? [{ debugName: "customActions" }] : [])); // Acciones personalizadas dinámicas
152
+ customActions = input([], ...(ngDevMode ? [{ debugName: "customActions" }] : /* istanbul ignore next */ [])); // Acciones personalizadas dinámicas
153
153
  /* v8 ignore next */
154
- size = input(0, ...(ngDevMode ? [{ debugName: "size" }] : [])); // Tamaño de la tabla (0 = sin límite, > 0 aplica max-height)
154
+ size = input(0, ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ [])); // Tamaño de la tabla (0 = sin límite, > 0 aplica max-height)
155
155
  /* v8 ignore next */
156
- multiple = input(true, ...(ngDevMode ? [{ debugName: "multiple" }] : [])); // Permite selección múltiple por defecto
156
+ multiple = input(true, ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ [])); // Permite selección múltiple por defecto
157
157
  /* v8 ignore next */
158
- rowId = input('id', ...(ngDevMode ? [{ debugName: "rowId" }] : [])); // Accessor de la PK de cada fila (default 'id'); usar si la entidad no usa 'id'
158
+ 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
159
  /* v8 ignore next */
160
- searchable = input(false, ...(ngDevMode ? [{ debugName: "searchable", transform: booleanAttribute }] : [{ transform: booleanAttribute }])); // Si es true, muestra barra de búsqueda
160
+ searchable = input(false, { ...(ngDevMode ? { debugName: "searchable" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); // Si es true, muestra barra de búsqueda
161
161
  /* v8 ignore next */
162
- allowSelection = input(false, ...(ngDevMode ? [{ debugName: "allowSelection", transform: booleanAttribute }] : [{ transform: booleanAttribute }])); // Si es true, permite selección de filas
162
+ allowSelection = input(false, { ...(ngDevMode ? { debugName: "allowSelection" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); // Si es true, permite selección de filas
163
163
  /* v8 ignore next */
164
- noConfirm = input(false, ...(ngDevMode ? [{ debugName: "noConfirm", transform: booleanAttribute }] : [{ transform: booleanAttribute }])); // Si es true, no muestra confirmaciones modales
164
+ noConfirm = input(false, { ...(ngDevMode ? { debugName: "noConfirm" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); // Si es true, no muestra confirmaciones modales
165
165
  /* v8 ignore next */
166
- paginated = input(false, ...(ngDevMode ? [{ debugName: "paginated", transform: booleanAttribute }] : [{ transform: booleanAttribute }])); // Si es true, habilita paginación con limit/offset
166
+ paginated = input(false, { ...(ngDevMode ? { debugName: "paginated" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); // Si es true, habilita paginación con limit/offset
167
167
  /* v8 ignore next */
168
- paginationConfig = input({ pageSize: 10 }, ...(ngDevMode ? [{ debugName: "paginationConfig" }] : [])); // Configuración de paginación (tamaño de página, total items)
168
+ paginationConfig = input({ pageSize: 10 }, ...(ngDevMode ? [{ debugName: "paginationConfig" }] : /* istanbul ignore next */ [])); // Configuración de paginación (tamaño de página, total items)
169
169
  // Outputs - Acciones unificadas (Angular 18+ output API)
170
170
  /* v8 ignore next */
171
171
  actionClick = output(); // Output unificado para TODAS las acciones (CRUD + custom)
@@ -177,8 +177,8 @@ import * as i0 from "@angular/core";
177
177
  paginationChange = output(); // Output para cambios de paginación (page, limit, offset)
178
178
  // Estado principal
179
179
  /* v8 ignore next 2 */
180
- data = signal([], ...(ngDevMode ? [{ debugName: "data" }] : []));
181
- searchValue = signal('', ...(ngDevMode ? [{ debugName: "searchValue" }] : []));
180
+ data = signal([], ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
181
+ searchValue = signal('', ...(ngDevMode ? [{ debugName: "searchValue" }] : /* istanbul ignore next */ []));
182
182
  // Estado de selección (delegado a servicio)
183
183
  /* v8 ignore next 4 */
184
184
  selectionState = this.selectionService.createSelectionState((item) => item[this.rowId()]);
@@ -202,24 +202,24 @@ import * as i0 from "@angular/core";
202
202
  hasPrevPage = this.paginationState.hasPrevPage;
203
203
  // Keys visibles computed automáticamente
204
204
  /* v8 ignore next 7 */
205
- keys = computed(() => this.visibilityService.updateVisibleKeys(this.columns(), { data: this.data(), creating: this.creating(), editing: this.editing() }), ...(ngDevMode ? [{ debugName: "keys" }] : []));
205
+ keys = computed(() => this.visibilityService.updateVisibleKeys(this.columns(), { data: this.data(), creating: this.creating(), editing: this.editing() }), ...(ngDevMode ? [{ debugName: "keys" }] : /* istanbul ignore next */ []));
206
206
  // Computed - Detecta acciones CRUD y custom
207
207
  /* v8 ignore next 5 */
208
- hasAnyActions = computed(() => this.customActions().length > 0, ...(ngDevMode ? [{ debugName: "hasAnyActions" }] : []));
209
- hasCrudCreate = computed(() => this.customActions().some(a => a.name === 'create'), ...(ngDevMode ? [{ debugName: "hasCrudCreate" }] : []));
210
- hasCrudUpdate = computed(() => this.customActions().some(a => a.name === 'update'), ...(ngDevMode ? [{ debugName: "hasCrudUpdate" }] : []));
211
- hasCrudDelete = computed(() => this.customActions().some(a => a.name === 'delete'), ...(ngDevMode ? [{ debugName: "hasCrudDelete" }] : []));
212
- hasCrudCancel = computed(() => this.customActions().some(a => a.name === 'cancel'), ...(ngDevMode ? [{ debugName: "hasCrudCancel" }] : []));
208
+ hasAnyActions = computed(() => this.customActions().length > 0, ...(ngDevMode ? [{ debugName: "hasAnyActions" }] : /* istanbul ignore next */ []));
209
+ hasCrudCreate = computed(() => this.customActions().some(a => a.name === 'create'), ...(ngDevMode ? [{ debugName: "hasCrudCreate" }] : /* istanbul ignore next */ []));
210
+ hasCrudUpdate = computed(() => this.customActions().some(a => a.name === 'update'), ...(ngDevMode ? [{ debugName: "hasCrudUpdate" }] : /* istanbul ignore next */ []));
211
+ hasCrudDelete = computed(() => this.customActions().some(a => a.name === 'delete'), ...(ngDevMode ? [{ debugName: "hasCrudDelete" }] : /* istanbul ignore next */ []));
212
+ hasCrudCancel = computed(() => this.customActions().some(a => a.name === 'cancel'), ...(ngDevMode ? [{ debugName: "hasCrudCancel" }] : /* istanbul ignore next */ []));
213
213
  /* v8 ignore next 5 */
214
214
  shouldShowCreateButton = computed(() => {
215
215
  const createAction = this.customActions().find(a => a.name === 'create');
216
216
  if (!createAction)
217
217
  return false;
218
218
  return !createAction.condition || createAction.condition({}, this.data());
219
- }, ...(ngDevMode ? [{ debugName: "shouldShowCreateButton" }] : []));
219
+ }, ...(ngDevMode ? [{ debugName: "shouldShowCreateButton" }] : /* istanbul ignore next */ []));
220
220
  // Table max height computed
221
221
  /* v8 ignore next 3 */
222
- tableMaxHeight = computed(() => this.dataUtils.getTableMaxHeight(this.size()), ...(ngDevMode ? [{ debugName: "tableMaxHeight" }] : []));
222
+ tableMaxHeight = computed(() => this.dataUtils.getTableMaxHeight(this.size()), ...(ngDevMode ? [{ debugName: "tableMaxHeight" }] : /* istanbul ignore next */ []));
223
223
  /* v8 ignore next 2 */
224
224
  dataSub;
225
225
  inputValuesSub;
@@ -556,11 +556,11 @@ import * as i0 from "@angular/core";
556
556
  // Para acciones sin color explícito, usar el color de dark mode
557
557
  return '#e9ecef';
558
558
  }
559
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
560
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", 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: "<!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n<div class=\"table-responsive\" [style.max-height]=\"tableMaxHeight()\" [style.overflow-y]=\"size() > 0 ? 'auto' : 'visible'\">\n <!-- Search Bar -->\n @if (searchable()) {\n <div class=\"search-container\">\n <div class=\"search-input-wrapper\">\n <div class=\"input-group\">\n <span class=\"input-group-text\">\n <c80-icon icon=\"search\" [size]=\".65\" [button]=\"false\" />\n </span>\n <input type=\"text\" class=\"form-control search-input\" placeholder=\"Buscar...\" [value]=\"searchValue()\" (input)=\"onSearchInput($event)\" aria-label=\"Buscar en la tabla\" />\n @if (searchValue()) {\n <button class=\"btn btn-outline-secondary btn-borrar\" type=\"button\" (click)=\"clearSearch()\" title=\"Limpiar b\u00FAsqueda\">\n <c80-icon icon=\"cancel\" [size]=\".6\" />\n </button>\n }\n </div>\n </div>\n </div>\n }\n\n <table class=\"table table-bordered table-hover align-middle\">\n <thead class=\"thead table-light sticky-header\">\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <th class=\"text-center selection-column\">\n @if (multiple()) {\n <input type=\"checkbox\" [checked]=\"selectAllChecked()\" [indeterminate]=\"selectAllIndeterminate()\" (change)=\"toggleSelectAll()\" aria-label=\"Seleccionar todo\" />\n }\n </th>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisibleInHeader(col)) {\n @if (col.type === 'boolean') {\n <th class=\"text-center boolean-column\">{{ col.label }}</th>\n }\n @else if (col.type === 'number' || col.type === 'integer') {\n <th class=\"text-center number-column\">{{ col.label }}</th>\n }\n @else if (col.type === 'date') {\n <th class=\"text-center date-column\">{{ col.label }}</th>\n }\n @else {\n <th>{{ col.label }}</th>\n }\n }\n }\n @if (hasAnyActions()) {\n <th class=\"table-actions-header\">\n <div class=\"actions-wrapper\">\n <span>Actions</span>\n @if (shouldShowCreateButton()) {\n <c80-icon button icon=\"add\" [disabled]=\"creating()\" title=\"Agregar\" [size]=\".6\" (iconClick)=\"startCreate()\" />\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of data(); track trackById(i, row); let i = $index) {\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <td class=\"text-center selection-column\">\n <input type=\"checkbox\" [checked]=\"isItemSelected(row)\" (change)=\"toggleItemSelection(row)\" [attr.aria-label]=\"'Seleccionar fila ' + (i + 1)\" />\n </td>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisibleForRow(col, row)) {\n @if (col.type === 'boolean') {\n <td class=\"text-center boolean-column\">\n @if (editing() === row['id'] && !col.readOnly) {\n <input type=\"checkbox\" [checked]=\"!!editRow()?.[col.accessor]\" (change)=\"onEditInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\n }\n @else {\n @if (getCellValue(row, col.accessor) === true) {\n <c80-icon icon=\"check\" [size]=\".7\" />\n <br />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\" />\n <br />\n }\n }\n </td>\n }\n @else if (col.type === 'number' || col.type === 'integer') {\n <td class=\"text-center number-column\">\n @if (editing() === row['id'] && !col.readOnly) {\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'\"\n (input)=\"onEditInput($event, col.accessor, col)\" />\n }\n @else {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\n col.accessor), col) }}</span>\n }\n </td>\n }\n @else if (col.type === 'date') {\n <td class=\"text-center date-column\">\n @if (editing() === row['id'] && !col.readOnly) {\n <input class=\"form-control form-control-sm\" type=\"datetime-local\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onEditInput($event, col.accessor, col)\" />\n }\n @else {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\n col.accessor), col) }}</span>\n }\n </td>\n }\n @else {\n <td>\n @if (editing() === row['id'] && !col.readOnly) {\n @if (col.type === 'enum') {\n <select class=\"form-control form-control-sm\" [value]=\"editRow()?.[col.accessor] ?? ''\" (change)=\"onEditInput($event, col.accessor, col)\">\n <option value=\"\">{{ col.label }}</option>\n @for (option of getEnumOptions(col); track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n }\n @else {\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)\" />\n }\n }\n @else {\n @if (col.type === 'password') {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">******</span>\n }\n @else if (col.type === 'enum') {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{\n getEnumDisplayValue(getCellValue(row, col.accessor), col)\n }}</span>\n }\n @else if (getCellValue(row, col.accessor) === true) {\n <c80-icon icon=\"check\" [size]=\".7\" />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\" />\n }\n @else {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\n col.accessor), col) }}</span>\n }\n }\n </td>\n }\n }\n }\n @if (hasAnyActions()) {\n <td class=\"text-end actions-cell\">\n <div class=\"actions-container\" [class.centered-actions]=\"editing() === row['id']\">\n @if (editing() === row['id']) {\n <!-- Modo edici\u00F3n: mostrar guardar y cancelar -->\n @if (hasCrudUpdate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\" [size]=\".7\" />\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\" [size]=\".7\" />\n }\n @else {\n @for (action of customActions(); track action.name) {\n @if (shouldShowAction(action, row, data())) {\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\" />\n }\n }\n }\n </div>\n </td>\n }\n </tr>\n }\n @if (creating() && hasCrudCreate()) {\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <td class=\"text-center selection-column\">\n <!-- Empty cell for alignment -->\n </td>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisible(col)) {\n @if (col.type === 'boolean') {\n <td class=\"text-center\">\n @if (!col.readOnly) {\n <input type=\"checkbox\" [checked]=\"!!newRow()?.[col.accessor]\" (change)=\"onInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\n }\n @else {\n <!-- ReadOnly boolean column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n } @else if (col.type === 'number' || col.type === 'integer') {\n <td class=\"text-center number-column\">\n @if (!col.readOnly) {\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'\"\n (input)=\"onInput($event, col.accessor, col)\" />\n }\n @else {\n <!-- ReadOnly number column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n } @else {\n <td>\n @if (!col.readOnly) {\n @if (col.type === 'enum') {\n <select class=\"form-control form-control-sm\" [value]=\"newRow()?.[col.accessor] ?? ''\" (change)=\"onInput($event, col.accessor, col)\">\n <option value=\"\">{{ col.label }}</option>\n @for (option of getEnumOptions(col); track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n }\n @else {\n <input class=\"form-control form-control-sm\" type=\"text\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onInput($event, col.accessor, col)\" />\n }\n }\n @else {\n <!-- ReadOnly column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n }\n }\n }\n <td class=\"text-end actions-cell\">\n <div class=\"actions-container centered-actions\">\n @if (hasCrudCreate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveCreate()\" [size]=\".7\" />\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelCreate()\" [size]=\".7\" />\n </div>\n </td>\n </tr>\n }\n </tbody>\n </table>\n @if (data().length === 0 && !creating()) {\n <div class=\"text-center text-muted py-3 small\">\n No hay datos para mostrar.\n </div>\n }\n\n <!-- Pagination Controls -->\n @if (paginated() && data().length > 0) {\n <div class=\"pagination-container\">\n <div class=\"pagination-info\">\n P\u00E1gina {{ currentPage() }} de {{ totalPages() }}\n </div>\n <div class=\"pagination-controls\">\n <button type=\"button\" class=\"btn btn-sm\" [disabled]=\"!hasPrevPage()\" (click)=\"onPrevPage()\" title=\"P\u00E1gina anterior\">\n <c80-icon icon=\"arrowLeft\" [size]=\".6\" [button]=\"false\" />\n </button>\n <button type=\"button\" class=\"btn btn-sm\" [disabled]=\"!hasNextPage()\" (click)=\"onNextPage()\" title=\"P\u00E1gina siguiente\">\n <c80-icon icon=\"arrowRight\" [size]=\".6\" [button]=\"false\" />\n </button>\n </div>\n </div>\n }\n</div>\n\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 });
559
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
560
+ 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
561
  }
562
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: TableComponent, decorators: [{
562
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TableComponent, decorators: [{
563
563
  type: Component,
564
- args: [{ selector: 'c80-table', standalone: true, imports: [IconComponent, ModalComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n<div class=\"table-responsive\" [style.max-height]=\"tableMaxHeight()\" [style.overflow-y]=\"size() > 0 ? 'auto' : 'visible'\">\n <!-- Search Bar -->\n @if (searchable()) {\n <div class=\"search-container\">\n <div class=\"search-input-wrapper\">\n <div class=\"input-group\">\n <span class=\"input-group-text\">\n <c80-icon icon=\"search\" [size]=\".65\" [button]=\"false\" />\n </span>\n <input type=\"text\" class=\"form-control search-input\" placeholder=\"Buscar...\" [value]=\"searchValue()\" (input)=\"onSearchInput($event)\" aria-label=\"Buscar en la tabla\" />\n @if (searchValue()) {\n <button class=\"btn btn-outline-secondary btn-borrar\" type=\"button\" (click)=\"clearSearch()\" title=\"Limpiar b\u00FAsqueda\">\n <c80-icon icon=\"cancel\" [size]=\".6\" />\n </button>\n }\n </div>\n </div>\n </div>\n }\n\n <table class=\"table table-bordered table-hover align-middle\">\n <thead class=\"thead table-light sticky-header\">\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <th class=\"text-center selection-column\">\n @if (multiple()) {\n <input type=\"checkbox\" [checked]=\"selectAllChecked()\" [indeterminate]=\"selectAllIndeterminate()\" (change)=\"toggleSelectAll()\" aria-label=\"Seleccionar todo\" />\n }\n </th>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisibleInHeader(col)) {\n @if (col.type === 'boolean') {\n <th class=\"text-center boolean-column\">{{ col.label }}</th>\n }\n @else if (col.type === 'number' || col.type === 'integer') {\n <th class=\"text-center number-column\">{{ col.label }}</th>\n }\n @else if (col.type === 'date') {\n <th class=\"text-center date-column\">{{ col.label }}</th>\n }\n @else {\n <th>{{ col.label }}</th>\n }\n }\n }\n @if (hasAnyActions()) {\n <th class=\"table-actions-header\">\n <div class=\"actions-wrapper\">\n <span>Actions</span>\n @if (shouldShowCreateButton()) {\n <c80-icon button icon=\"add\" [disabled]=\"creating()\" title=\"Agregar\" [size]=\".6\" (iconClick)=\"startCreate()\" />\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of data(); track trackById(i, row); let i = $index) {\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <td class=\"text-center selection-column\">\n <input type=\"checkbox\" [checked]=\"isItemSelected(row)\" (change)=\"toggleItemSelection(row)\" [attr.aria-label]=\"'Seleccionar fila ' + (i + 1)\" />\n </td>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisibleForRow(col, row)) {\n @if (col.type === 'boolean') {\n <td class=\"text-center boolean-column\">\n @if (editing() === row['id'] && !col.readOnly) {\n <input type=\"checkbox\" [checked]=\"!!editRow()?.[col.accessor]\" (change)=\"onEditInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\n }\n @else {\n @if (getCellValue(row, col.accessor) === true) {\n <c80-icon icon=\"check\" [size]=\".7\" />\n <br />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\" />\n <br />\n }\n }\n </td>\n }\n @else if (col.type === 'number' || col.type === 'integer') {\n <td class=\"text-center number-column\">\n @if (editing() === row['id'] && !col.readOnly) {\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'\"\n (input)=\"onEditInput($event, col.accessor, col)\" />\n }\n @else {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\n col.accessor), col) }}</span>\n }\n </td>\n }\n @else if (col.type === 'date') {\n <td class=\"text-center date-column\">\n @if (editing() === row['id'] && !col.readOnly) {\n <input class=\"form-control form-control-sm\" type=\"datetime-local\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onEditInput($event, col.accessor, col)\" />\n }\n @else {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\n col.accessor), col) }}</span>\n }\n </td>\n }\n @else {\n <td>\n @if (editing() === row['id'] && !col.readOnly) {\n @if (col.type === 'enum') {\n <select class=\"form-control form-control-sm\" [value]=\"editRow()?.[col.accessor] ?? ''\" (change)=\"onEditInput($event, col.accessor, col)\">\n <option value=\"\">{{ col.label }}</option>\n @for (option of getEnumOptions(col); track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n }\n @else {\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)\" />\n }\n }\n @else {\n @if (col.type === 'password') {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">******</span>\n }\n @else if (col.type === 'enum') {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{\n getEnumDisplayValue(getCellValue(row, col.accessor), col)\n }}</span>\n }\n @else if (getCellValue(row, col.accessor) === true) {\n <c80-icon icon=\"check\" [size]=\".7\" />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\" />\n }\n @else {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\n col.accessor), col) }}</span>\n }\n }\n </td>\n }\n }\n }\n @if (hasAnyActions()) {\n <td class=\"text-end actions-cell\">\n <div class=\"actions-container\" [class.centered-actions]=\"editing() === row['id']\">\n @if (editing() === row['id']) {\n <!-- Modo edici\u00F3n: mostrar guardar y cancelar -->\n @if (hasCrudUpdate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\" [size]=\".7\" />\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\" [size]=\".7\" />\n }\n @else {\n @for (action of customActions(); track action.name) {\n @if (shouldShowAction(action, row, data())) {\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\" />\n }\n }\n }\n </div>\n </td>\n }\n </tr>\n }\n @if (creating() && hasCrudCreate()) {\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <td class=\"text-center selection-column\">\n <!-- Empty cell for alignment -->\n </td>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisible(col)) {\n @if (col.type === 'boolean') {\n <td class=\"text-center\">\n @if (!col.readOnly) {\n <input type=\"checkbox\" [checked]=\"!!newRow()?.[col.accessor]\" (change)=\"onInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\n }\n @else {\n <!-- ReadOnly boolean column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n } @else if (col.type === 'number' || col.type === 'integer') {\n <td class=\"text-center number-column\">\n @if (!col.readOnly) {\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'\"\n (input)=\"onInput($event, col.accessor, col)\" />\n }\n @else {\n <!-- ReadOnly number column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n } @else {\n <td>\n @if (!col.readOnly) {\n @if (col.type === 'enum') {\n <select class=\"form-control form-control-sm\" [value]=\"newRow()?.[col.accessor] ?? ''\" (change)=\"onInput($event, col.accessor, col)\">\n <option value=\"\">{{ col.label }}</option>\n @for (option of getEnumOptions(col); track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n }\n @else {\n <input class=\"form-control form-control-sm\" type=\"text\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onInput($event, col.accessor, col)\" />\n }\n }\n @else {\n <!-- ReadOnly column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n }\n }\n }\n <td class=\"text-end actions-cell\">\n <div class=\"actions-container centered-actions\">\n @if (hasCrudCreate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveCreate()\" [size]=\".7\" />\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelCreate()\" [size]=\".7\" />\n </div>\n </td>\n </tr>\n }\n </tbody>\n </table>\n @if (data().length === 0 && !creating()) {\n <div class=\"text-center text-muted py-3 small\">\n No hay datos para mostrar.\n </div>\n }\n\n <!-- Pagination Controls -->\n @if (paginated() && data().length > 0) {\n <div class=\"pagination-container\">\n <div class=\"pagination-info\">\n P\u00E1gina {{ currentPage() }} de {{ totalPages() }}\n </div>\n <div class=\"pagination-controls\">\n <button type=\"button\" class=\"btn btn-sm\" [disabled]=\"!hasPrevPage()\" (click)=\"onPrevPage()\" title=\"P\u00E1gina anterior\">\n <c80-icon icon=\"arrowLeft\" [size]=\".6\" [button]=\"false\" />\n </button>\n <button type=\"button\" class=\"btn btn-sm\" [disabled]=\"!hasNextPage()\" (click)=\"onNextPage()\" title=\"P\u00E1gina siguiente\">\n <c80-icon icon=\"arrowRight\" [size]=\".6\" [button]=\"false\" />\n </button>\n </div>\n </div>\n }\n</div>\n\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"] }]
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"] }]
565
565
  }], 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
566
  //# sourceMappingURL=table.component.js.map