@c80/ui 1.0.64 → 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 (110) hide show
  1. package/README.md +1 -1
  2. package/esm2022/index.js +3 -0
  3. package/esm2022/index.js.map +1 -1
  4. package/esm2022/lib/action-list/action-list.component.js +5 -5
  5. package/esm2022/lib/action-list/action-list.component.js.map +1 -1
  6. package/esm2022/lib/action-list/action-list.types.js +0 -1
  7. package/esm2022/lib/card-level/card-level.component.js +12 -12
  8. package/esm2022/lib/card-level/card-level.component.js.map +1 -1
  9. package/esm2022/lib/card-level/card-level.interface.js +0 -1
  10. package/esm2022/lib/error-notification/error-notification.component.js +5 -5
  11. package/esm2022/lib/error-notification/error-notification.component.js.map +1 -1
  12. package/esm2022/lib/error-notification/error-notification.types.js +0 -1
  13. package/esm2022/lib/header/header.component.js +7 -6
  14. package/esm2022/lib/header/header.component.js.map +1 -1
  15. package/esm2022/lib/header/header.types.js +0 -1
  16. package/esm2022/lib/icon/icon.component.js +26 -26
  17. package/esm2022/lib/icon/icon.component.js.map +1 -1
  18. package/esm2022/lib/icon/icon.definitions.js +3 -0
  19. package/esm2022/lib/icon/icon.definitions.js.map +1 -1
  20. package/esm2022/lib/icon/icon.types.js +0 -1
  21. package/esm2022/lib/icon/theme.service.js +23 -8
  22. package/esm2022/lib/icon/theme.service.js.map +1 -1
  23. package/esm2022/lib/info-list/info-list.component.js +4 -4
  24. package/esm2022/lib/info-list/info-list.component.js.map +1 -1
  25. package/esm2022/lib/info-list/info-list.types.js +0 -1
  26. package/esm2022/lib/info-message/index.js +3 -0
  27. package/esm2022/lib/info-message/index.js.map +1 -0
  28. package/esm2022/lib/info-message/info-message.component.js +25 -0
  29. package/esm2022/lib/info-message/info-message.component.js.map +1 -0
  30. package/esm2022/lib/info-message/info-message.types.js +1 -0
  31. package/esm2022/lib/info-message/info-message.types.js.map +1 -0
  32. package/esm2022/lib/input-field/input-field.component.js +11 -11
  33. package/esm2022/lib/input-field/input-field.component.js.map +1 -1
  34. package/esm2022/lib/input-search/c80-input-search.component.js +5 -5
  35. package/esm2022/lib/input-search/c80-input-search.component.js.map +1 -1
  36. package/esm2022/lib/legal-disclaimer/index.js +2 -0
  37. package/esm2022/lib/legal-disclaimer/index.js.map +1 -0
  38. package/esm2022/lib/legal-disclaimer/legal-disclaimer.component.js +21 -0
  39. package/esm2022/lib/legal-disclaimer/legal-disclaimer.component.js.map +1 -0
  40. package/esm2022/lib/modal/modal.component.js +12 -5
  41. package/esm2022/lib/modal/modal.component.js.map +1 -1
  42. package/esm2022/lib/modal/modal.service.js +22 -10
  43. package/esm2022/lib/modal/modal.service.js.map +1 -1
  44. package/esm2022/lib/modal/modal.types.js +0 -1
  45. package/esm2022/lib/modal/modal.types.js.map +1 -1
  46. package/esm2022/lib/navigation-card/index.js +3 -0
  47. package/esm2022/lib/navigation-card/index.js.map +1 -0
  48. package/esm2022/lib/navigation-card/navigation-card.component.js +18 -0
  49. package/esm2022/lib/navigation-card/navigation-card.component.js.map +1 -0
  50. package/esm2022/lib/navigation-card/navigation-card.types.js +1 -0
  51. package/esm2022/lib/navigation-card/navigation-card.types.js.map +1 -0
  52. package/esm2022/lib/profile-stats/profile-stats.component.js +4 -4
  53. package/esm2022/lib/profile-stats/profile-stats.component.js.map +1 -1
  54. package/esm2022/lib/profile-stats/profile-stats.types.js +0 -1
  55. package/esm2022/lib/rating-display/rating-display.component.js +7 -7
  56. package/esm2022/lib/rating-display/rating-display.component.js.map +1 -1
  57. package/esm2022/lib/rating-stars/rating-stars.component.js +8 -8
  58. package/esm2022/lib/rating-stars/rating-stars.component.js.map +1 -1
  59. package/esm2022/lib/select/select.component.js +17 -17
  60. package/esm2022/lib/select/select.component.js.map +1 -1
  61. package/esm2022/lib/select/select.types.js +0 -1
  62. package/esm2022/lib/snackbar/snackbar.component.js +6 -6
  63. package/esm2022/lib/snackbar/snackbar.component.js.map +1 -1
  64. package/esm2022/lib/snackbar/snackbar.service.js +3 -3
  65. package/esm2022/lib/snackbar/snackbar.types.js +0 -1
  66. package/esm2022/lib/spinner/spinner.component.js +7 -7
  67. package/esm2022/lib/spinner/spinner.component.js.map +1 -1
  68. package/esm2022/lib/stat-card/stat-card.component.js +5 -5
  69. package/esm2022/lib/stat-card/stat-card.component.js.map +1 -1
  70. package/esm2022/lib/stat-card/stat-card.types.js +0 -1
  71. package/esm2022/lib/tab/c80-tab.component.js +6 -6
  72. package/esm2022/lib/tab/c80-tab.component.js.map +1 -1
  73. package/esm2022/lib/tab/c80-tab.types.js +0 -1
  74. package/esm2022/lib/tab/directives/c80-tab-item.directive.js +3 -3
  75. package/esm2022/lib/tab/directives/c80-tab-label.directive.js +3 -3
  76. package/esm2022/lib/table/table-column-visibility.service.js +3 -3
  77. package/esm2022/lib/table/table-crud-state.service.js +7 -7
  78. package/esm2022/lib/table/table-crud-state.service.js.map +1 -1
  79. package/esm2022/lib/table/table-data-converter.service.js +3 -3
  80. package/esm2022/lib/table/table-data-utils.service.js +3 -3
  81. package/esm2022/lib/table/table-dto-mapper.service.js +32 -35
  82. package/esm2022/lib/table/table-dto-mapper.service.js.map +1 -1
  83. package/esm2022/lib/table/table-pagination.service.js +10 -10
  84. package/esm2022/lib/table/table-pagination.service.js.map +1 -1
  85. package/esm2022/lib/table/table-selection.service.js +22 -22
  86. package/esm2022/lib/table/table-selection.service.js.map +1 -1
  87. package/esm2022/lib/table/table.component.js +46 -30
  88. package/esm2022/lib/table/table.component.js.map +1 -1
  89. package/esm2022/lib/table/table.types.js +0 -1
  90. package/esm2022/lib/table/table.utils.js +4 -3
  91. package/esm2022/lib/table/table.utils.js.map +1 -1
  92. package/index.d.ts +3 -0
  93. package/lib/header/header.component.d.ts +2 -1
  94. package/lib/icon/theme.service.d.ts +34 -0
  95. package/lib/info-message/index.d.ts +2 -0
  96. package/lib/info-message/info-message.component.d.ts +17 -0
  97. package/lib/info-message/info-message.types.d.ts +5 -0
  98. package/lib/legal-disclaimer/index.d.ts +1 -0
  99. package/lib/legal-disclaimer/legal-disclaimer.component.d.ts +15 -0
  100. package/lib/modal/modal.component.d.ts +5 -0
  101. package/lib/modal/modal.service.d.ts +11 -2
  102. package/lib/modal/modal.types.d.ts +1 -0
  103. package/lib/navigation-card/index.d.ts +2 -0
  104. package/lib/navigation-card/navigation-card.component.d.ts +10 -0
  105. package/lib/navigation-card/navigation-card.types.d.ts +7 -0
  106. package/lib/table/table-dto-mapper.service.d.ts +12 -5
  107. package/lib/table/table-selection.service.d.ts +1 -1
  108. package/lib/table/table.component.d.ts +2 -1
  109. package/lib/table/table.utils.d.ts +2 -1
  110. package/package.json +4 -3
