@c80/ui 1.0.49 → 1.0.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/index.js +1 -0
- package/esm2022/index.js.map +1 -1
- package/esm2022/lib/card-level/card-level.component.js +12 -14
- package/esm2022/lib/card-level/card-level.component.js.map +1 -1
- package/esm2022/lib/icon/icon.component.js +3 -3
- package/esm2022/lib/icon/icon.component.js.map +1 -1
- package/esm2022/lib/icon/icon.constants.js +71 -13
- package/esm2022/lib/icon/icon.constants.js.map +1 -1
- package/esm2022/lib/icon/icon.types.js.map +1 -1
- package/esm2022/lib/modal/modal.component.js +7 -7
- package/esm2022/lib/modal/modal.component.js.map +1 -1
- package/esm2022/lib/modal/modal.service.js +2 -2
- package/esm2022/lib/modal/modal.service.js.map +1 -1
- package/esm2022/lib/select/select.component.js +2 -3
- package/esm2022/lib/select/select.component.js.map +1 -1
- package/esm2022/lib/snackbar/index.js +2 -0
- package/esm2022/lib/snackbar/index.js.map +1 -0
- package/esm2022/lib/snackbar/snackbar.component.js +57 -0
- package/esm2022/lib/snackbar/snackbar.component.js.map +1 -0
- package/esm2022/lib/snackbar/snackbar.model.js +2 -0
- package/esm2022/lib/snackbar/snackbar.model.js.map +1 -0
- package/esm2022/lib/snackbar/snackbar.service.js +43 -0
- package/esm2022/lib/snackbar/snackbar.service.js.map +1 -0
- package/esm2022/lib/stat-card/stat-card.component.js +3 -3
- package/esm2022/lib/stat-card/stat-card.component.js.map +1 -1
- package/esm2022/lib/table/table-column-visibility.service.js.map +1 -1
- package/esm2022/lib/table/table-crud-state.service.js.map +1 -1
- package/esm2022/lib/table/table-data-converter.service.js.map +1 -1
- package/esm2022/lib/table/table-data-utils.service.js.map +1 -1
- package/esm2022/lib/table/table-selection.service.js.map +1 -1
- package/esm2022/lib/table/table.component.js +4 -4
- package/esm2022/lib/table/table.component.js.map +1 -1
- package/esm2022/lib/table/table.utils.js +2 -2
- package/esm2022/lib/table/table.utils.js.map +1 -1
- package/index.d.ts +1 -0
- package/lib/card-level/card-level.component.d.ts +3 -4
- package/lib/icon/icon.component.d.ts +2 -2
- package/lib/icon/icon.constants.d.ts +12 -2
- package/lib/icon/icon.types.d.ts +1 -1
- package/lib/modal/modal.service.d.ts +1 -1
- package/lib/select/select.component.d.ts +2 -2
- package/lib/snackbar/index.d.ts +2 -0
- package/lib/snackbar/snackbar.component.d.ts +17 -0
- package/lib/snackbar/snackbar.model.d.ts +11 -0
- package/lib/snackbar/snackbar.service.d.ts +11 -0
- package/lib/stat-card/stat-card.component.d.ts +1 -1
- package/lib/table/table-column-visibility.service.d.ts +1 -1
- package/lib/table/table-crud-state.service.d.ts +1 -1
- package/lib/table/table-data-converter.service.d.ts +1 -1
- package/lib/table/table-data-utils.service.d.ts +1 -1
- package/lib/table/table-selection.service.d.ts +1 -1
- package/lib/table/table.component.d.ts +3 -3
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-data-converter.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table-data-converter.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { C80TableColDef } from './table.types';\n\n/**\n * Servicio para conversión y validación de tipos de datos en tablas C80\n *\n * Maneja la conversión entre diferentes tipos de datos y la validación de valores vacíos.\n * Soporta los tipos: string, number, integer, boolean, password, enum\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class TableDataConverterService {\n\n /**\n * Convierte un valor de celda basándose en el tipo de columna o datos de muestra\n * @param value - Valor a convertir\n * @param col - Definición de la columna\n * @param sampleValue - Valor de muestra para inferir el tipo (opcional)\n * @returns Valor convertido al tipo apropiado\n */\n convertCellValue(value: unknown, col: C80TableColDef, sampleValue?: unknown): unknown {\n if (col.type === 'boolean') return this.toBoolean(value);\n if (col.type === 'number') return this.toNumber(value);\n if (col.type === 'integer') return this.toInteger(value);\n if (col.type === 'string' || col.type === 'password')\n return this.toStringValue(value);\n\n // Fallback: usar datos de muestra si están disponibles\n if (sampleValue) {\n if (typeof sampleValue === 'boolean') return this.toBoolean(value);\n if (typeof sampleValue === 'number') return this.toNumber(value);\n if (typeof sampleValue === 'string') return this.toStringValue(value);\n }\n\n return value;\n }\n\n /**\n * Convierte un valor a boolean usando mejores prácticas\n * @param value - Valor a convertir\n * @returns Valor booleano\n */\n toBoolean(value: unknown): boolean {\n if (typeof value === 'boolean') return value;\n if (typeof value === 'string')\n return value.trim().toLowerCase() === 'true' || value.trim() === '1';\n if (typeof value === 'number') return value === 1;\n return false;\n }\n\n /**\n * Convierte un valor a number usando mejores prácticas\n * @param value - Valor a convertir\n * @returns Número o undefined si no es válido\n */\n toNumber(value: unknown): number | undefined {\n if (typeof value === 'number') return value;\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed === '') return undefined;\n const num = Number(trimmed);\n return Number.isNaN(num) ? undefined : num;\n }\n if (typeof value === 'boolean') return value ? 1 : 0;\n return undefined;\n }\n\n /**\n * Convierte un valor a integer usando mejores prácticas\n * @param value - Valor a convertir\n * @returns Entero o undefined si no es válido\n */\n toInteger(value: unknown): number | undefined {\n if (typeof value === 'number') return Math.floor(value);\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed === '') return undefined;\n const num = Number(trimmed);\n return Number.isNaN(num) ? undefined : Math.floor(num);\n }\n if (typeof value === 'boolean') return value ? 1 : 0;\n return undefined;\n }\n\n /**\n * Convierte un valor a string usando mejores prácticas, siempre stringifica objetos\n * @param value - Valor a convertir\n * @returns Cadena de texto\n */\n toStringValue(value: unknown): string {\n if (value == null) return '';\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean')\n return String(value);\n if (typeof value === 'object') {\n try {\n return JSON.stringify(value);\n } catch {\n return '[object Object]';\n }\n }\n // Para funciones, símbolos, undefined, etc., devolver cadena vacía\n return '';\n }\n\n /**\n * Verifica si un valor individual está vacío/nulo\n * @param value - Valor a verificar\n * @returns true si el valor se considera vacío\n */\n isValueEmpty(value: unknown): boolean {\n // Considerar vacío: null, undefined, ''\n if (value === null || value === undefined || value === '') {\n return true;\n }\n\n // Para números y booleanos, siempre son valores válidos\n if (typeof value === 'number' || typeof value === 'boolean') {\n return false;\n }\n\n // Para arrays vacíos\n if (Array.isArray(value)) {\n return value.length === 0;\n }\n\n // Para objetos vacíos\n if (typeof value === 'object' && value !== null) {\n return Object.keys(value).length === 0;\n }\n\n return false;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"table-data-converter.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table-data-converter.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport type { C80TableColDef } from './table.types';\n\n/**\n * Servicio para conversión y validación de tipos de datos en tablas C80\n *\n * Maneja la conversión entre diferentes tipos de datos y la validación de valores vacíos.\n * Soporta los tipos: string, number, integer, boolean, password, enum\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class TableDataConverterService {\n\n /**\n * Convierte un valor de celda basándose en el tipo de columna o datos de muestra\n * @param value - Valor a convertir\n * @param col - Definición de la columna\n * @param sampleValue - Valor de muestra para inferir el tipo (opcional)\n * @returns Valor convertido al tipo apropiado\n */\n convertCellValue(value: unknown, col: C80TableColDef, sampleValue?: unknown): unknown {\n if (col.type === 'boolean') return this.toBoolean(value);\n if (col.type === 'number') return this.toNumber(value);\n if (col.type === 'integer') return this.toInteger(value);\n if (col.type === 'string' || col.type === 'password')\n return this.toStringValue(value);\n\n // Fallback: usar datos de muestra si están disponibles\n if (sampleValue) {\n if (typeof sampleValue === 'boolean') return this.toBoolean(value);\n if (typeof sampleValue === 'number') return this.toNumber(value);\n if (typeof sampleValue === 'string') return this.toStringValue(value);\n }\n\n return value;\n }\n\n /**\n * Convierte un valor a boolean usando mejores prácticas\n * @param value - Valor a convertir\n * @returns Valor booleano\n */\n toBoolean(value: unknown): boolean {\n if (typeof value === 'boolean') return value;\n if (typeof value === 'string')\n return value.trim().toLowerCase() === 'true' || value.trim() === '1';\n if (typeof value === 'number') return value === 1;\n return false;\n }\n\n /**\n * Convierte un valor a number usando mejores prácticas\n * @param value - Valor a convertir\n * @returns Número o undefined si no es válido\n */\n toNumber(value: unknown): number | undefined {\n if (typeof value === 'number') return value;\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed === '') return undefined;\n const num = Number(trimmed);\n return Number.isNaN(num) ? undefined : num;\n }\n if (typeof value === 'boolean') return value ? 1 : 0;\n return undefined;\n }\n\n /**\n * Convierte un valor a integer usando mejores prácticas\n * @param value - Valor a convertir\n * @returns Entero o undefined si no es válido\n */\n toInteger(value: unknown): number | undefined {\n if (typeof value === 'number') return Math.floor(value);\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed === '') return undefined;\n const num = Number(trimmed);\n return Number.isNaN(num) ? undefined : Math.floor(num);\n }\n if (typeof value === 'boolean') return value ? 1 : 0;\n return undefined;\n }\n\n /**\n * Convierte un valor a string usando mejores prácticas, siempre stringifica objetos\n * @param value - Valor a convertir\n * @returns Cadena de texto\n */\n toStringValue(value: unknown): string {\n if (value == null) return '';\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean')\n return String(value);\n if (typeof value === 'object') {\n try {\n return JSON.stringify(value);\n } catch {\n return '[object Object]';\n }\n }\n // Para funciones, símbolos, undefined, etc., devolver cadena vacía\n return '';\n }\n\n /**\n * Verifica si un valor individual está vacío/nulo\n * @param value - Valor a verificar\n * @returns true si el valor se considera vacío\n */\n isValueEmpty(value: unknown): boolean {\n // Considerar vacío: null, undefined, ''\n if (value === null || value === undefined || value === '') {\n return true;\n }\n\n // Para números y booleanos, siempre son valores válidos\n if (typeof value === 'number' || typeof value === 'boolean') {\n return false;\n }\n\n // Para arrays vacíos\n if (Array.isArray(value)) {\n return value.length === 0;\n }\n\n // Para objetos vacíos\n if (typeof value === 'object' && value !== null) {\n return Object.keys(value).length === 0;\n }\n\n return false;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-data-utils.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table-data-utils.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { C80TableColDef } from './table.types';\n\n/**\n * Servicio para utilidades de manipulación de datos en tablas C80\n *\n * Proporciona métodos para:\n * - Acceso a valores de celdas (incluyendo propiedades anidadas)\n * - Formateo de valores para display\n * - Gestión de enums y colores\n * - Ordenamiento de datos\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class TableDataUtilsService {\n\n /**\n * Obtiene el valor de una celda usando el accessor, soportando notación de punto para propiedades anidadas\n * @param row - La fila de datos\n * @param accessor - El accessor de la columna\n * @returns El valor de la celda\n */\n getCellValue<T extends Record<string, unknown>>(row: T, accessor: string): unknown {\n if (accessor.includes('.')) {\n return this.getNestedValue(row, accessor);\n }\n return (row as Record<string, unknown>)[accessor];\n }\n\n /**\n * Obtiene el valor de un objeto usando notación de punto (ej: 'task.name')\n * @param obj - Objeto del cual obtener el valor\n * @param accessor - Ruta de acceso usando notación de punto\n * @returns El valor anidado o undefined\n */\n getNestedValue(obj: Record<string, unknown>, accessor: string): unknown {\n return accessor.split('.').reduce((current, key) => {\n return current && typeof current === 'object' ? (current as Record<string, unknown>)[key] : undefined;\n }, obj as unknown);\n }\n\n /**\n * Devuelve el valor de display para una celda, mostrando '-' para valores falsy excepto 0, false y objetos/arrays vacíos\n * @param value - Valor a formatear\n * @param col - Definición de columna (opcional) para formateo específico por tipo\n * @returns Cadena formateada para display\n */\n getDisplayValue(value: unknown, col?: C80TableColDef): string {\n return this.formatValueByType(value, col);\n }\n\n private formatValueByType(value: unknown, col?: C80TableColDef): string {\n if (value === 0) return '0';\n if (value === false) return 'false';\n if (col?.type === 'date' && value) return this.formatDateValue(value);\n if (typeof value === 'object' && value !== null) return this.formatObjectValue(value);\n if (!value) return '-';\n return this.formatPrimitiveValue(value);\n }\n\n private formatPrimitiveValue(value: unknown): string {\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n return '-';\n }\n\n /**\n * Formatea un valor de fecha a formato legible\n * @param value - Valor de fecha (Date, string ISO, timestamp)\n * @returns Fecha formateada como DD/MM/YYYY HH:MM\n */\n private formatDateValue(value: unknown): string {\n try {\n const date = this.parseDate(value);\n if (!date || Number.isNaN(date.getTime())) return '-';\n\n const day = String(date.getDate()).padStart(2, '0');\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const year = date.getFullYear();\n const hours = String(date.getHours()).padStart(2, '0');\n const minutes = String(date.getMinutes()).padStart(2, '0');\n\n return `${day}/${month}/${year} ${hours}:${minutes}`;\n } catch {\n return '-';\n }\n }\n\n private parseDate(value: unknown): Date | null {\n if (value instanceof Date) return value;\n if (typeof value === 'string' || typeof value === 'number') return new Date(value);\n return null;\n }\n\n private formatObjectValue(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch {\n return '[object Object]';\n }\n } /**\n * Obtiene el texto de display para un valor enum\n * @param value - Valor del enum\n * @param col - Definición de la columna\n * @returns Texto formateado del enum\n */\n getEnumDisplayValue(value: unknown, col: C80TableColDef): string {\n if (!col.enum || (value !== 0 && !value)) {\n return '-';\n }\n const displayValue = col.enum[value as string | number];\n return (\n displayValue ||\n (typeof value === 'string' || typeof value === 'number'\n ? String(value)\n : '-')\n );\n }\n\n /**\n * Obtiene las opciones del enum como array para dropdowns select\n * @param col - Definición de la columna\n * @returns Array de opciones con value y label\n */\n getEnumOptions(col: C80TableColDef): { value: string | number; label: string }[] {\n if (!col.enum) return [];\n return Object.entries(col.enum).map(([value, label]) => ({\n value: Number.isNaN(Number(value)) ? value : Number(value),\n label,\n }));\n }\n\n /**\n * Obtiene el color CSS para un valor de celda basado en la configuración de color de la columna\n * @param value - Valor de la celda\n * @param col - Definición de la columna\n * @returns Color CSS o undefined si no hay configuración\n */\n getCellColor(value: unknown, col: C80TableColDef): string | undefined {\n if (!col.color || (value !== 0 && !value)) {\n return undefined;\n }\n return col.color[value as string | number];\n }\n\n /**\n * Aplica ordenamiento a los items basándose en las columnas con configuración de orden\n * @param items - Array de items a ordenar (se modifica in-place)\n * @param columns - Definiciones de columnas\n */\n applySorting<T extends Record<string, unknown>>(items: T[], columns: C80TableColDef[]): void {\n const orderedColumns = columns.filter((col) => col.order);\n if (orderedColumns.length > 0) {\n for (const col of orderedColumns) {\n items.sort((a, b) => {\n const valueA = this.getCellValue(a, col.accessor) as string | number;\n const valueB = this.getCellValue(b, col.accessor) as string | number;\n\n if (col.order === 'ASC') {\n if (valueA > valueB) return 1;\n if (valueA < valueB) return -1;\n return 0;\n } else {\n if (valueA < valueB) return 1;\n if (valueA > valueB) return -1;\n return 0;\n }\n });\n }\n }\n }\n\n /**\n * Calcula el max-height de la tabla basado en el tamaño\n * @param size - Tamaño configurado (0 = sin límite)\n * @returns String CSS para max-height o undefined si sin límite\n */\n getTableMaxHeight(size: number): string | undefined {\n if (size <= 0) {\n return undefined; // Sin límite de altura\n }\n // Altura base de 400px * size\n const baseHeight = 400;\n const maxHeight = Math.round(baseHeight * size);\n return `${maxHeight}px`;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"table-data-utils.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table-data-utils.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport type { C80TableColDef } from './table.types';\n\n/**\n * Servicio para utilidades de manipulación de datos en tablas C80\n *\n * Proporciona métodos para:\n * - Acceso a valores de celdas (incluyendo propiedades anidadas)\n * - Formateo de valores para display\n * - Gestión de enums y colores\n * - Ordenamiento de datos\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class TableDataUtilsService {\n\n /**\n * Obtiene el valor de una celda usando el accessor, soportando notación de punto para propiedades anidadas\n * @param row - La fila de datos\n * @param accessor - El accessor de la columna\n * @returns El valor de la celda\n */\n getCellValue<T extends Record<string, unknown>>(row: T, accessor: string): unknown {\n if (accessor.includes('.')) {\n return this.getNestedValue(row, accessor);\n }\n return (row as Record<string, unknown>)[accessor];\n }\n\n /**\n * Obtiene el valor de un objeto usando notación de punto (ej: 'task.name')\n * @param obj - Objeto del cual obtener el valor\n * @param accessor - Ruta de acceso usando notación de punto\n * @returns El valor anidado o undefined\n */\n getNestedValue(obj: Record<string, unknown>, accessor: string): unknown {\n return accessor.split('.').reduce((current, key) => {\n return current && typeof current === 'object' ? (current as Record<string, unknown>)[key] : undefined;\n }, obj as unknown);\n }\n\n /**\n * Devuelve el valor de display para una celda, mostrando '-' para valores falsy excepto 0, false y objetos/arrays vacíos\n * @param value - Valor a formatear\n * @param col - Definición de columna (opcional) para formateo específico por tipo\n * @returns Cadena formateada para display\n */\n getDisplayValue(value: unknown, col?: C80TableColDef): string {\n return this.formatValueByType(value, col);\n }\n\n private formatValueByType(value: unknown, col?: C80TableColDef): string {\n if (value === 0) return '0';\n if (value === false) return 'false';\n if (col?.type === 'date' && value) return this.formatDateValue(value);\n if (typeof value === 'object' && value !== null) return this.formatObjectValue(value);\n if (!value) return '-';\n return this.formatPrimitiveValue(value);\n }\n\n private formatPrimitiveValue(value: unknown): string {\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n return '-';\n }\n\n /**\n * Formatea un valor de fecha a formato legible\n * @param value - Valor de fecha (Date, string ISO, timestamp)\n * @returns Fecha formateada como DD/MM/YYYY HH:MM\n */\n private formatDateValue(value: unknown): string {\n try {\n const date = this.parseDate(value);\n if (!date || Number.isNaN(date.getTime())) return '-';\n\n const day = String(date.getDate()).padStart(2, '0');\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const year = date.getFullYear();\n const hours = String(date.getHours()).padStart(2, '0');\n const minutes = String(date.getMinutes()).padStart(2, '0');\n\n return `${day}/${month}/${year} ${hours}:${minutes}`;\n } catch {\n return '-';\n }\n }\n\n private parseDate(value: unknown): Date | null {\n if (value instanceof Date) return value;\n if (typeof value === 'string' || typeof value === 'number') return new Date(value);\n return null;\n }\n\n private formatObjectValue(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch {\n return '[object Object]';\n }\n } /**\n * Obtiene el texto de display para un valor enum\n * @param value - Valor del enum\n * @param col - Definición de la columna\n * @returns Texto formateado del enum\n */\n getEnumDisplayValue(value: unknown, col: C80TableColDef): string {\n if (!col.enum || (value !== 0 && !value)) {\n return '-';\n }\n const displayValue = col.enum[value as string | number];\n return (\n displayValue ||\n (typeof value === 'string' || typeof value === 'number'\n ? String(value)\n : '-')\n );\n }\n\n /**\n * Obtiene las opciones del enum como array para dropdowns select\n * @param col - Definición de la columna\n * @returns Array de opciones con value y label\n */\n getEnumOptions(col: C80TableColDef): { value: string | number; label: string }[] {\n if (!col.enum) return [];\n return Object.entries(col.enum).map(([value, label]) => ({\n value: Number.isNaN(Number(value)) ? value : Number(value),\n label,\n }));\n }\n\n /**\n * Obtiene el color CSS para un valor de celda basado en la configuración de color de la columna\n * @param value - Valor de la celda\n * @param col - Definición de la columna\n * @returns Color CSS o undefined si no hay configuración\n */\n getCellColor(value: unknown, col: C80TableColDef): string | undefined {\n if (!col.color || (value !== 0 && !value)) {\n return undefined;\n }\n return col.color[value as string | number];\n }\n\n /**\n * Aplica ordenamiento a los items basándose en las columnas con configuración de orden\n * @param items - Array de items a ordenar (se modifica in-place)\n * @param columns - Definiciones de columnas\n */\n applySorting<T extends Record<string, unknown>>(items: T[], columns: C80TableColDef[]): void {\n const orderedColumns = columns.filter((col) => col.order);\n if (orderedColumns.length > 0) {\n for (const col of orderedColumns) {\n items.sort((a, b) => {\n const valueA = this.getCellValue(a, col.accessor) as string | number;\n const valueB = this.getCellValue(b, col.accessor) as string | number;\n\n if (col.order === 'ASC') {\n if (valueA > valueB) return 1;\n if (valueA < valueB) return -1;\n return 0;\n } else {\n if (valueA < valueB) return 1;\n if (valueA > valueB) return -1;\n return 0;\n }\n });\n }\n }\n }\n\n /**\n * Calcula el max-height de la tabla basado en el tamaño\n * @param size - Tamaño configurado (0 = sin límite)\n * @returns String CSS para max-height o undefined si sin límite\n */\n getTableMaxHeight(size: number): string | undefined {\n if (size <= 0) {\n return undefined; // Sin límite de altura\n }\n // Altura base de 400px * size\n const baseHeight = 400;\n const maxHeight = Math.round(baseHeight * size);\n return `${maxHeight}px`;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-selection.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table-selection.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAoB,MAAM,eAAe,CAAC;;AAErE;;;;;;;;GAQG;AAIH,MAAM,OAAO,qBAAqB;IAEhC;;;OAGG;IACH,oBAAoB;QAClB,MAAM,aAAa,GAAG,MAAM,CAAc,IAAI,GAAG,EAAE,yDAAC,CAAC;QACrD,MAAM,gBAAgB,GAAG,MAAM,CAAC,KAAK,4DAAC,CAAC;QACvC,MAAM,sBAAsB,GAAG,MAAM,CAAC,KAAK,kEAAC,CAAC;QAE7C,MAAM,OAAO,GAAG,EAAE,aAAa,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,CAAC;QAE5E,OAAO;YACL,aAAa,EAAE,aAAa,CAAC,UAAU,EAAE;YACzC,gBAAgB,EAAE,gBAAgB,CAAC,UAAU,EAAE;YAC/C,sBAAsB,EAAE,sBAAsB,CAAC,UAAU,EAAE;YAC3D,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC;YAClD,eAAe,EAAE,CAAC,QAAa,EAAE,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC;YAC3E,mBAAmB,EAAE,CAAC,IAAO,EAAE,QAAiB,EAAE,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,aAAa,EAAE,IAAI,EAAE,QAAQ,CAAC;YAC5G,cAAc,EAAE,CAAC,IAAO,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,aAAa,EAAE,IAAI,CAAC;YACrE,iBAAiB,EAAE,CAAC,OAAY,EAAE,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC;YAC7E,gBAAgB,EAAE,CAAC,OAAY,EAAE,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,aAAa,EAAE,OAAO,CAAC;SAClF,CAAC;IACJ,CAAC;IAEO,cAAc,CAAC,OAItB;QACC,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;QACrC,OAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpC,OAAO,CAAC,sBAAsB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IAEO,eAAe,CACrB,OAIC,EACD,QAAa;QAEb,MAAM,gBAAgB,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;QAEjD,IAAI,gBAAgB,CAAC,IAAI,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC;YAC9C,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;YACrC,OAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACpC,OAAO,CAAC,sBAAsB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC5C,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAW,CAAC,CAAC,CAAC;YACnE,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAClC,IAAI,CAAC,oBAAoB,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,gBAAgB,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;QAC7G,CAAC;IACH,CAAC;IAEO,mBAAmB,CACzB,aAAqD,EACrD,IAAO,EACP,QAAiB;QAEjB,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAW,CAAC;QAChC,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC;QAElD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,gBAAgB,CAAC,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC7B,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;aAAM,IAAI,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACpC,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC3B,CAAC;QAED,aAAa,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACtC,CAAC;IAEO,cAAc,CACpB,aAAqD,EACrD,IAAO;QAEP,OAAO,aAAa,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAW,CAAC,CAAC;IACnD,CAAC;IAEO,iBAAiB,CACvB,OAIC,EACD,OAAY;QAEZ,MAAM,gBAAgB,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;QAEjD,IAAI,gBAAgB,CAAC,IAAI,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxD,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAW,CAAC,CAAC,CAAC;QACxE,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAChC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAChE,CAAC;QAEF,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAC9C,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,CAAC,IAAI,EAAE,OAAO,CAAC,gBAAgB,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACxH,CAAC;IAEO,gBAAgB,CACtB,aAAqD,EACrD,OAAY;QAEZ,MAAM,WAAW,GAAG,aAAa,EAAE,CAAC;QACpC,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAW,CAAC,CAAC,CAAC;IACvE,CAAC;IAEO,oBAAoB,CAC1B,QAAa,EACb,aAAqB,EACrB,gBAAoD,EACpD,sBAA0D;QAE1D,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC;QAEnC,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;YACxB,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAC5B,sBAAsB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;aAAM,IAAI,aAAa,KAAK,UAAU,EAAE,CAAC;YACxC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC3B,sBAAsB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;aAAM,CAAC;YACN,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAC5B,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,aAAa,CACX,cAA2D,EAC3D,OAAY,EACZ,iBAAwC;QAExC,MAAM,aAAa,GAAG,cAAc,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAC/D,iBAAiB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACxC,CAAC;uGAvJU,qBAAqB;2GAArB,qBAAqB,cAFpB,MAAM;;2FAEP,qBAAqB;kBAHjC,UAAU;mBAAC;oBACV,UAAU,EAAE,MAAM;iBACnB","sourcesContent":["import { Injectable, signal, OutputEmitterRef } from '@angular/core';\n\n/**\n * Servicio para gestionar la selección de elementos en tablas C80\n *\n * Maneja:\n * - Selección simple y múltiple\n * - Estado de selección completa\n * - Preservación de selección tras actualizaciones de datos\n * - Emisión de eventos de selección\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class TableSelectionService {\n\n /**\n * Inicializa el estado de selección para una nueva tabla\n * @returns Objeto con signals y métodos de selección\n */\n createSelectionState<T extends Record<string, unknown>>() {\n const selectedItems = signal<Set<string>>(new Set());\n const selectAllChecked = signal(false);\n const selectAllIndeterminate = signal(false);\n\n const signals = { selectedItems, selectAllChecked, selectAllIndeterminate };\n\n return {\n selectedItems: selectedItems.asReadonly(),\n selectAllChecked: selectAllChecked.asReadonly(),\n selectAllIndeterminate: selectAllIndeterminate.asReadonly(),\n clearSelection: () => this.clearSelection(signals),\n toggleSelectAll: (allItems: T[]) => this.toggleSelectAll(signals, allItems),\n toggleItemSelection: (item: T, multiple: boolean) => this.toggleItemSelection(selectedItems, item, multiple),\n isItemSelected: (item: T) => this.isItemSelected(selectedItems, item),\n preserveSelection: (newData: T[]) => this.preserveSelection(signals, newData),\n getSelectedItems: (allData: T[]) => this.getSelectedItems(selectedItems, allData),\n };\n }\n\n private clearSelection(signals: {\n selectedItems: ReturnType<typeof signal<Set<string>>>;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n }): void {\n signals.selectedItems.set(new Set());\n signals.selectAllChecked.set(false);\n signals.selectAllIndeterminate.set(false);\n }\n\n private toggleSelectAll<T extends Record<string, unknown>>(\n signals: {\n selectedItems: ReturnType<typeof signal<Set<string>>>;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n },\n allItems: T[]\n ): void {\n const currentSelection = signals.selectedItems();\n\n if (currentSelection.size === allItems.length) {\n signals.selectedItems.set(new Set());\n signals.selectAllChecked.set(false);\n signals.selectAllIndeterminate.set(false);\n } else {\n const allIds = new Set(allItems.map(item => item['id'] as string));\n signals.selectedItems.set(allIds);\n this.updateSelectAllState(allItems, allIds.size, signals.selectAllChecked, signals.selectAllIndeterminate);\n }\n }\n\n private toggleItemSelection<T extends Record<string, unknown>>(\n selectedItems: ReturnType<typeof signal<Set<string>>>,\n item: T,\n multiple: boolean\n ): void {\n const id = item['id'] as string;\n const currentSelection = new Set(selectedItems());\n\n if (!multiple) {\n currentSelection.clear();\n if (!selectedItems().has(id)) {\n currentSelection.add(id);\n }\n } else if (currentSelection.has(id)) {\n currentSelection.delete(id);\n } else {\n currentSelection.add(id);\n }\n\n selectedItems.set(currentSelection);\n }\n\n private isItemSelected<T extends Record<string, unknown>>(\n selectedItems: ReturnType<typeof signal<Set<string>>>,\n item: T\n ): boolean {\n return selectedItems().has(item['id'] as string);\n }\n\n private preserveSelection<T extends Record<string, unknown>>(\n signals: {\n selectedItems: ReturnType<typeof signal<Set<string>>>;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n },\n newData: T[]\n ): void {\n const currentSelection = signals.selectedItems();\n\n if (currentSelection.size === 0 || newData.length === 0) {\n this.clearSelection(signals);\n return;\n }\n\n const availableIds = new Set(newData.map(item => item['id'] as string));\n const preservedSelection = new Set(\n Array.from(currentSelection).filter(id => availableIds.has(id))\n );\n\n signals.selectedItems.set(preservedSelection);\n this.updateSelectAllState(newData, preservedSelection.size, signals.selectAllChecked, signals.selectAllIndeterminate);\n }\n\n private getSelectedItems<T extends Record<string, unknown>>(\n selectedItems: ReturnType<typeof signal<Set<string>>>,\n allData: T[]\n ): T[] {\n const selectedIds = selectedItems();\n return allData.filter(item => selectedIds.has(item['id'] as string));\n }\n\n private updateSelectAllState<T extends Record<string, unknown>>(\n allItems: T[],\n selectedCount: number,\n selectAllChecked: ReturnType<typeof signal<boolean>>,\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>\n ): void {\n const totalCount = allItems.length;\n\n if (selectedCount === 0) {\n selectAllChecked.set(false);\n selectAllIndeterminate.set(false);\n } else if (selectedCount === totalCount) {\n selectAllChecked.set(true);\n selectAllIndeterminate.set(false);\n } else {\n selectAllChecked.set(false);\n selectAllIndeterminate.set(true);\n }\n }\n\n /**\n * Emite los elementos seleccionados a través del output proporcionado\n * @param selectionState - Estado de selección\n * @param allData - Todos los datos de la tabla\n * @param selectableEmitter - Output para emitir la selección\n */\n emitSelection<T extends Record<string, unknown>>(\n selectionState: { getSelectedItems: (allData: T[]) => T[] },\n allData: T[],\n selectableEmitter: OutputEmitterRef<T[]>\n ): void {\n const selectedItems = selectionState.getSelectedItems(allData);\n selectableEmitter.emit(selectedItems);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"table-selection.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table-selection.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { type OutputEmitterRef, Injectable, signal } from '@angular/core';\n\n/**\n * Servicio para gestionar la selección de elementos en tablas C80\n *\n * Maneja:\n * - Selección simple y múltiple\n * - Estado de selección completa\n * - Preservación de selección tras actualizaciones de datos\n * - Emisión de eventos de selección\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class TableSelectionService {\n\n /**\n * Inicializa el estado de selección para una nueva tabla\n * @returns Objeto con signals y métodos de selección\n */\n createSelectionState<T extends Record<string, unknown>>() {\n const selectedItems = signal<Set<string>>(new Set());\n const selectAllChecked = signal(false);\n const selectAllIndeterminate = signal(false);\n\n const signals = { selectedItems, selectAllChecked, selectAllIndeterminate };\n\n return {\n selectedItems: selectedItems.asReadonly(),\n selectAllChecked: selectAllChecked.asReadonly(),\n selectAllIndeterminate: selectAllIndeterminate.asReadonly(),\n clearSelection: () => this.clearSelection(signals),\n toggleSelectAll: (allItems: T[]) => this.toggleSelectAll(signals, allItems),\n toggleItemSelection: (item: T, multiple: boolean) => this.toggleItemSelection(selectedItems, item, multiple),\n isItemSelected: (item: T) => this.isItemSelected(selectedItems, item),\n preserveSelection: (newData: T[]) => this.preserveSelection(signals, newData),\n getSelectedItems: (allData: T[]) => this.getSelectedItems(selectedItems, allData),\n };\n }\n\n private clearSelection(signals: {\n selectedItems: ReturnType<typeof signal<Set<string>>>;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n }): void {\n signals.selectedItems.set(new Set());\n signals.selectAllChecked.set(false);\n signals.selectAllIndeterminate.set(false);\n }\n\n private toggleSelectAll<T extends Record<string, unknown>>(\n signals: {\n selectedItems: ReturnType<typeof signal<Set<string>>>;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n },\n allItems: T[]\n ): void {\n const currentSelection = signals.selectedItems();\n\n if (currentSelection.size === allItems.length) {\n signals.selectedItems.set(new Set());\n signals.selectAllChecked.set(false);\n signals.selectAllIndeterminate.set(false);\n } else {\n const allIds = new Set(allItems.map(item => item['id'] as string));\n signals.selectedItems.set(allIds);\n this.updateSelectAllState(allItems, allIds.size, signals.selectAllChecked, signals.selectAllIndeterminate);\n }\n }\n\n private toggleItemSelection<T extends Record<string, unknown>>(\n selectedItems: ReturnType<typeof signal<Set<string>>>,\n item: T,\n multiple: boolean\n ): void {\n const id = item['id'] as string;\n const currentSelection = new Set(selectedItems());\n\n if (!multiple) {\n currentSelection.clear();\n if (!selectedItems().has(id)) {\n currentSelection.add(id);\n }\n } else if (currentSelection.has(id)) {\n currentSelection.delete(id);\n } else {\n currentSelection.add(id);\n }\n\n selectedItems.set(currentSelection);\n }\n\n private isItemSelected<T extends Record<string, unknown>>(\n selectedItems: ReturnType<typeof signal<Set<string>>>,\n item: T\n ): boolean {\n return selectedItems().has(item['id'] as string);\n }\n\n private preserveSelection<T extends Record<string, unknown>>(\n signals: {\n selectedItems: ReturnType<typeof signal<Set<string>>>;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n },\n newData: T[]\n ): void {\n const currentSelection = signals.selectedItems();\n\n if (currentSelection.size === 0 || newData.length === 0) {\n this.clearSelection(signals);\n return;\n }\n\n const availableIds = new Set(newData.map(item => item['id'] as string));\n const preservedSelection = new Set(\n Array.from(currentSelection).filter(id => availableIds.has(id))\n );\n\n signals.selectedItems.set(preservedSelection);\n this.updateSelectAllState(newData, preservedSelection.size, signals.selectAllChecked, signals.selectAllIndeterminate);\n }\n\n private getSelectedItems<T extends Record<string, unknown>>(\n selectedItems: ReturnType<typeof signal<Set<string>>>,\n allData: T[]\n ): T[] {\n const selectedIds = selectedItems();\n return allData.filter(item => selectedIds.has(item['id'] as string));\n }\n\n private updateSelectAllState<T extends Record<string, unknown>>(\n allItems: T[],\n selectedCount: number,\n selectAllChecked: ReturnType<typeof signal<boolean>>,\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>\n ): void {\n const totalCount = allItems.length;\n\n if (selectedCount === 0) {\n selectAllChecked.set(false);\n selectAllIndeterminate.set(false);\n } else if (selectedCount === totalCount) {\n selectAllChecked.set(true);\n selectAllIndeterminate.set(false);\n } else {\n selectAllChecked.set(false);\n selectAllIndeterminate.set(true);\n }\n }\n\n /**\n * Emite los elementos seleccionados a través del output proporcionado\n * @param selectionState - Estado de selección\n * @param allData - Todos los datos de la tabla\n * @param selectableEmitter - Output para emitir la selección\n */\n emitSelection<T extends Record<string, unknown>>(\n selectionState: { getSelectedItems: (allData: T[]) => T[] },\n allData: T[],\n selectableEmitter: OutputEmitterRef<T[]>\n ): void {\n const selectedItems = selectionState.getSelectedItems(allData);\n selectableEmitter.emit(selectedItems);\n }\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Component, input, signal, computed, output, inject, } from '@angular/core';
|
|
1
|
+
import { Component, ChangeDetectionStrategy, input, signal, computed, output, inject, } from '@angular/core';
|
|
2
2
|
import { C80IconComponent } from '../icon';
|
|
3
3
|
import { TableColumnVisibilityService } from './table-column-visibility.service';
|
|
4
4
|
import { TableDataUtilsService } from './table-data-utils.service';
|
|
@@ -337,7 +337,7 @@ import * as i0 from "@angular/core";
|
|
|
337
337
|
async handleActionWithConfirmation(action, row) {
|
|
338
338
|
if (!action.confirmation)
|
|
339
339
|
return;
|
|
340
|
-
const confirmed = await this.modalService.confirm(action.confirmation.title, action.confirmation.message, action.confirmation.confirmText
|
|
340
|
+
const confirmed = await this.modalService.confirm(action.confirmation.title, action.confirmation.message, action.confirmation.confirmText ?? 'Confirmar', action.confirmation.cancelText ?? 'Cancelar');
|
|
341
341
|
if (confirmed) {
|
|
342
342
|
this.actionClick.emit({ action: action.name, row });
|
|
343
343
|
}
|
|
@@ -404,10 +404,10 @@ import * as i0 from "@angular/core";
|
|
|
404
404
|
return this.visibilityService.isColumnVisibleForRow(column, row, this.data(), this.editing());
|
|
405
405
|
}
|
|
406
406
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: C80TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
407
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: C80TableComponent, isStandalone: true, selector: "c80-table", inputs: { data$: { classPropertyName: "data$", publicName: "data$", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, inputValues$: { classPropertyName: "inputValues$", publicName: "inputValues$", isSignal: true, isRequired: false, transformFunction: null }, customActions: { classPropertyName: "customActions", publicName: "customActions", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, allowSelection: { classPropertyName: "allowSelection", publicName: "allowSelection", isSignal: true, isRequired: false, transformFunction: null }, noConfirm: { classPropertyName: "noConfirm", publicName: "noConfirm", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionClick: "actionClick", searchTerm: "searchTerm", errorEvent: "errorEvent", selectable: "selectable" }, ngImport: i0, template: "<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]=\".8\"></c80-icon>\n </span>\n <input type=\"text\" class=\"form-control search-input\" placeholder=\"Buscar...\" [value]=\"searchValue()\" (input)=\"onSearchInput($event)\" aria-label=\"Buscar en la tabla\" />\n @if (searchValue()) {\n <button class=\"btn btn-outline-secondary btn-borrar\" type=\"button\" (click)=\"clearSearch()\" title=\"Limpiar b\u00FAsqueda\">\n <c80-icon icon=\"cancel\" [size]=\".7\"></c80-icon>\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 {\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 (hasCrudCreate()) {\n <c80-icon button icon=\"add\" [disabled]=\"creating()\" title=\"Agregar\" [size]=\".6\" (iconClick)=\"startCreate()\"></c80-icon>\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\"></c80-icon>\n <br />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\"></c80-icon>\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 <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 <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">******</span>\n }\n @else if (col.type === 'enum') {\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\"></c80-icon>\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\"></c80-icon>\n }\n @else {\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-center actions-cell\">\n <div class=\"actions-container\">\n @if (editing() === row['id']) {\n <!-- Modo edici\u00F3n: mostrar guardar y cancelar -->\n @if (hasCrudUpdate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\" [size]=\".7\"></c80-icon>\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\" [size]=\".7\"></c80-icon>\n }\n @else {\n @for (action of customActions(); track action.name) {\n @if (shouldShowAction(action, row)) {\n <c80-icon button [icon]=\"action.icon\" [customColor]=\"action.color\" [color]=\"action.name === 'delete' ? 'warn' : 'primary'\" [title]=\"getActionTooltip(action)\" (iconClick)=\"onDynamicAction(action, row)\" [size]=\".7\"></c80-icon>\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-center actions-cell\">\n <div class=\"actions-container\">\n @if (hasCrudCreate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveCreate()\" [size]=\".7\"></c80-icon>\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelCreate()\" [size]=\".7\"></c80-icon>\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</div>\n\n<c80-modal></c80-modal>", styles: ["@charset \"UTF-8\";input[type=checkbox]{width:1.3rem!important;height:1.3rem!important;accent-color:rgba(226,0,0,.7647058824);background:#fff;margin:0 .25rem;vertical-align:middle;cursor:pointer}.table-responsive{width:100%;overflow-x:auto}.table-responsive .search-container{margin-bottom:-.06rem}.table-responsive .search-container .search-input-wrapper .input-group .btn-borrar{border-bottom-right-radius:0;border-color:#dee2e6}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text{background-color:#f8f9fa;border-color:#dee2e6;border-bottom-left-radius:0;color:#495057;width:56px}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text c80-icon{display:flex;align-items:center;justify-content:center;padding-bottom:.2rem}.table-responsive .search-container .search-input-wrapper .input-group .search-input{border-color:#dee2e6;border-bottom-right-radius:0;font-size:.95rem;outline:none!important}.table-responsive .search-container .search-input-wrapper .input-group .search-input:focus{outline:none!important}.table-responsive .search-container .search-input-wrapper .input-group .search-input::placeholder{color:#999;font-style:italic}.table-responsive .table{min-width:0px;margin-bottom:.5rem}.table-responsive .table .sticky-header{position:sticky;top:0;z-index:10;background-color:#f8f9fa!important}.table-responsive .table .sticky-header .table-actions-header{display:table-cell;vertical-align:middle;padding:.2rem .6rem!important;background-color:#f8f9fa!important}.table-responsive .table .sticky-header .actions-wrapper{display:flex;align-items:center;justify-content:center;gap:.5rem;height:100%}.table-responsive .table .sticky-header th{max-height:31px!important;vertical-align:middle!important;padding:.2rem .6rem!important;font-size:small!important;background-color:#f8f9fa!important;border-bottom:2px solid #dee2e6}.table-responsive .table tbody td{height:35px!important;min-height:35px!important;max-height:35px!important;vertical-align:middle!important;padding:.2rem .8rem!important;font-size:small}.table-responsive .table tbody tr{height:35px!important;min-height:35px!important;max-height:35px!important;cursor:pointer}.table-responsive .table tbody tr:hover{background-color:#f5f5f5}.table-responsive .table tbody input{border:1px solid rgba(34,0,255,.37);height:100%!important;font-size:smaller!important}.table-responsive .table tbody input[type=text],.table-responsive .table tbody input:not([type]){width:100%!important}.table-responsive .table tbody input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table thead th.boolean-column,.table-responsive .table tbody td.boolean-column,.table-responsive .table thead th.selection-column,.table-responsive .table tbody td.selection-column,.table-responsive .table thead th.table-actions-header,.table-responsive .table tbody td.table-actions-header{width:1%;white-space:nowrap}.table-responsive .table thead th.number-column,.table-responsive .table tbody td.number-column{width:1%;white-space:nowrap;text-align:center}.table-responsive .table thead th.number-column input[type=number],.table-responsive .table tbody td.number-column input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table .actions-cell{white-space:nowrap;padding:0!important}.table-responsive .table .actions-container{display:flex;flex-direction:row;justify-content:center;align-items:center;width:100%;height:100%}\n"], dependencies: [{ kind: "component", type: C80IconComponent, selector: "c80-icon", inputs: ["icon", "color", "customColor", "disabled", "size", "button", "border", "type", "textLeft", "textRight"], outputs: ["iconClick"] }, { kind: "component", type: C80ModalComponent, selector: "c80-modal" }] });
|
|
407
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: C80TableComponent, isStandalone: true, selector: "c80-table", inputs: { data$: { classPropertyName: "data$", publicName: "data$", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, inputValues$: { classPropertyName: "inputValues$", publicName: "inputValues$", isSignal: true, isRequired: false, transformFunction: null }, customActions: { classPropertyName: "customActions", publicName: "customActions", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, allowSelection: { classPropertyName: "allowSelection", publicName: "allowSelection", isSignal: true, isRequired: false, transformFunction: null }, noConfirm: { classPropertyName: "noConfirm", publicName: "noConfirm", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionClick: "actionClick", searchTerm: "searchTerm", errorEvent: "errorEvent", selectable: "selectable" }, ngImport: i0, template: "<!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n<div class=\"table-responsive\" [style.max-height]=\"tableMaxHeight()\" [style.overflow-y]=\"size() > 0 ? 'auto' : 'visible'\">\n <!-- Search Bar -->\n @if (searchable()) {\n <div class=\"search-container\">\n <div class=\"search-input-wrapper\">\n <div class=\"input-group\">\n <span class=\"input-group-text\">\n <c80-icon icon=\"search\" [size]=\".8\" />\n </span>\n <input type=\"text\" class=\"form-control search-input\" placeholder=\"Buscar...\" [value]=\"searchValue()\" (input)=\"onSearchInput($event)\" aria-label=\"Buscar en la tabla\" />\n @if (searchValue()) {\n <button class=\"btn btn-outline-secondary btn-borrar\" type=\"button\" (click)=\"clearSearch()\" title=\"Limpiar b\u00FAsqueda\">\n <c80-icon icon=\"cancel\" [size]=\".7\" />\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 {\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 (hasCrudCreate()) {\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 {\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-center actions-cell\">\n <div class=\"actions-container\">\n @if (editing() === row['id']) {\n <!-- Modo edici\u00F3n: mostrar guardar y cancelar -->\n @if (hasCrudUpdate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\" [size]=\".7\" />\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\" [size]=\".7\" />\n }\n @else {\n @for (action of customActions(); track action.name) {\n @if (shouldShowAction(action, row)) {\n <c80-icon button [icon]=\"action.icon\" [customColor]=\"action.color\" [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-center actions-cell\">\n <div class=\"actions-container\">\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</div>\n\n<c80-modal />", styles: ["@charset \"UTF-8\";input[type=checkbox]{width:1.3rem!important;height:1.3rem!important;accent-color:rgba(226,0,0,.7647058824);background:#fff;margin:0 .25rem;vertical-align:middle;cursor:pointer}.table-responsive{width:100%;overflow-x:auto}.table-responsive .search-container{margin-bottom:-.06rem}.table-responsive .search-container .search-input-wrapper .input-group .btn-borrar{border-bottom-right-radius:0;border-color:#dee2e6}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text{background-color:#f8f9fa;border-color:#dee2e6;border-bottom-left-radius:0;color:#495057;width:56px}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text c80-icon{display:flex;align-items:center;justify-content:center;padding-bottom:.2rem}.table-responsive .search-container .search-input-wrapper .input-group .search-input{border-color:#dee2e6;border-bottom-right-radius:0;font-size:.95rem;outline:none!important}.table-responsive .search-container .search-input-wrapper .input-group .search-input:focus{outline:none!important}.table-responsive .search-container .search-input-wrapper .input-group .search-input::placeholder{color:#999;font-style:italic}.table-responsive .table{min-width:0px;margin-bottom:.5rem}.table-responsive .table .sticky-header{position:sticky;top:0;z-index:10;background-color:#f8f9fa!important}.table-responsive .table .sticky-header .table-actions-header{display:table-cell;vertical-align:middle;padding:.2rem .6rem!important;background-color:#f8f9fa!important}.table-responsive .table .sticky-header .actions-wrapper{display:flex;align-items:center;justify-content:center;gap:.5rem;height:100%}.table-responsive .table .sticky-header th{max-height:31px!important;vertical-align:middle!important;padding:.2rem .6rem!important;font-size:small!important;background-color:#f8f9fa!important;border-bottom:2px solid #dee2e6}.table-responsive .table tbody td{height:35px!important;min-height:35px!important;max-height:35px!important;vertical-align:middle!important;padding:.2rem .8rem!important;font-size:small}.table-responsive .table tbody tr{height:35px!important;min-height:35px!important;max-height:35px!important;cursor:pointer}.table-responsive .table tbody tr:hover{background-color:#f5f5f5}.table-responsive .table tbody input{border:1px solid rgba(34,0,255,.37);height:100%!important;font-size:smaller!important}.table-responsive .table tbody input[type=text],.table-responsive .table tbody input:not([type]){width:100%!important}.table-responsive .table tbody input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table thead th.boolean-column,.table-responsive .table tbody td.boolean-column,.table-responsive .table thead th.selection-column,.table-responsive .table tbody td.selection-column,.table-responsive .table thead th.table-actions-header,.table-responsive .table tbody td.table-actions-header{width:1%;white-space:nowrap}.table-responsive .table thead th.number-column,.table-responsive .table tbody td.number-column{width:1%;white-space:nowrap;text-align:center}.table-responsive .table thead th.number-column input[type=number],.table-responsive .table tbody td.number-column input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table .actions-cell{white-space:nowrap;padding:0!important}.table-responsive .table .actions-container{display:flex;flex-direction:row;justify-content:center;align-items:center;width:100%;height:100%}\n"], dependencies: [{ kind: "component", type: C80IconComponent, selector: "c80-icon", inputs: ["icon", "color", "customColor", "disabled", "size", "button", "border", "type", "textLeft", "textRight"], outputs: ["iconClick"] }, { kind: "component", type: C80ModalComponent, selector: "c80-modal" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
408
408
|
}
|
|
409
409
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: C80TableComponent, decorators: [{
|
|
410
410
|
type: Component,
|
|
411
|
-
args: [{ selector: 'c80-table', standalone: true, imports: [C80IconComponent, C80ModalComponent], template: "<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]=\".8\"></c80-icon>\n </span>\n <input type=\"text\" class=\"form-control search-input\" placeholder=\"Buscar...\" [value]=\"searchValue()\" (input)=\"onSearchInput($event)\" aria-label=\"Buscar en la tabla\" />\n @if (searchValue()) {\n <button class=\"btn btn-outline-secondary btn-borrar\" type=\"button\" (click)=\"clearSearch()\" title=\"Limpiar b\u00FAsqueda\">\n <c80-icon icon=\"cancel\" [size]=\".7\"></c80-icon>\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 {\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 (hasCrudCreate()) {\n <c80-icon button icon=\"add\" [disabled]=\"creating()\" title=\"Agregar\" [size]=\".6\" (iconClick)=\"startCreate()\"></c80-icon>\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\"></c80-icon>\n <br />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\"></c80-icon>\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 <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 <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">******</span>\n }\n @else if (col.type === 'enum') {\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\"></c80-icon>\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\"></c80-icon>\n }\n @else {\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-center actions-cell\">\n <div class=\"actions-container\">\n @if (editing() === row['id']) {\n <!-- Modo edici\u00F3n: mostrar guardar y cancelar -->\n @if (hasCrudUpdate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\" [size]=\".7\"></c80-icon>\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\" [size]=\".7\"></c80-icon>\n }\n @else {\n @for (action of customActions(); track action.name) {\n @if (shouldShowAction(action, row)) {\n <c80-icon button [icon]=\"action.icon\" [customColor]=\"action.color\" [color]=\"action.name === 'delete' ? 'warn' : 'primary'\" [title]=\"getActionTooltip(action)\" (iconClick)=\"onDynamicAction(action, row)\" [size]=\".7\"></c80-icon>\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-center actions-cell\">\n <div class=\"actions-container\">\n @if (hasCrudCreate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveCreate()\" [size]=\".7\"></c80-icon>\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelCreate()\" [size]=\".7\"></c80-icon>\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</div>\n\n<c80-modal></c80-modal>", styles: ["@charset \"UTF-8\";input[type=checkbox]{width:1.3rem!important;height:1.3rem!important;accent-color:rgba(226,0,0,.7647058824);background:#fff;margin:0 .25rem;vertical-align:middle;cursor:pointer}.table-responsive{width:100%;overflow-x:auto}.table-responsive .search-container{margin-bottom:-.06rem}.table-responsive .search-container .search-input-wrapper .input-group .btn-borrar{border-bottom-right-radius:0;border-color:#dee2e6}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text{background-color:#f8f9fa;border-color:#dee2e6;border-bottom-left-radius:0;color:#495057;width:56px}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text c80-icon{display:flex;align-items:center;justify-content:center;padding-bottom:.2rem}.table-responsive .search-container .search-input-wrapper .input-group .search-input{border-color:#dee2e6;border-bottom-right-radius:0;font-size:.95rem;outline:none!important}.table-responsive .search-container .search-input-wrapper .input-group .search-input:focus{outline:none!important}.table-responsive .search-container .search-input-wrapper .input-group .search-input::placeholder{color:#999;font-style:italic}.table-responsive .table{min-width:0px;margin-bottom:.5rem}.table-responsive .table .sticky-header{position:sticky;top:0;z-index:10;background-color:#f8f9fa!important}.table-responsive .table .sticky-header .table-actions-header{display:table-cell;vertical-align:middle;padding:.2rem .6rem!important;background-color:#f8f9fa!important}.table-responsive .table .sticky-header .actions-wrapper{display:flex;align-items:center;justify-content:center;gap:.5rem;height:100%}.table-responsive .table .sticky-header th{max-height:31px!important;vertical-align:middle!important;padding:.2rem .6rem!important;font-size:small!important;background-color:#f8f9fa!important;border-bottom:2px solid #dee2e6}.table-responsive .table tbody td{height:35px!important;min-height:35px!important;max-height:35px!important;vertical-align:middle!important;padding:.2rem .8rem!important;font-size:small}.table-responsive .table tbody tr{height:35px!important;min-height:35px!important;max-height:35px!important;cursor:pointer}.table-responsive .table tbody tr:hover{background-color:#f5f5f5}.table-responsive .table tbody input{border:1px solid rgba(34,0,255,.37);height:100%!important;font-size:smaller!important}.table-responsive .table tbody input[type=text],.table-responsive .table tbody input:not([type]){width:100%!important}.table-responsive .table tbody input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table thead th.boolean-column,.table-responsive .table tbody td.boolean-column,.table-responsive .table thead th.selection-column,.table-responsive .table tbody td.selection-column,.table-responsive .table thead th.table-actions-header,.table-responsive .table tbody td.table-actions-header{width:1%;white-space:nowrap}.table-responsive .table thead th.number-column,.table-responsive .table tbody td.number-column{width:1%;white-space:nowrap;text-align:center}.table-responsive .table thead th.number-column input[type=number],.table-responsive .table tbody td.number-column input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table .actions-cell{white-space:nowrap;padding:0!important}.table-responsive .table .actions-container{display:flex;flex-direction:row;justify-content:center;align-items:center;width:100%;height:100%}\n"] }]
|
|
411
|
+
args: [{ selector: 'c80-table', standalone: true, imports: [C80IconComponent, C80ModalComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n<div class=\"table-responsive\" [style.max-height]=\"tableMaxHeight()\" [style.overflow-y]=\"size() > 0 ? 'auto' : 'visible'\">\n <!-- Search Bar -->\n @if (searchable()) {\n <div class=\"search-container\">\n <div class=\"search-input-wrapper\">\n <div class=\"input-group\">\n <span class=\"input-group-text\">\n <c80-icon icon=\"search\" [size]=\".8\" />\n </span>\n <input type=\"text\" class=\"form-control search-input\" placeholder=\"Buscar...\" [value]=\"searchValue()\" (input)=\"onSearchInput($event)\" aria-label=\"Buscar en la tabla\" />\n @if (searchValue()) {\n <button class=\"btn btn-outline-secondary btn-borrar\" type=\"button\" (click)=\"clearSearch()\" title=\"Limpiar b\u00FAsqueda\">\n <c80-icon icon=\"cancel\" [size]=\".7\" />\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 {\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 (hasCrudCreate()) {\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 {\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-center actions-cell\">\n <div class=\"actions-container\">\n @if (editing() === row['id']) {\n <!-- Modo edici\u00F3n: mostrar guardar y cancelar -->\n @if (hasCrudUpdate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\" [size]=\".7\" />\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\" [size]=\".7\" />\n }\n @else {\n @for (action of customActions(); track action.name) {\n @if (shouldShowAction(action, row)) {\n <c80-icon button [icon]=\"action.icon\" [customColor]=\"action.color\" [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-center actions-cell\">\n <div class=\"actions-container\">\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</div>\n\n<c80-modal />", styles: ["@charset \"UTF-8\";input[type=checkbox]{width:1.3rem!important;height:1.3rem!important;accent-color:rgba(226,0,0,.7647058824);background:#fff;margin:0 .25rem;vertical-align:middle;cursor:pointer}.table-responsive{width:100%;overflow-x:auto}.table-responsive .search-container{margin-bottom:-.06rem}.table-responsive .search-container .search-input-wrapper .input-group .btn-borrar{border-bottom-right-radius:0;border-color:#dee2e6}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text{background-color:#f8f9fa;border-color:#dee2e6;border-bottom-left-radius:0;color:#495057;width:56px}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text c80-icon{display:flex;align-items:center;justify-content:center;padding-bottom:.2rem}.table-responsive .search-container .search-input-wrapper .input-group .search-input{border-color:#dee2e6;border-bottom-right-radius:0;font-size:.95rem;outline:none!important}.table-responsive .search-container .search-input-wrapper .input-group .search-input:focus{outline:none!important}.table-responsive .search-container .search-input-wrapper .input-group .search-input::placeholder{color:#999;font-style:italic}.table-responsive .table{min-width:0px;margin-bottom:.5rem}.table-responsive .table .sticky-header{position:sticky;top:0;z-index:10;background-color:#f8f9fa!important}.table-responsive .table .sticky-header .table-actions-header{display:table-cell;vertical-align:middle;padding:.2rem .6rem!important;background-color:#f8f9fa!important}.table-responsive .table .sticky-header .actions-wrapper{display:flex;align-items:center;justify-content:center;gap:.5rem;height:100%}.table-responsive .table .sticky-header th{max-height:31px!important;vertical-align:middle!important;padding:.2rem .6rem!important;font-size:small!important;background-color:#f8f9fa!important;border-bottom:2px solid #dee2e6}.table-responsive .table tbody td{height:35px!important;min-height:35px!important;max-height:35px!important;vertical-align:middle!important;padding:.2rem .8rem!important;font-size:small}.table-responsive .table tbody tr{height:35px!important;min-height:35px!important;max-height:35px!important;cursor:pointer}.table-responsive .table tbody tr:hover{background-color:#f5f5f5}.table-responsive .table tbody input{border:1px solid rgba(34,0,255,.37);height:100%!important;font-size:smaller!important}.table-responsive .table tbody input[type=text],.table-responsive .table tbody input:not([type]){width:100%!important}.table-responsive .table tbody input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table thead th.boolean-column,.table-responsive .table tbody td.boolean-column,.table-responsive .table thead th.selection-column,.table-responsive .table tbody td.selection-column,.table-responsive .table thead th.table-actions-header,.table-responsive .table tbody td.table-actions-header{width:1%;white-space:nowrap}.table-responsive .table thead th.number-column,.table-responsive .table tbody td.number-column{width:1%;white-space:nowrap;text-align:center}.table-responsive .table thead th.number-column input[type=number],.table-responsive .table tbody td.number-column input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table .actions-cell{white-space:nowrap;padding:0!important}.table-responsive .table .actions-container{display:flex;flex-direction:row;justify-content:center;align-items:center;width:100%;height:100%}\n"] }]
|
|
412
412
|
}], propDecorators: { data$: [{ type: i0.Input, args: [{ isSignal: true, alias: "data$", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], inputValues$: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputValues$", required: false }] }], customActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "customActions", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], allowSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowSelection", required: false }] }], noConfirm: [{ type: i0.Input, args: [{ isSignal: true, alias: "noConfirm", required: false }] }], actionClick: [{ type: i0.Output, args: ["actionClick"] }], searchTerm: [{ type: i0.Output, args: ["searchTerm"] }], errorEvent: [{ type: i0.Output, args: ["errorEvent"] }], selectable: [{ type: i0.Output, args: ["selectable"] }] } });
|
|
413
413
|
//# sourceMappingURL=table.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table.component.ts","../../../../../libs/ui/src/lib/table/table.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n input,\n signal,\n computed,\n output,\n OnInit,\n OnDestroy,\n inject,\n} from '@angular/core';\nimport { Observable, Subscription } from 'rxjs';\nimport { C80IconComponent } 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 { C80TableColDef, CustomTableAction } from './table.types';\nimport { C80ModalComponent, 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: [C80IconComponent, C80ModalComponent],\n templateUrl: './table.component.html',\n styleUrl: './table.component.scss',\n})\nexport class C80TableComponent<T extends Record<string, unknown>> implements OnInit, OnDestroy {\n // Servicios inyectados\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\n // Inputs\n readonly data$ = input.required<Observable<T[]>>();\n readonly columns = input<C80TableColDef[]>([]);\n readonly inputValues$ = input<Observable<Partial<T>>>(); // Observable para actualizar valores de inputs dinámicamente en creación/edición\n readonly customActions = input<CustomTableAction[]>([]); // Acciones personalizadas dinámicas\n readonly size = input(0); // Tamaño de la tabla (0 = sin límite, > 0 aplica max-height)\n readonly multiple = input(true); // Permite selección múltiple por defecto\n readonly searchable = input(false, { transform: booleanAttribute }); // Si es true, muestra barra de búsqueda\n readonly allowSelection = input(false, { transform: booleanAttribute }); // Si es true, permite selección de filas\n readonly noConfirm = input(false, { transform: booleanAttribute }); // Si es true, no muestra confirmaciones modales\n\n // Outputs - Acciones unificadas (Angular 18+ output API)\n readonly actionClick = output<{ action: string; row: T }>(); // Output unificado para TODAS las acciones (CRUD + custom)\n\n // Outputs - Utilidades\n readonly searchTerm = output<string>();\n readonly errorEvent = output<string>();\n readonly selectable = output<T[]>();\n\n // Estado principal\n readonly data = signal<T[]>([]);\n readonly searchValue = signal<string>('');\n\n // Estado de selección (delegado a servicio)\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 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 // Keys visibles computed automáticamente\n readonly keys = computed(() =>\n this.visibilityService.updateVisibleKeys(\n this.columns(),\n this.data(),\n this.creating(),\n this.editing()\n )\n );\n\n // Computed - Detecta acciones CRUD y custom\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 // Table max height computed\n readonly tableMaxHeight = computed(() =>\n this.dataUtils.getTableMaxHeight(this.size())\n );\n\n private dataSub?: Subscription;\n private inputValuesSub?: Subscription;\n\n /**\n * Maneja input de creación/edición de forma unificada\n */\n private handleInput(\n event: Event,\n key: string,\n col: C80TableColDef | undefined,\n isEdit: boolean\n ): void {\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(\n title: string,\n message: string,\n confirmText: string,\n action: () => void\n ): Promise<void> {\n if (this.noConfirm()) {\n action();\n return;\n }\n\n const confirmed = await this.modalService.confirm(\n title,\n message,\n confirmText,\n 'Cancelar'\n );\n\n if (confirmed) {\n action();\n }\n }\n\n\n\n ngOnInit() {\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() {\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?: C80TableColDef): void {\n this.handleInput(event, key, col, false);\n }\n\n onEditInput(event: Event, key: string, col?: C80TableColDef): void {\n this.handleInput(event, key, col, true);\n }\n\n async onDelete(row: T): Promise<void> {\n await this.handleConfirmAction(\n 'Confirmar eliminación',\n '¿Está seguro de que desea eliminar este elemento? Esta acción no se puede deshacer.',\n 'Eliminar',\n () => this.actionClick.emit({ action: 'delete', row })\n );\n }\n\n async onCancel(row: T): Promise<void> {\n await this.handleConfirmAction(\n 'Confirmar cancelación',\n '¿Está seguro de que desea cancelar este elemento?',\n 'Cancelar elemento',\n () => this.actionClick.emit({ action: 'cancel', row })\n );\n }\n\n startCreate(): void {\n this.crudState.startCreate(this.columns(), 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 this.actionClick.emit({ action: 'create', row: convertedRow as T });\n this.cancelCreate();\n }\n }\n\n onEdit(row: T): void {\n this.crudState.startEdit(row, this.columns(), 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 updatedRow = { ...row, ...convertedChanges } as T;\n this.actionClick.emit({ action: 'update', row: updatedRow });\n this.cancelEdit();\n }\n }\n\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 action.confirmation.title,\n action.confirmation.message,\n action.confirmation.confirmText || 'Confirmar',\n 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: C80TableColDef): boolean {\n return this.visibilityService.isColumnVisible(column, this.data(), {\n creating: this.creating(),\n row: this.newRow() ?? undefined\n });\n }\n\n isColumnVisibleInHeader(column: C80TableColDef): boolean {\n return this.visibilityService.isColumnVisibleInHeader(\n column,\n this.data(),\n this.creating(),\n this.editing()\n );\n }\n\n isColumnVisibleForRow(column: C80TableColDef, row: T): boolean {\n return this.visibilityService.isColumnVisibleForRow(\n column,\n row,\n this.data(),\n this.editing()\n );\n }\n}\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]=\".8\"></c80-icon>\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]=\".7\"></c80-icon>\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 {\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 (hasCrudCreate()) {\n <c80-icon button icon=\"add\" [disabled]=\"creating()\" title=\"Agregar\" [size]=\".6\" (iconClick)=\"startCreate()\"></c80-icon>\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\"></c80-icon>\n <br />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\"></c80-icon>\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 <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 <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">******</span>\n }\n @else if (col.type === 'enum') {\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\"></c80-icon>\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\"></c80-icon>\n }\n @else {\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-center actions-cell\">\n <div class=\"actions-container\">\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\"></c80-icon>\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\" [size]=\".7\"></c80-icon>\n }\n @else {\n @for (action of customActions(); track action.name) {\n @if (shouldShowAction(action, row)) {\n <c80-icon button [icon]=\"action.icon\" [customColor]=\"action.color\" [color]=\"action.name === 'delete' ? 'warn' : 'primary'\" [title]=\"getActionTooltip(action)\" (iconClick)=\"onDynamicAction(action, row)\" [size]=\".7\"></c80-icon>\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-center actions-cell\">\n <div class=\"actions-container\">\n @if (hasCrudCreate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveCreate()\" [size]=\".7\"></c80-icon>\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelCreate()\" [size]=\".7\"></c80-icon>\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</div>\n\n<c80-modal></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 {\n type OnInit,\n type OnDestroy,\n Component,\n ChangeDetectionStrategy,\n input,\n signal,\n computed,\n output,\n inject,\n} from '@angular/core';\nimport type { Observable, Subscription } from 'rxjs';\nimport { C80IconComponent } 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 type { C80TableColDef, CustomTableAction } from './table.types';\nimport { C80ModalComponent, 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: [C80IconComponent, C80ModalComponent],\n templateUrl: './table.component.html',\n styleUrl: './table.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class C80TableComponent<T extends Record<string, unknown>> implements OnInit, OnDestroy {\n // Servicios inyectados\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\n // Inputs\n readonly data$ = input.required<Observable<T[]>>();\n readonly columns = input<C80TableColDef[]>([]);\n readonly inputValues$ = input<Observable<Partial<T>>>(); // Observable para actualizar valores de inputs dinámicamente en creación/edición\n readonly customActions = input<CustomTableAction[]>([]); // Acciones personalizadas dinámicas\n readonly size = input(0); // Tamaño de la tabla (0 = sin límite, > 0 aplica max-height)\n readonly multiple = input(true); // Permite selección múltiple por defecto\n readonly searchable = input(false, { transform: booleanAttribute }); // Si es true, muestra barra de búsqueda\n readonly allowSelection = input(false, { transform: booleanAttribute }); // Si es true, permite selección de filas\n readonly noConfirm = input(false, { transform: booleanAttribute }); // Si es true, no muestra confirmaciones modales\n\n // Outputs - Acciones unificadas (Angular 18+ output API)\n readonly actionClick = output<{ action: string; row: T }>(); // Output unificado para TODAS las acciones (CRUD + custom)\n\n // Outputs - Utilidades\n readonly searchTerm = output<string>();\n readonly errorEvent = output<string>();\n readonly selectable = output<T[]>();\n\n // Estado principal\n readonly data = signal<T[]>([]);\n readonly searchValue = signal<string>('');\n\n // Estado de selección (delegado a servicio)\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 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 // Keys visibles computed automáticamente\n readonly keys = computed(() =>\n this.visibilityService.updateVisibleKeys(\n this.columns(),\n this.data(),\n this.creating(),\n this.editing()\n )\n );\n\n // Computed - Detecta acciones CRUD y custom\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 // Table max height computed\n readonly tableMaxHeight = computed(() =>\n this.dataUtils.getTableMaxHeight(this.size())\n );\n\n private dataSub?: Subscription;\n private inputValuesSub?: Subscription;\n\n /**\n * Maneja input de creación/edición de forma unificada\n */\n private handleInput(\n event: Event,\n key: string,\n col: C80TableColDef | undefined,\n isEdit: boolean\n ): void {\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(\n title: string,\n message: string,\n confirmText: string,\n action: () => void\n ): Promise<void> {\n if (this.noConfirm()) {\n action();\n return;\n }\n\n const confirmed = await this.modalService.confirm(\n title,\n message,\n confirmText,\n 'Cancelar'\n );\n\n if (confirmed) {\n action();\n }\n }\n\n\n\n ngOnInit() {\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() {\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?: C80TableColDef): void {\n this.handleInput(event, key, col, false);\n }\n\n onEditInput(event: Event, key: string, col?: C80TableColDef): void {\n this.handleInput(event, key, col, true);\n }\n\n async onDelete(row: T): Promise<void> {\n await this.handleConfirmAction(\n 'Confirmar eliminación',\n '¿Está seguro de que desea eliminar este elemento? Esta acción no se puede deshacer.',\n 'Eliminar',\n () => this.actionClick.emit({ action: 'delete', row })\n );\n }\n\n async onCancel(row: T): Promise<void> {\n await this.handleConfirmAction(\n 'Confirmar cancelación',\n '¿Está seguro de que desea cancelar este elemento?',\n 'Cancelar elemento',\n () => this.actionClick.emit({ action: 'cancel', row })\n );\n }\n\n startCreate(): void {\n this.crudState.startCreate(this.columns(), 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 this.actionClick.emit({ action: 'create', row: convertedRow as T });\n this.cancelCreate();\n }\n }\n\n onEdit(row: T): void {\n this.crudState.startEdit(row, this.columns(), 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 updatedRow = { ...row, ...convertedChanges } as T;\n this.actionClick.emit({ action: 'update', row: updatedRow });\n this.cancelEdit();\n }\n }\n\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 action.confirmation.title,\n action.confirmation.message,\n action.confirmation.confirmText ?? 'Confirmar',\n 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: C80TableColDef): boolean {\n return this.visibilityService.isColumnVisible(column, this.data(), {\n creating: this.creating(),\n row: this.newRow() ?? undefined\n });\n }\n\n isColumnVisibleInHeader(column: C80TableColDef): boolean {\n return this.visibilityService.isColumnVisibleInHeader(\n column,\n this.data(),\n this.creating(),\n this.editing()\n );\n }\n\n isColumnVisibleForRow(column: C80TableColDef, row: T): boolean {\n return this.visibilityService.isColumnVisibleForRow(\n column,\n row,\n this.data(),\n this.editing()\n );\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]=\".8\" />\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]=\".7\" />\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 {\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 (hasCrudCreate()) {\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 {\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-center actions-cell\">\n <div class=\"actions-container\">\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)) {\n <c80-icon button [icon]=\"action.icon\" [customColor]=\"action.color\" [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-center actions-cell\">\n <div class=\"actions-container\">\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</div>\n\n<c80-modal />"]}
|
|
@@ -13,7 +13,7 @@ export function booleanAttribute(value) {
|
|
|
13
13
|
*/
|
|
14
14
|
export function getErrorMessage(err) {
|
|
15
15
|
const error = err;
|
|
16
|
-
return error?.message
|
|
16
|
+
return error?.message ?? 'Error al cargar datos';
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
19
|
* Obtiene el valor de un input HTML según el tipo de columna
|
|
@@ -102,6 +102,6 @@ export function shouldShowAction(action, row) {
|
|
|
102
102
|
* @returns Texto del tooltip
|
|
103
103
|
*/
|
|
104
104
|
export function getActionTooltip(action) {
|
|
105
|
-
return action.tooltip
|
|
105
|
+
return action.tooltip ?? action.name;
|
|
106
106
|
}
|
|
107
107
|
//# sourceMappingURL=table.utils.js.map
|