@@ -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 {\n type OnInit,\n type OnDestroy,\n Component,\n ChangeDetectionStrategy,\n input,\n signal,\n computed,\n output,\n inject,\n effect,\n} from '@angular/core';\nimport type { Observable, Subscription } from 'rxjs';\nimport { IconComponent } from '../icon';\nimport { TableColumnVisibilityService } from './table-column-visibility.service';\nimport { TableDataUtilsService } from './table-data-utils.service';\nimport { TableDataConverterService } from './table-data-converter.service';\nimport { TableSelectionService } from './table-selection.service';\nimport { TableCrudStateService } from './table-crud-state.service';\nimport { TablePaginationService } from './table-pagination.service';\nimport type { TableColDef, CustomTableAction, PaginationChangeEvent, PaginationConfig } from './table.types';\nimport { ModalComponent, ModalService } from '../modal';\nimport {\n booleanAttribute,\n getErrorMessage,\n getInputValue,\n trackById,\n shouldShowAction,\n getActionTooltip,\n} from './table.utils';\n\n/**\n * C80TableComponent - Componente de tabla avanzado con funcionalidades CRUD\n *\n * COMPORTAMIENTO DE VISIBILIDAD DE COLUMNAS:\n * ========================================\n *\n * 1. PRIORIDAD MÁXIMA - visible: false\n * - La columna se oculta SIEMPRE, sin excepciones\n * - Ni en modo creación ni en modo edición se muestra\n *\n * 2. OCULTACIÓN AUTOMÁTICA - hideIfAllValuesAreNull: true\n * - La columna se oculta solo si TODOS los valores actuales están vacíos\n * - Valores considerados vacíos: null, undefined, '', [], {}\n * - Valores NO vacíos: 0, false (son valores válidos)\n * - EXCEPCIONES IMPORTANTES:\n * * En modo creación (creating=true) estas columnas SÍ se muestran\n * * En modo edición de una fila específica se muestran SOLO si esa fila tiene valor\n *\n * 3. POR DEFECTO - Columnas normales\n * - Se muestran siempre (visualización, creación y edición)\n *\n * VALORES POR DEFECTO EN CREACIÓN:\n * ===============================\n *\n * - Propiedad `default?: unknown` permite definir valores por defecto para modo creación\n * - Solo se aplica cuando se inicia el modo creación (startCreate)\n * - Puede ser cualquier tipo: string, number, boolean, etc.\n * - Si no se especifica `default`, se usa cadena vacía ('')\n *\n * VALORES DINÁMICOS EN CREACIÓN Y EDICIÓN:\n * =======================================\n *\n * - Input `inputValues$?: Observable<Partial<T>>` permite actualizar valores dinámicamente\n * - Solo se aplica durante modo creación (creating=true) o edición (editing!=null)\n * - Los valores se aplican automáticamente cuando el Observable emite\n * - Permite cambios múltiples durante el mismo modo de creación/edición\n * - Los nuevos valores sobrescriben los existentes (spread operator)\n *\n * TIPOS DE DATOS SOPORTADOS:\n * =========================\n *\n * - 'string': Texto normal (default)\n * - 'number': Números decimales (preserva decimales: 5.3 → 5.3)\n * - 'integer': Números enteros (convierte a entero: 5.3 → 5)\n * - 'boolean': Verdadero/Falso (checkbox)\n * - 'password': Texto oculto (input type=\"password\")\n * - 'enum': Lista de opciones predefinidas (select)\n *\n * SISTEMA DE ACCIONES UNIFICADO (customActions):\n * =============================================\n *\n * Input: `customActions: CustomTableAction[]` - Array de acciones dinámicas\n * Output: `(actionClick)` - Evento unificado que emite { action: string, row: T }\n *\n * ACCIONES CRUD PREDEFINIDAS (TABLE_CRUD_ACTIONS):\n * ------------------------------------------------\n * - CREATE: Solo aparece como botón \"+\" en header (no en filas)\n * - UPDATE: Activa modo edición (muestra inputs), botón \"✓\" guarda cambios\n * - DELETE: Muestra confirmación y emite evento delete\n * - CANCEL: Muestra confirmación y emite evento cancel (opcional)\n *\n * ACCIONES PERSONALIZADAS (Custom Actions):\n * -----------------------------------------\n * Interfaz: { name: string, icon: IconType, condition?: (row) => boolean, tooltip?: string }\n * - name: ID único de la acción\n * - icon: Icono del botón (ej: 'settings', 'upload', 'refresh')\n * - condition: Función opcional para mostrar/ocultar según estado de fila\n * - tooltip: Texto al hacer hover (default: name)\n *\n * MANEJO EN COMPONENTE:\n * --------------------\n * ```typescript\n * // 1. Definir acciones en constants:\n * export const ENTITY_TABLE_ACTIONS: CustomTableAction[] = [\n * TABLE_CRUD_ACTIONS.CREATE,\n * TABLE_CRUD_ACTIONS.UPDATE,\n * { name: 'custom-action', icon: 'settings', tooltip: 'Configurar' },\n * TABLE_CRUD_ACTIONS.DELETE\n * ];\n *\n * // 2. En el componente:\n * readonly tableActions = ENTITY_TABLE_ACTIONS;\n *\n * handleAction({ action, row }) {\n * const entity = row as unknown as EntityType;\n * switch (action) {\n * case 'create': this.onCreate(row); break;\n * case 'update': this.onUpdate(entity); break;\n * case 'delete': this.onDelete(entity.id); break;\n * case 'custom-action': this.onCustom(entity); break;\n * }\n * }\n * ```\n *\n * ACCIONES CON CONDICIÓN:\n * ----------------------\n * ```typescript\n * {\n * name: 'enable',\n * icon: 'toggleOn',\n * tooltip: 'Habilitar',\n * condition: (row) => row['enabled'] === false\n * }\n * ```\n *\n * CONSTANTES REUTILIZABLES:\n * ------------------------\n * - TABLE_CRUD_ACTIONS: Objeto con CREATE, UPDATE, DELETE, CANCEL\n * - BASIC_CRUD_ACTIONS: Array con [CREATE, UPDATE, DELETE]\n * Importar desde: `@shared` o `@shared/constants`\n *\n * EJEMPLOS COMPLETOS:\n * ------------------\n * - { accessor: 'id', visible: false } → NUNCA se muestra\n * - { accessor: 'motorPos', hideIfAllValuesAreNull: true, default: 0, type: 'integer' } → Entero (5.7 → 5)\n * - { accessor: 'weight', type: 'number', default: 2.5 } → Decimal preservado (5.7 → 5.7)\n * - { accessor: 'status', default: 'active' } → Se autorellena con 'active' en creación\n * - { accessor: 'name' } → Siempre visible, sin valor por defecto (cadena vacía)\n * - inputValues$ emite { motorPos: 5, weight: 2.3 } → actualiza inputs dinámicamente\n * - customActions con CREATE → Muestra botón \"+\" en header\n * - customActions con UPDATE → Botón \"edit\" activa modo edición\n * - customActions con custom → Botón personalizado emite evento\n */@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-table',\n standalone: true,\n imports: [IconComponent, ModalComponent],\n templateUrl: './table.component.html',\n styleUrl: './table.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class TableComponent<T extends Record<string, unknown>> implements OnInit, OnDestroy {\n // Servicios inyectados\n /* v8 ignore next 7 */\n private readonly modalService = inject(ModalService);\n private readonly visibilityService = inject(TableColumnVisibilityService);\n private readonly dataUtils = inject(TableDataUtilsService);\n private readonly dataConverter = inject(TableDataConverterService);\n private readonly selectionService = inject(TableSelectionService);\n private readonly crudService = inject(TableCrudStateService);\n private readonly paginationService = inject(TablePaginationService);\n\n // Inputs\n /* v8 ignore next */\n readonly data$ = input.required<Observable<T[]>>();\n /* v8 ignore next */\n readonly columns = input<TableColDef[]>([]);\n /* v8 ignore next */\n readonly inputValues$ = input<Observable<Partial<T>>>(); // Observable para actualizar valores de inputs dinámicamente en creación/edición\n /* v8 ignore next */\n readonly customActions = input<CustomTableAction[]>([]); // Acciones personalizadas dinámicas\n /* v8 ignore next */\n readonly size = input(0); // Tamaño de la tabla (0 = sin límite, > 0 aplica max-height)\n /* v8 ignore next */\n readonly multiple = input(true); // Permite selección múltiple por defecto\n /* v8 ignore next */\n readonly searchable = input(false, { transform: booleanAttribute }); // Si es true, muestra barra de búsqueda\n /* v8 ignore next */\n readonly allowSelection = input(false, { transform: booleanAttribute }); // Si es true, permite selección de filas\n /* v8 ignore next */\n readonly noConfirm = input(false, { transform: booleanAttribute }); // Si es true, no muestra confirmaciones modales\n /* v8 ignore next */\n readonly paginated = input(false, { transform: booleanAttribute }); // Si es true, habilita paginación con limit/offset\n /* v8 ignore next */\n readonly paginationConfig = input<PaginationConfig>({ pageSize: 10 }); // Configuración de paginación (tamaño de página, total items)\n\n // Outputs - Acciones unificadas (Angular 18+ output API)\n /* v8 ignore next */\n readonly actionClick = output<{ action: string; row: T }>(); // Output unificado para TODAS las acciones (CRUD + custom)\n\n // Outputs - Utilidades\n /* v8 ignore next 4 */\n readonly searchTerm = output<string>();\n readonly errorEvent = output<string>();\n readonly selectable = output<T[]>();\n readonly paginationChange = output<PaginationChangeEvent>(); // Output para cambios de paginación (page, limit, offset)\n\n // Estado principal\n /* v8 ignore next 2 */\n readonly data = signal<T[]>([]);\n readonly searchValue = signal<string>('');\n\n // Estado de selección (delegado a servicio)\n /* v8 ignore next 4 */\n private readonly selectionState = this.selectionService.createSelectionState<T>();\n readonly selectedItems = this.selectionState.selectedItems;\n readonly selectAllChecked = this.selectionState.selectAllChecked;\n readonly selectAllIndeterminate = this.selectionState.selectAllIndeterminate;\n\n // Estado CRUD (delegado a servicio)\n /* v8 ignore next 5 */\n private readonly crudState = this.crudService.createCrudState<T>();\n readonly creating = this.crudState.creating;\n readonly newRow = this.crudState.newRow;\n readonly editing = this.crudState.editing;\n readonly editRow = this.crudState.editRow;\n\n // Estado de paginación (delegado a servicio)\n /* v8 ignore next 7 */\n private readonly paginationState = this.paginationService.createPaginationState(\n this.paginationConfig().pageSize ?? 10\n );\n readonly currentPage = this.paginationState.currentPage;\n readonly pageSize = this.paginationState.pageSize;\n readonly totalPages = this.paginationState.totalPages;\n readonly hasNextPage = this.paginationState.hasNextPage;\n readonly hasPrevPage = this.paginationState.hasPrevPage;\n\n // Keys visibles computed automáticamente\n /* v8 ignore next 7 */\n readonly keys = computed(() =>\n this.visibilityService.updateVisibleKeys(\n this.columns(),\n { data: this.data(), creating: this.creating(), editing: this.editing() }\n )\n );\n\n // Computed - Detecta acciones CRUD y custom\n /* v8 ignore next 5 */\n readonly hasAnyActions = computed(() => this.customActions().length > 0);\n readonly hasCrudCreate = computed(() => this.customActions().some(a => a.name === 'create'));\n readonly hasCrudUpdate = computed(() => this.customActions().some(a => a.name === 'update'));\n readonly hasCrudDelete = computed(() => this.customActions().some(a => a.name === 'delete'));\n readonly hasCrudCancel = computed(() => this.customActions().some(a => a.name === 'cancel'));\n\n /* v8 ignore next 5 */\n readonly shouldShowCreateButton = computed(() => {\n const createAction = this.customActions().find(a => a.name === 'create');\n if (!createAction) return false;\n return !createAction.condition || createAction.condition({} as Record<string, unknown>, this.data());\n });\n\n // Table max height computed\n /* v8 ignore next 3 */\n readonly tableMaxHeight = computed(() =>\n this.dataUtils.getTableMaxHeight(this.size())\n );\n\n /* v8 ignore next 2 */\n private dataSub?: Subscription;\n private inputValuesSub?: Subscription;\n\n constructor() {\n // Sincronizar totalItems del paginationConfig con el estado de paginación\n /* v8 ignore next 4 */\n effect(() => {\n const config = this.paginationConfig();\n if (config.totalItems !== undefined && this.paginated()) {\n this.paginationState.setTotalItems(config.totalItems);\n }\n });\n }\n\n /**\n * Maneja input de creación/edición de forma unificada\n */\n private handleInput(options: {\n event: Event;\n key: string;\n col: TableColDef | undefined;\n isEdit: boolean;\n }): void {\n const { event, key, col, isEdit } = options;\n const updateFn = isEdit\n ? this.crudState.updateEditRow.bind(this.crudState)\n : this.crudState.updateNewRow.bind(this.crudState);\n\n const value = getInputValue(event, col);\n if (value !== undefined) {\n updateFn(key, value);\n }\n }\n\n /**\n * Maneja confirmación modal de forma genérica\n */\n private async handleConfirmAction(options: {\n title: string;\n message: string;\n confirmText: string;\n action: () => void;\n }): Promise<void> {\n const { title, message, confirmText, action } = options;\n if (this.noConfirm()) {\n action();\n return;\n }\n\n const confirmed = await this.modalService.confirm({\n title,\n message,\n confirmText,\n cancelText: 'Cancelar'\n });\n\n if (confirmed) {\n action();\n }\n }\n\n\n\n ngOnInit(): void {\n const data$ = this.data$();\n if (!data$) return;\n this.dataSub = data$.subscribe({\n next: (items) => {\n this.dataUtils.applySorting(items, this.columns());\n this.data.set(items);\n this.preserveSelection();\n },\n error: (err: unknown) =>\n this.errorEvent.emit(getErrorMessage(err)),\n });\n\n // Suscribirse a inputValues$ para actualizar valores dinámicamente en creación/edición\n const inputValues$ = this.inputValues$();\n if (inputValues$) {\n this.inputValuesSub = inputValues$.subscribe({\n next: (partialValues) => {\n this.crudState.applyInputValues(partialValues);\n },\n error: (err: unknown) =>\n console.warn('Error en inputValues$:', getErrorMessage(err)),\n });\n }\n }\n\n ngOnDestroy(): void {\n this.dataSub?.unsubscribe();\n this.inputValuesSub?.unsubscribe();\n\n // Close any open modal when component is destroyed\n this.modalService.closeModal();\n }\n\n onInput(event: Event, key: string, col?: TableColDef): void {\n this.handleInput({ event, key, col, isEdit: false });\n }\n\n onEditInput(event: Event, key: string, col?: TableColDef): void {\n this.handleInput({ event, key, col, isEdit: true });\n }\n\n async onDelete(row: T): Promise<void> {\n await this.handleConfirmAction({\n title: 'Confirmar eliminación',\n message: '¿Está seguro de que desea eliminar este elemento? Esta acción no se puede deshacer.',\n confirmText: 'Eliminar',\n action: () => this.actionClick.emit({ action: 'delete', row })\n });\n }\n\n async onCancel(row: T): Promise<void> {\n await this.handleConfirmAction({\n title: 'Confirmar cancelación',\n message: '¿Está seguro de que desea cancelar este elemento?',\n confirmText: 'Cancelar elemento',\n action: () => this.actionClick.emit({ action: 'cancel', row })\n });\n }\n\n startCreate(): void {\n this.crudState.startCreate({ columns: this.columns(), data: this.data() });\n }\n\n cancelCreate(): void {\n this.crudState.cancelCreate();\n }\n\n saveCreate(): void {\n const current = this.newRow();\n if (current) {\n const convertedRow = this.convertRowTypes(current);\n const filteredRow = this.filterReadOnlyFields(convertedRow);\n this.actionClick.emit({ action: 'create', row: filteredRow as T });\n this.cancelCreate();\n }\n }\n\n onEdit(row: T): void {\n this.crudState.startEdit({ row, columns: this.columns(), data: this.data() });\n }\n\n cancelEdit(): void {\n this.crudState.cancelEdit();\n }\n\n saveEdit(row: T): void {\n const changes = this.editRow();\n if (changes) {\n const convertedChanges = this.convertRowTypes(changes);\n const filteredChanges = this.filterReadOnlyFields(convertedChanges);\n // Solo enviar los cambios filtrados junto con el ID\n const updatePayload = {\n id: (row as Record<string, unknown>)['id'],\n ...filteredChanges\n } as unknown as T;\n this.actionClick.emit({ action: 'update', row: updatePayload });\n this.cancelEdit();\n }\n }\n\n /**\n * Filtra los campos readOnly de los cambios para evitar enviarlos en las actualizaciones\n */\n private filterReadOnlyFields(changes: Partial<T>): Partial<T> {\n const columnsMap = new Map(this.columns().map(col => [col.accessor, col]));\n const filtered: Partial<T> = {};\n\n for (const [key, value] of Object.entries(changes)) {\n const col = columnsMap.get(key);\n // Solo incluir campos que no son readOnly\n if (!col?.readOnly) {\n (filtered as Record<string, unknown>)[key] = value;\n }\n }\n\n return filtered;\n } /**\n * Convierte todos los valores de una fila según los tipos definidos en las columnas\n * Asegura que los datos emitidos tengan el tipo correcto (integer, number, boolean, etc.)\n */\n private convertRowTypes(row: Partial<T>): Partial<T> {\n const converted: Record<string, unknown> = {};\n const columnsMap = new Map(this.columns().map(col => [col.accessor, col]));\n\n for (const [key, value] of Object.entries(row)) {\n const col = columnsMap.get(key);\n if (col) {\n converted[key] = this.dataConverter.convertCellValue(value, col);\n } else {\n converted[key] = value;\n }\n }\n\n return converted as Partial<T>;\n }\n\n /**\n * TrackBy function for ngFor to avoid DOM re-creation (NG0956 warning).\n */\n readonly trackById = trackById<T>;\n\n /**\n * Verifica si una acción personalizada debe mostrarse para una fila específica\n */\n readonly shouldShowAction = shouldShowAction<T>;\n\n /**\n * Obtiene el tooltip de una acción\n */\n readonly getActionTooltip = getActionTooltip;\n\n /**\n * Maneja el click en una acción personalizada dinámica\n * UPDATE activa el modo edición, otras acciones emiten directamente\n * Si la acción tiene configuración de confirmación, muestra modal antes de ejecutar\n */\n onDynamicAction(action: CustomTableAction, row: T): void {\n if (action.name === 'update') {\n this.onEdit(row);\n return;\n }\n\n if (action.name === 'delete') {\n void this.onDelete(row);\n return;\n }\n\n if (action.name === 'cancel') {\n void this.onCancel(row);\n return;\n }\n\n // Si la acción tiene confirmación configurada, mostrar modal\n if (action.confirmation) {\n void this.handleActionWithConfirmation(action, row);\n return;\n }\n\n // Sin confirmación, emitir directamente\n this.actionClick.emit({ action: action.name, row });\n }\n\n /**\n * Maneja acciones que requieren confirmación del usuario\n */\n private async handleActionWithConfirmation(action: CustomTableAction, row: T): Promise<void> {\n if (!action.confirmation) return;\n\n const confirmed = await this.modalService.confirm({\n title: action.confirmation.title,\n message: action.confirmation.message,\n confirmText: action.confirmation.confirmText ?? 'Confirmar',\n cancelText: action.confirmation.cancelText ?? 'Cancelar'\n });\n\n if (confirmed) {\n this.actionClick.emit({ action: action.name, row });\n }\n }\n\n /**\n * Handles search input changes with debouncing\n */\n onSearchInput(event: Event): void {\n const target = event.target as HTMLInputElement;\n const value = target.value;\n this.searchValue.set(value);\n this.searchTerm.emit(value);\n }\n\n /**\n * Clears the search input\n */\n clearSearch(): void {\n this.searchValue.set('');\n this.searchTerm.emit('');\n }\n\n // Referencias readonly a métodos de servicios (evita wrappers innecesarios)\n readonly getCellValue = this.dataUtils.getCellValue.bind(this.dataUtils);\n readonly getDisplayValue = this.dataUtils.getDisplayValue.bind(this.dataUtils);\n readonly getEnumDisplayValue = this.dataUtils.getEnumDisplayValue.bind(this.dataUtils);\n readonly getEnumOptions = this.dataUtils.getEnumOptions.bind(this.dataUtils);\n readonly getCellColor = this.dataUtils.getCellColor.bind(this.dataUtils);\n\n /**\n * Selection methods\n */\n clearSelection(): void {\n this.selectionState.clearSelection();\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\n }\n\n /**\n * Mantiene la selección existente después de actualizar los datos,\n * eliminando solo los IDs que ya no existen en los nuevos datos\n */\n private preserveSelection(): void {\n this.selectionState.preserveSelection(this.data());\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\n }\n\n toggleSelectAll(): void {\n this.selectionState.toggleSelectAll(this.data());\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\n }\n\n toggleItemSelection(item: T): void {\n this.selectionState.toggleItemSelection(item, this.multiple());\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\n }\n\n isItemSelected(item: T): boolean {\n return this.selectionState.isItemSelected(item);\n }\n\n\n\n // Métodos de visibilidad delegados a servicio\n isColumnVisible(column: TableColDef): boolean {\n return this.visibilityService.isColumnVisible(column, this.data(), {\n creating: this.creating(),\n row: this.newRow() ?? undefined\n });\n }\n\n isColumnVisibleInHeader(column: TableColDef): boolean {\n return this.visibilityService.isColumnVisibleInHeader(\n column,\n { data: this.data(), creating: this.creating(), editing: this.editing() }\n );\n }\n\n isColumnVisibleForRow(column: TableColDef, row: T): boolean {\n return this.visibilityService.isColumnVisibleForRow(\n column,\n { row, data: this.data(), editing: this.editing() }\n );\n }\n\n // Métodos de paginación\n onPageChange(page: number): void {\n this.paginationState.setPage(page);\n this.emitPaginationChange();\n }\n\n onNextPage(): void {\n this.paginationState.nextPage();\n this.emitPaginationChange();\n }\n\n onPrevPage(): void {\n this.paginationState.prevPage();\n this.emitPaginationChange();\n }\n\n private emitPaginationChange(): void {\n const event: PaginationChangeEvent = {\n page: this.currentPage(),\n limit: this.pageSize(),\n offset: this.paginationState.offset()\n };\n this.paginationChange.emit(event);\n }\n\n /**\n * Actualiza el total de items para calcular páginas\n * Debe ser llamado por el componente padre después de recibir datos\n */\n updateTotalItems(total: number): void {\n this.paginationState.setTotalItems(total);\n }\n\n /**\n * Obtiene el color de una acción considerando el tema actual.\n * Si la acción tiene color explícito, lo usa. Si no, aplica color por tema.\n */\n getActionColor(action: CustomTableAction): string | undefined {\n // Delete siempre en rojo (color warn de Material)\n if (action.name === 'delete') {\n return undefined; // Deja que el atributo [color]=\"warn\" lo maneje\n }\n\n // Si la acción tiene color explícito (rojo/verde para toggles), respetarlo\n if (action.color) {\n return action.color;\n }\n\n // Para acciones sin color explícito, usar el color de dark mode\n return '#e9ecef';\n }\n}\n","<!-- 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úsqueda\">\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ón: 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ágina {{ currentPage() }} de {{ totalPages() }}\n </div>\n <div class=\"pagination-controls\">\n <button type=\"button\" class=\"btn btn-sm\" [disabled]=\"!hasPrevPage()\" (click)=\"onPrevPage()\" title=\"Página 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ágina siguiente\">\n <c80-icon icon=\"arrowRight\" [size]=\".6\" [button]=\"false\" />\n </button>\n </div>\n </div>\n }\n</div>\n\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 } 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,5 +1,4 @@
1
1
  /**
2
2
  * Tipos comunes para las tablas C80
3
3
  */
4
- export {};
5
4
  //# sourceMappingURL=table.types.js.map
@@ -82,11 +82,12 @@ function convertEnumValue(value) {
82
82
  * Extrae el ID de una fila para usar como trackBy en ngFor
83
83
  * @param index - Índice de la fila
84
84
  * @param row - Fila de datos
85
+ * @param rowId - Accessor de la PK de la fila (default 'id')
85
86
  * @returns ID como string o índice como fallback
86
87
  */
87
- export function trackById(index, row) {
88
- const id = row && typeof row === 'object' && 'id' in row
89
- ? row['id']
88
+ export function trackById(index, row, rowId = 'id') {
89
+ const id = row && typeof row === 'object' && rowId in row
90
+ ? row[rowId]
90
91
  : undefined;
91
92
  return typeof id === 'string' ? id : index;
92
93
  }
@@ -1 +1 @@
1
- {"version":3,"file":"table.utils.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table.utils.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TableColDef, CustomTableAction } from './table.types';\n\n/**\n * Transform function para convertir valores string/boolean a boolean\n * Usado en @Input() con transform para habilitar sintaxis de atributos booleanos\n * @param value\n * @returns Valor convertido a boolean\n * @example [searchable]=\"true\" o simplemente searchable\n */\nexport function booleanAttribute(value: boolean | string): boolean {\n return value === '' || value === true || value === 'true';\n}\n\n/**\n * Extrae mensaje de error de forma segura desde un objeto unknown\n * @param err - Error desconocido (puede ser Error, string, object, etc.)\n * @returns Mensaje de error legible\n */\nexport function getErrorMessage(err: unknown): string {\n const error = err as { message?: string };\n return error?.message ?? 'Error al cargar datos';\n}\n\n/**\n * Obtiene el valor de un input HTML según el tipo de columna\n * IMPORTANTE: Convierte el valor al tipo correcto antes de retornarlo\n * @param event - Evento del input\n * @param col - Definición de columna (opcional)\n * @returns Valor extraído y convertido según el tipo de columna\n */\nexport function getInputValue(event: Event, col?: TableColDef): unknown {\n if (col?.type === 'boolean') {\n return (event.target as HTMLInputElement).checked;\n }\n\n const target = event.target as HTMLInputElement | HTMLSelectElement;\n const rawValue = target?.value;\n\n if (!col) {\n return rawValue;\n }\n\n return convertInputValueByType(rawValue, col.type);\n}\n\n/**\n * Convierte un valor de input según el tipo de columna especificado\n * @param rawValue - Valor crudo del input (string)\n * @param type - Tipo de columna\n * @returns Valor convertido al tipo apropiado\n */\nfunction convertInputValueByType(\n rawValue: string,\n type?: 'string' | 'number' | 'integer' | 'boolean' | 'password' | 'enum' | 'date'\n): unknown {\n if (!type || type === 'string' || type === 'password' || type === 'date') {\n return rawValue;\n }\n\n if (type === 'integer' || type === 'number') {\n return convertToNumber(rawValue, type === 'integer');\n }\n\n if (type === 'enum') {\n return convertEnumValue(rawValue);\n }\n\n return rawValue;\n}\n\n/**\n * Convierte string a number o integer\n * @param value\n * @param isInteger\n * @returns Número convertido o undefined si no es válido\n */\nfunction convertToNumber(value: string, isInteger: boolean): number | undefined {\n if (value === '' || value === null || value === undefined) {\n return undefined;\n }\n const num = Number(value);\n if (Number.isNaN(num)) {\n return undefined;\n }\n return isInteger ? Math.floor(num) : num;\n}\n\n/**\n * Convierte valor de enum (intenta convertir a número si es posible)\n * @param value\n * @returns Valor convertido a número si es posible, sino string\n */\nfunction convertEnumValue(value: string): string | number {\n const num = Number(value);\n return Number.isNaN(num) ? value : num;\n}\n\n/**\n * Extrae el ID de una fila para usar como trackBy en ngFor\n * @param index - Índice de la fila\n * @param row - Fila de datos\n * @returns ID como string o índice como fallback\n */\nexport function trackById<T extends Record<string, unknown>>(index: number, row: T): string | number {\n const id = row && typeof row === 'object' && 'id' in row\n ? (row as Record<string, unknown>)['id']\n : undefined;\n return typeof id === 'string' ? id : index;\n}\n\n/**\n * Verifica si una acción debe mostrarse para una fila específica\n * CREATE se excluye porque se maneja con el botón \"+\" en el header\n * @param action - Acción a verificar\n * @param row - Fila de datos\n * @param data - Todos los datos de la tabla (opcional)\n * @returns true si la acción debe mostrarse\n */\nexport function shouldShowAction<T extends Record<string, unknown>>(\n action: CustomTableAction,\n row: T,\n data?: T[]\n): boolean {\n if (action.name === 'create') {\n return false;\n }\n return !action.condition || action.condition(row, data);\n}\n\n/**\n * Obtiene el tooltip de una acción (usa tooltip personalizado o name por defecto)\n * @param action - Acción\n * @returns Texto del tooltip\n */\nexport function getActionTooltip(action: CustomTableAction): string {\n return action.tooltip ?? action.name;\n}\n"]}
1
+ {"version":3,"file":"table.utils.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table.utils.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TableColDef, CustomTableAction } from './table.types';\n\n/**\n * Transform function para convertir valores string/boolean a boolean\n * Usado en @Input() con transform para habilitar sintaxis de atributos booleanos\n * @param value\n * @returns Valor convertido a boolean\n * @example [searchable]=\"true\" o simplemente searchable\n */\nexport function booleanAttribute(value: boolean | string): boolean {\n return value === '' || value === true || value === 'true';\n}\n\n/**\n * Extrae mensaje de error de forma segura desde un objeto unknown\n * @param err - Error desconocido (puede ser Error, string, object, etc.)\n * @returns Mensaje de error legible\n */\nexport function getErrorMessage(err: unknown): string {\n const error = err as { message?: string };\n return error?.message ?? 'Error al cargar datos';\n}\n\n/**\n * Obtiene el valor de un input HTML según el tipo de columna\n * IMPORTANTE: Convierte el valor al tipo correcto antes de retornarlo\n * @param event - Evento del input\n * @param col - Definición de columna (opcional)\n * @returns Valor extraído y convertido según el tipo de columna\n */\nexport function getInputValue(event: Event, col?: TableColDef): unknown {\n if (col?.type === 'boolean') {\n return (event.target as HTMLInputElement).checked;\n }\n\n const target = event.target as HTMLInputElement | HTMLSelectElement;\n const rawValue = target?.value;\n\n if (!col) {\n return rawValue;\n }\n\n return convertInputValueByType(rawValue, col.type);\n}\n\n/**\n * Convierte un valor de input según el tipo de columna especificado\n * @param rawValue - Valor crudo del input (string)\n * @param type - Tipo de columna\n * @returns Valor convertido al tipo apropiado\n */\nfunction convertInputValueByType(\n rawValue: string,\n type?: 'string' | 'number' | 'integer' | 'boolean' | 'password' | 'enum' | 'date'\n): unknown {\n if (!type || type === 'string' || type === 'password' || type === 'date') {\n return rawValue;\n }\n\n if (type === 'integer' || type === 'number') {\n return convertToNumber(rawValue, type === 'integer');\n }\n\n if (type === 'enum') {\n return convertEnumValue(rawValue);\n }\n\n return rawValue;\n}\n\n/**\n * Convierte string a number o integer\n * @param value\n * @param isInteger\n * @returns Número convertido o undefined si no es válido\n */\nfunction convertToNumber(value: string, isInteger: boolean): number | undefined {\n if (value === '' || value === null || value === undefined) {\n return undefined;\n }\n const num = Number(value);\n if (Number.isNaN(num)) {\n return undefined;\n }\n return isInteger ? Math.floor(num) : num;\n}\n\n/**\n * Convierte valor de enum (intenta convertir a número si es posible)\n * @param value\n * @returns Valor convertido a número si es posible, sino string\n */\nfunction convertEnumValue(value: string): string | number {\n const num = Number(value);\n return Number.isNaN(num) ? value : num;\n}\n\n/**\n * Extrae el ID de una fila para usar como trackBy en ngFor\n * @param index - Índice de la fila\n * @param row - Fila de datos\n * @param rowId - Accessor de la PK de la fila (default 'id')\n * @returns ID como string o índice como fallback\n */\nexport function trackById<T extends Record<string, unknown>>(index: number, row: T, rowId = 'id'): string | number {\n const id = row && typeof row === 'object' && rowId in row\n ? (row as Record<string, unknown>)[rowId]\n : undefined;\n return typeof id === 'string' ? id : index;\n}\n\n/**\n * Verifica si una acción debe mostrarse para una fila específica\n * CREATE se excluye porque se maneja con el botón \"+\" en el header\n * @param action - Acción a verificar\n * @param row - Fila de datos\n * @param data - Todos los datos de la tabla (opcional)\n * @returns true si la acción debe mostrarse\n */\nexport function shouldShowAction<T extends Record<string, unknown>>(\n action: CustomTableAction,\n row: T,\n data?: T[]\n): boolean {\n if (action.name === 'create') {\n return false;\n }\n return !action.condition || action.condition(row, data);\n}\n\n/**\n * Obtiene el tooltip de una acción (usa tooltip personalizado o name por defecto)\n * @param action - Acción\n * @returns Texto del tooltip\n */\nexport function getActionTooltip(action: CustomTableAction): string {\n return action.tooltip ?? action.name;\n}\n"]}
package/index.d.ts CHANGED
@@ -3,9 +3,12 @@ export * from './lib/card-level';
3
3
  export * from './lib/header';
4
4
  export * from './lib/icon';
5
5
  export * from './lib/info-list';
6
+ export * from './lib/info-message';
6
7
  export * from './lib/input-field';
7
8
  export * from './lib/input-search';
9
+ export * from './lib/legal-disclaimer';
8
10
  export * from './lib/modal';
11
+ export * from './lib/navigation-card';
9
12
  export * from './lib/profile-stats';
10
13
  export * from './lib/rating-display';
11
14
  export * from './lib/rating-stars';
@@ -6,10 +6,11 @@ import * as i0 from "@angular/core";
6
6
  export declare class HeaderComponent {
7
7
  private readonly location;
8
8
  config: import("@angular/core").InputSignal<HeaderConfig>;
9
+ backIcon: import("@angular/core").InputSignal<string>;
9
10
  /**
10
11
  *
11
12
  */
12
13
  protected onBackClick(): void;
13
14
  static ɵfac: i0.ɵɵFactoryDeclaration<HeaderComponent, never>;
14
- static ɵcmp: i0.ɵɵComponentDeclaration<HeaderComponent, "c80-header", never, { "config": { "alias": "config"; "required": true; "isSignal": true; }; }, {}, never, ["*"], true, never>;
15
+ static ɵcmp: i0.ɵɵComponentDeclaration<HeaderComponent, "c80-header", never, { "config": { "alias": "config"; "required": true; "isSignal": true; }; "backIcon": { "alias": "backIcon"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
15
16
  }
@@ -1,8 +1,42 @@
1
+ import { InjectionToken } from '@angular/core';
1
2
  import * as i0 from "@angular/core";
3
+ /** Clave de almacenamiento donde se persiste la preferencia de tema. */
4
+ export declare const THEME_STORAGE_KEY = "theme";
5
+ /**
6
+ * Contrato mínimo de almacenamiento que necesita ThemeService.
7
+ * Permite a las apps consumidoras inyectar su propio backend
8
+ * (por ejemplo, un StorageService propio) sin acoplar la librería a localStorage.
9
+ */
10
+ export interface ThemeStorage {
11
+ /**
12
+ *
13
+ * @param key
14
+ * @returns Valor almacenado o null si no existe
15
+ */
16
+ get(key: string): string | null;
17
+ /**
18
+ *
19
+ * @param key
20
+ * @param value
21
+ */
22
+ set(key: string, value: string): void;
23
+ /**
24
+ *
25
+ * @param key
26
+ * @returns true si hay un valor almacenado para la clave
27
+ */
28
+ has(key: string): boolean;
29
+ }
30
+ /**
31
+ * Token del almacenamiento usado por ThemeService.
32
+ * El default reproduce el comportamiento histórico respaldado por localStorage.
33
+ */
34
+ export declare const THEME_STORAGE: InjectionToken<ThemeStorage>;
2
35
  /**
3
36
  *
4
37
  */
5
38
  export declare class ThemeService {
39
+ private readonly storage;
6
40
  readonly isDark: import("@angular/core").WritableSignal<boolean>;
7
41
  /**
8
42
  *
@@ -0,0 +1,2 @@
1
+ export * from './info-message.component';
2
+ export * from './info-message.types';
@@ -0,0 +1,17 @@
1
+ import type { InfoNotificationLevel, InfoMessageLink } from './info-message.types';
2
+ import * as i0 from "@angular/core";
3
+ /**
4
+ * Componente reutilizable para mostrar mensajes informativos o de advertencia
5
+ */
6
+ export declare class InfoMessageComponent {
7
+ message: import("@angular/core").InputSignal<string>;
8
+ level: import("@angular/core").InputSignal<InfoNotificationLevel>;
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;
15
+ static ɵfac: i0.ɵɵFactoryDeclaration<InfoMessageComponent, never>;
16
+ 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
+ }
@@ -0,0 +1,5 @@
1
+ export type InfoNotificationLevel = 'info' | 'warn';
2
+ export interface InfoMessageLink {
3
+ link: string;
4
+ text: string;
5
+ }
@@ -0,0 +1 @@
1
+ export * from './legal-disclaimer.component';
@@ -0,0 +1,15 @@
1
+ import * as i0 from "@angular/core";
2
+ /**
3
+ * Texto legal genérico por defecto.
4
+ * Neutro y sin dominio específico; las apps deben pasar su propio texto vía el input `text`.
5
+ */
6
+ export declare const DEFAULT_LEGAL_DISCLAIMER = "La informaci\u00F3n mostrada se proporciona \u00FAnicamente con fines orientativos y puede no estar actualizada. El uso de esta aplicaci\u00F3n es responsabilidad exclusiva del usuario.";
7
+ /**
8
+ * Componente reutilizable para mostrar avisos legales.
9
+ * Por defecto muestra un texto genérico, personalizable mediante el input `text`.
10
+ */
11
+ export declare class LegalDisclaimerComponent {
12
+ readonly text: import("@angular/core").InputSignal<string>;
13
+ static ɵfac: i0.ɵɵFactoryDeclaration<LegalDisclaimerComponent, never>;
14
+ static ɵcmp: i0.ɵɵComponentDeclaration<LegalDisclaimerComponent, "c80-legal-disclaimer", never, { "text": { "alias": "text"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
15
+ }
@@ -76,6 +76,11 @@ export declare class ModalComponent {
76
76
  * @returns Texto del botón No
77
77
  */
78
78
  getNoText(): string;
79
+ /**
80
+ *
81
+ * @returns Texto del botón OK
82
+ */
83
+ getOkText(): string;
79
84
  static ɵfac: i0.ɵɵFactoryDeclaration<ModalComponent, never>;
80
85
  static ɵcmp: i0.ɵɵComponentDeclaration<ModalComponent, "c80-modal", never, {}, {}, never, never, true, never>;
81
86
  }
@@ -23,6 +23,7 @@ export declare class ModalService {
23
23
  * @param options.message
24
24
  * @param options.confirmText
25
25
  * @param options.cancelText
26
+ * @param options.allowHtml
26
27
  * @returns Promise que resuelve true si se confirmó
27
28
  */
28
29
  confirm(options: {
@@ -30,6 +31,7 @@ export declare class ModalService {
30
31
  message: string;
31
32
  confirmText?: string;
32
33
  cancelText?: string;
34
+ allowHtml?: boolean;
33
35
  }): Promise<boolean>;
34
36
  /**
35
37
  *
@@ -38,6 +40,7 @@ export declare class ModalService {
38
40
  * @param options.message
39
41
  * @param options.yesText
40
42
  * @param options.noText
43
+ * @param options.allowHtml
41
44
  * @returns Promise que resuelve true si se eligió Sí
42
45
  */
43
46
  yesNo(options: {
@@ -45,14 +48,17 @@ export declare class ModalService {
45
48
  message: string;
46
49
  yesText?: string;
47
50
  noText?: string;
51
+ allowHtml?: boolean;
48
52
  }): Promise<boolean>;
49
53
  /**
50
54
  *
51
55
  * @param title
52
56
  * @param message
57
+ * @param allowHtml
58
+ * @param confirmText
53
59
  * @returns Promise que resuelve cuando se cierra el modal
54
60
  */
55
- info(title: string, message: string): Promise<void>;
61
+ info(title: string, message: string, allowHtml?: boolean, confirmText?: string): Promise<void>;
56
62
  /**
57
63
  *
58
64
  * @param options
@@ -60,6 +66,7 @@ export declare class ModalService {
60
66
  * @param options.message
61
67
  * @param options.confirmText
62
68
  * @param options.cancelText
69
+ * @param options.allowHtml
63
70
  * @returns Promise que resuelve true si se confirmó
64
71
  */
65
72
  warning(options: {
@@ -67,15 +74,17 @@ export declare class ModalService {
67
74
  message: string;
68
75
  confirmText?: string;
69
76
  cancelText?: string;
77
+ allowHtml?: boolean;
70
78
  }): Promise<boolean>;
71
79
  /**
72
80
  *
73
81
  * @param title
74
82
  * @param message
75
83
  * @param confirmText
84
+ * @param allowHtml
76
85
  * @returns Promise que resuelve true si se confirmó
77
86
  */
78
- error(title: string, message: string, confirmText?: string): Promise<void>;
87
+ error(title: string, message: string, confirmText?: string, allowHtml?: boolean): Promise<void>;
79
88
  /**
80
89
  * Maneja el resultado del modal y resuelve la promesa
81
90
  * @param result - Resultado de la acción del modal
@@ -8,6 +8,7 @@ export interface ModalConfig {
8
8
  yesText?: string;
9
9
  noText?: string;
10
10
  showCancel?: boolean;
11
+ allowHtml?: boolean;
11
12
  }
12
13
  export interface ModalResult {
13
14
  action: 'confirm' | 'cancel' | 'yes' | 'no';
@@ -0,0 +1,2 @@
1
+ export * from './navigation-card.component';
2
+ export * from './navigation-card.types';
@@ -0,0 +1,10 @@
1
+ import type { NavigationCard } from './navigation-card.types';
2
+ import * as i0 from "@angular/core";
3
+ export declare class NavigationCardComponent {
4
+ readonly card: import("@angular/core").InputSignal<NavigationCard>;
5
+ readonly active: import("@angular/core").InputSignal<boolean>;
6
+ readonly cardClick: import("@angular/core").OutputEmitterRef<NavigationCard>;
7
+ onCardClick(): void;
8
+ static ɵfac: i0.ɵɵFactoryDeclaration<NavigationCardComponent, never>;
9
+ static ɵcmp: i0.ɵɵComponentDeclaration<NavigationCardComponent, "c80-navigation-card", never, { "card": { "alias": "card"; "required": true; "isSignal": true; }; "active": { "alias": "active"; "required": false; "isSignal": true; }; }, { "cardClick": "cardClick"; }, never, never, true, never>;
10
+ }
@@ -0,0 +1,7 @@
1
+ import type { IconType } from '../icon';
2
+ export interface NavigationCard {
3
+ readonly title: string;
4
+ readonly icon: IconType;
5
+ readonly route: string;
6
+ readonly permission?: string;
7
+ }
@@ -7,9 +7,15 @@ import * as i0 from "@angular/core";
7
7
  * Reglas de exclusión:
8
8
  * - readOnly: true → campo NO se incluye
9
9
  * - accessor: 'id' → campo NO se incluye (IDs van en URL, no en body)
10
+ * - undefined / null → campo NO se incluye (no hubo cambio)
11
+ * - '' (cadena vacía) → se envía null para LIMPIAR el campo
10
12
  * - readOnly: false o undefined → campo se incluye
13
+ *
14
+ * La conversión de tipos delega en TableDataConverterService (que acepta
15
+ * strings, tal como llegan desde los inputs HTML).
11
16
  */
12
17
  export declare class TableDtoMapperService {
18
+ private readonly converter;
13
19
  /**
14
20
  * Mapea un objeto de fila a DTO, excluyendo campos readOnly e id
15
21
  * @param row - Datos de la fila
@@ -19,16 +25,17 @@ export declare class TableDtoMapperService {
19
25
  */
20
26
  mapToDto(row: Record<string, unknown>, columns: TableColDef[], additionalFields?: Record<string, unknown>): Record<string, unknown>;
21
27
  /**
22
- * Convierte un valor según el tipo de columna
28
+ * Convierte un valor según el tipo de columna, reutilizando
29
+ * TableDataConverterService (acepta strings provenientes de inputs HTML).
23
30
  * @param value - Valor a convertir
24
31
  * @param col - Definición de columna
25
32
  * @returns Valor convertido
26
33
  */
27
34
  private convertValue;
28
- private toInteger;
29
- private toNumber;
30
- private toBoolean;
31
- private toString;
35
+ /**
36
+ * Aplica los límites min/max declarados en la columna a un valor numérico.
37
+ */
38
+ private applyBounds;
32
39
  static ɵfac: i0.ɵɵFactoryDeclaration<TableDtoMapperService, never>;
33
40
  static ɵprov: i0.ɵɵInjectableDeclaration<TableDtoMapperService>;
34
41
  }
@@ -25,7 +25,7 @@ export declare class TableSelectionService {
25
25
  * Inicializa el estado de selección para una nueva tabla
26
26
  * @returns Objeto con signals y métodos de selección
27
27
  */
28
- createSelectionState<T extends Record<string, unknown>>(): SelectionState<T>;
28
+ createSelectionState<T extends Record<string, unknown>>(getRowId?: (item: T) => string): SelectionState<T>;
29
29
  private clearSelection;
30
30
  private toggleSelectAll;
31
31
  private toggleItemSelection;