@zentto/datagrid-core
v1.7.0
Published
Pure logic engine for ZenttoDataGrid — sort, filter, group, pivot, aggregate, export. Zero UI dependencies.
Downloads
1,863
Maintainers
Readme
@zentto/datagrid-core
Motor de logica puro para ZenttoDataGrid — ordenamiento, filtrado, agrupacion, pivot, agregacion, formulas, exportacion y mas. Sin dependencias de UI.
Este paquete es el nucleo sin interfaz del ecosistema @zentto/datagrid. Puede usarse de forma independiente en cualquier entorno JavaScript/TypeScript para procesar datos tabulares, o como base para integraciones en frameworks propios.
Paquete privado — pertenece a la organizacion npm @zentto. Para instalarlo necesitas autenticarte con un token npm de la org.
Instalacion
# Configurar el token de la org (una sola vez)
npm config set //registry.npmjs.org/:_authToken <TOKEN_NPM_ZENTTO>
# Instalar el paquete
npm install @zentto/datagrid-coreUso basico
import {
sortRows,
filterRows,
groupRows,
pivotRows,
aggregate,
computeTotals,
} from '@zentto/datagrid-core';
import type { ColumnDef, GridRow, FilterRule, SortEntry } from '@zentto/datagrid-core';
const columns: ColumnDef[] = [
{ field: 'nombre', header: 'Producto', sortable: true, filterable: true },
{ field: 'precio', header: 'Precio', type: 'number', aggregation: 'sum' },
{ field: 'categoria', header: 'Categoria', sortable: true, groupable: true },
];
const rows: GridRow[] = [
{ id: 1, nombre: 'Arroz Premium', precio: 45.00, categoria: 'Alimentos' },
{ id: 2, nombre: 'Aceite de Oliva', precio: 120.00, categoria: 'Alimentos' },
{ id: 3, nombre: 'Detergente', precio: 75.00, categoria: 'Limpieza' },
];
// Ordenar por precio descendente
const sorted = sortRows(rows, [{ field: 'precio', direction: 'desc' }]);
// Filtrar por categoria
const filtered = filterRows(rows, [
{ field: 'categoria', operator: 'equals', value: 'Alimentos' },
]);
// Calcular totales
const totals = computeTotals(rows, columns);
// { precio: 240, __zentto_totals__: true, ... }API
Funciones de datos
| Funcion | Descripcion | Parametros | Retorno |
|---------|-------------|------------|---------|
| sortRows(rows, sorts) | Ordena filas por multiples columnas (sort estable, locale-aware) | rows: GridRow[], sorts: SortEntry[] | GridRow[] |
| filterRows(rows, rules) | Aplica reglas de filtro combinadas con AND | rows: GridRow[], rules: FilterRule[] | GridRow[] |
| quickSearch(rows, query, fields?) | Busqueda de texto libre en todos los campos | rows: GridRow[], query: string, fields?: string[] | GridRow[] |
| aggregate(rows, field, fn) | Calcula una agregacion numerica sobre un campo | rows: GridRow[], field: string, fn: AggregationType | number |
| computeTotals(rows, columns, label?) | Genera la fila de totales para columnas con aggregation | rows: GridRow[], columns: ColumnDef[], label?: string | GridRow |
| groupRows(rows, config) | Agrupa filas con subtotales opcionales | rows: GridRow[], config: RowGroupingConfig | GroupedResult |
| pivotRows(rows, config) | Transforma filas planas en tabla pivot | rows: GridRow[], config: PivotConfig | PivotResult |
| paginateRows(rows, model) | Pagina filas del lado del cliente | rows: GridRow[], model: PaginationModel | PaginationResult |
Formulas
| Funcion | Descripcion | Parametros | Retorno |
|---------|-------------|------------|---------|
| evaluateFormula(formula, row, allRows) | Evalua una expresion tipo Excel para una fila | formula: string, row: GridRow, allRows: GridRow[] | unknown |
| applyFormulas(rows, formulas) | Aplica multiples definiciones de formula a todas las filas | rows: GridRow[], formulas: FormulaDefinition[] | GridRow[] |
Exportacion
| Funcion | Descripcion | Parametros | Retorno |
|---------|-------------|------------|---------|
| toCsv(rows, columns) | Genera string CSV con encabezados | rows: GridRow[], columns: ColumnDef[] | string |
| downloadCsv(rows, columns, filename?) | Descarga CSV como archivo (browser) | rows: GridRow[], columns: ColumnDef[], filename?: string | void |
| toJson(rows, columns) | Serializa a JSON | rows: GridRow[], columns: ColumnDef[] | string |
| downloadJson(rows, columns, filename?) | Descarga JSON como archivo (browser) | mismos que arriba | void |
| toExcelHtml(rows, columns) | Genera HTML compatible con Excel | rows: GridRow[], columns: ColumnDef[] | string |
| downloadExcel(rows, columns, filename?) | Descarga archivo .xls (browser) | mismos que arriba | void |
| toMarkdown(rows, columns) | Genera tabla Markdown | rows: GridRow[], columns: ColumnDef[] | string |
| generatePrintHtml(rows, columns, options?) | Genera HTML optimizado para imprimir/PDF | rows: GridRow[], columns: ColumnDef[], options?: PrintOptions | string |
Busqueda y seleccion
| Funcion | Descripcion | Parametros | Retorno |
|---------|-------------|------------|---------|
| findInGrid(rows, columns, query) | Encuentra celdas que coinciden con el query (tipo Ctrl+F) | rows: GridRow[], columns: ColumnDef[], query: string | FindMatch[] |
| copyToClipboard(rows, columns) | Copia filas al portapapeles como texto tabulado | rows: GridRow[], columns: ColumnDef[] | Promise<void> |
| copyRangeToClipboard(rows, columns, range) | Copia un rango de celdas seleccionado | rows: GridRow[], columns: ColumnDef[], range: NormalizedRange | Promise<void> |
| parseClipboardData(text) | Parsea texto del portapapeles en formato tabular | text: string | PasteData |
| applyPasteData(rows, paste, startRow, startCol, columns) | Aplica datos pegados desde portapapeles | multiples parametros | GridRow[] |
| normalizeRange(range) | Normaliza un rango de seleccion (garantiza start <= end) | range: SelectionRange | NormalizedRange |
| isCellInRange(range, row, col) | Verifica si una celda esta dentro de un rango | range: NormalizedRange, row: number, col: number | boolean |
Edicion avanzada
| Funcion / Clase | Descripcion | Uso principal |
|-----------------|-------------|---------------|
| applyBatchEdit(rows, changes) | Aplica multiples cambios de celda en una operacion | Edicion masiva sin mutacion |
| validateValue(value, rule) | Valida un valor contra una regla de validacion | Edicion inline con validacion |
| evaluateConditionalFormat(value, rules) | Evalua reglas de formato condicional para una celda | Estilo dinamico por condicion |
| UndoRedoStack | Clase para historial de ediciones (undo/redo) | new UndoRedoStack(maxSize?) |
Virtualizacion y layout
| Funcion | Descripcion | Retorno |
|---------|-------------|---------|
| calculateVirtualScroll(config) | Calcula ventana de filas visibles para scroll virtual | VirtualScrollResult |
| calculateDynamicVirtualScroll(config) | Virtualizacion con alturas de fila variables | VirtualScrollResult |
| saveLayout(gridId, layout) | Guarda layout en localStorage + zentto-cache remoto | void |
| loadLayout(gridId) | Carga layout desde localStorage (sync) con sync remoto en background | GridLayout \| null |
| clearLayout(gridId) | Elimina layout guardado | void |
Visualizacion (SVG, sin dependencias)
| Funcion | Descripcion |
|---------|-------------|
| generateChartSvg(rows, columns, config) | Genera SVG de grafico (bar, line, pie, area, donut, scatter, stacked, combo) |
| generateQrSvg(value) | Genera SVG de codigo QR (ISO 18004, usa qrcode-generator) |
| generateBarcodeSvg(value, type) | Genera SVG de codigo de barras (code128, ean13, code39) |
| generateTimelineSvg(entries) | Genera SVG de linea de tiempo horizontal |
| processSparklineData(data, type) | Prepara datos para sparklines (line, bar, area) |
Datos jerarquicos y estructurales
| Funcion | Descripcion |
|---------|-------------|
| buildTreeRows(rows, idField, parentField) | Construye estructura de arbol para datos jerarquicos |
| getDescendantIds(nodes, id) | Obtiene todos los IDs descendientes de un nodo |
| computeMergeMap(rows, columns) | Calcula mapa de celdas fusionadas para columnas con merge: true |
Auditoria
| Clase | Descripcion |
|-------|-------------|
| AuditTrail | Registra historial de cambios con usuario, timestamp y valores anterior/nuevo |
Ejemplos
Ordenamiento multi-columna
import { sortRows } from '@zentto/datagrid-core';
import type { GridRow, SortEntry } from '@zentto/datagrid-core';
const rows: GridRow[] = [
{ id: 1, nombre: 'Arroz Premium', precio: 45, categoria: 'Alimentos' },
{ id: 2, nombre: 'Aceite de Oliva', precio: 120, categoria: 'Alimentos' },
{ id: 3, nombre: 'Detergente', precio: 75, categoria: 'Limpieza' },
{ id: 4, nombre: 'Papel Higienico', precio: 30, categoria: 'Limpieza' },
];
// Ordenar por categoria ascendente, luego por precio descendente
const sorts: SortEntry[] = [
{ field: 'categoria', direction: 'asc' },
{ field: 'precio', direction: 'desc' },
];
const sorted = sortRows(rows, sorts);
// Alimentos: Aceite(120), Arroz(45) → Limpieza: Detergente(75), Papel(30)Filtrado combinado con busqueda rapida
import { filterRows, quickSearch } from '@zentto/datagrid-core';
import type { GridRow, FilterRule } from '@zentto/datagrid-core';
const rows: GridRow[] = [
{ id: 1, nombre: 'Widget A', precio: 29.99, activo: true },
{ id: 2, nombre: 'Gadget B', precio: 49.99, activo: false },
{ id: 3, nombre: 'Widget Pro', precio: 99.99, activo: true },
];
// Filtrar por precio mayor a 25 Y activo igual a true
const rules: FilterRule[] = [
{ field: 'precio', operator: 'gt', value: 25 },
{ field: 'activo', operator: 'equals', value: 'true' },
];
const filtered = filterRows(rows, rules);
// Busqueda de texto libre
const searched = quickSearch(rows, 'widget');
// Retorna filas que contienen "widget" en cualquier campoTabla pivot con totales
import { pivotRows } from '@zentto/datagrid-core';
import type { GridRow, PivotConfig } from '@zentto/datagrid-core';
const ventas: GridRow[] = [
{ id: 1, vendedor: 'Maria', region: 'Norte', monto: 100 },
{ id: 2, vendedor: 'Maria', region: 'Sur', monto: 80 },
{ id: 3, vendedor: 'Pedro', region: 'Norte', monto: 150 },
{ id: 4, vendedor: 'Pedro', region: 'Sur', monto: 120 },
{ id: 5, vendedor: 'Ana', region: 'Norte', monto: 200 },
];
const config: PivotConfig = {
rowField: 'vendedor',
columnField: 'region',
valueField: 'monto',
aggregation: 'sum',
showGrandTotals: true,
showRowTotals: true,
};
const { rows, columns } = pivotRows(ventas, config);
// rows: [{ vendedor:'Ana', Norte:200, Sur:0, __total__:200 }, ...]
// La fila TOTAL agrega todas las columnasFormulas tipo Excel
import { applyFormulas } from '@zentto/datagrid-core';
import type { GridRow, FormulaDefinition } from '@zentto/datagrid-core';
const rows: GridRow[] = [
{ id: 1, precioVenta: 100, precioCompra: 60 },
{ id: 2, precioVenta: 200, precioCompra: 140 },
];
const formulas: FormulaDefinition[] = [
// Margen bruto por fila
{ field: 'margen', formula: '={precioVenta}-{precioCompra}' },
// Porcentaje de margen redondeado a 2 decimales
{ field: 'margenPct', formula: '=ROUND(({precioVenta}-{precioCompra})/{precioCompra}*100, 2)' },
// Etiqueta condicional
{ field: 'clasificacion', formula: '=IF({margenPct} > 30, "Alta", "Normal")' },
];
const enrichedRows = applyFormulas(rows, formulas);
// rows[0]: { ..., margen: 40, margenPct: 66.67, clasificacion: 'Alta' }Historial de ediciones (Undo/Redo)
import { UndoRedoStack } from '@zentto/datagrid-core';
import type { EditAction } from '@zentto/datagrid-core';
const history = new UndoRedoStack(50); // max 50 acciones
// Registrar una edicion
const action: EditAction = {
type: 'cell-edit',
timestamp: Date.now(),
rowKey: '1',
field: 'precio',
oldValue: 100,
newValue: 120,
};
history.push(action);
// Deshacer
if (history.canUndo) {
const undone = history.undo();
console.log(undone?.field); // 'precio'
}
// Rehacer
if (history.canRedo) {
history.redo();
}Persistencia de layout con zentto-cache
import { saveLayout, loadLayout, configureRemoteCache } from '@zentto/datagrid-core';
import type { GridLayout } from '@zentto/datagrid-core';
// Configurar cache remoto una vez al iniciar la app
configureRemoteCache({
baseUrl: 'https://cache.zentto.net',
companyId: 'empresa-001',
userId: 'usuario-42',
});
// Guardar layout (sincronico local + async remoto)
const layout: GridLayout = {
columnOrder: ['nombre', 'precio', 'categoria'],
density: 'compact',
sorts: [{ field: 'precio', direction: 'desc' }],
pageSize: 25,
};
saveLayout('grid-productos', layout);
// Cargar layout (sincronico desde localStorage, sync remoto en background)
const saved = loadLayout('grid-productos');
if (saved) {
console.log(saved.density); // 'compact'
}Tipos principales
GridRow
type GridRow = Record<string, unknown>;Representa una fila de datos. Los campos se acceden por nombre.
ColumnDef
Definicion completa de una columna. Campos destacados:
interface ColumnDef {
field: string; // Nombre del campo en el row (obligatorio)
header?: string; // Etiqueta visible
type?: 'string' | 'number' | 'date' | 'datetime' | 'boolean' | 'actions' | 'color' | 'percentage';
sortable?: boolean;
filterable?: boolean;
aggregation?: 'sum' | 'avg' | 'count' | 'min' | 'max';
formula?: string; // Formula tipo Excel: '={campo1}*{campo2}'
statusColors?: Record<string, string>; // { Activo: 'success', Inactivo: 'error' }
conditionalFormat?: ConditionalFormatRule[];
validation?: ValidationRule;
sparkline?: 'line' | 'bar' | 'area';
barcode?: 'qr' | 'code128' | 'ean13' | 'code39';
merge?: boolean; // Fusionar celdas consecutivas con el mismo valor
renderCell?: (value: unknown, row: GridRow) => string;
}FilterRule
interface FilterRule {
field: string;
operator: 'contains' | 'notContains' | 'equals' | 'notEquals' |
'startsWith' | 'endsWith' | 'gt' | 'gte' | 'lt' | 'lte' |
'isEmpty' | 'isNotEmpty' | 'between' | 'inList';
value: unknown;
}PivotConfig
interface PivotConfig {
rowField: string; // Campo para las filas del pivot
columnField: string; // Campo cuyos valores se convierten en columnas
valueField: string; // Campo numerico que se agrega
aggregation?: 'sum' | 'avg' | 'count' | 'min' | 'max'; // Default: 'sum'
showGrandTotals?: boolean; // Agrega fila TOTAL al final
showRowTotals?: boolean; // Agrega columna __total__ por fila
}GridLayout
interface GridLayout {
columnOrder?: string[];
columnWidths?: Record<string, number>;
columnVisibility?: Record<string, boolean>;
density?: 'compact' | 'standard' | 'comfortable';
groupByField?: string;
sorts?: Array<{ field: string; direction: string }>;
pageSize?: number;
viewMode?: 'table' | 'form' | 'cards' | 'kanban' | 'chart';
pivotConfig?: PivotConfig;
}GridOptions
Opciones completas disponibles al configurar el grid (usadas por @zentto/datagrid internamente):
interface GridOptions {
columns: ColumnDef[];
rows: GridRow[];
sortModel?: SortEntry[];
filters?: FilterRule[];
pagination?: PaginationModel;
paginationMode?: 'client' | 'server';
enableGrouping?: boolean;
enablePivot?: boolean;
showTotals?: boolean;
theme?: 'light' | 'dark' | 'zentto';
locale?: 'es' | 'en' | 'pt';
gridId?: string; // Para persistencia de layout
// ... y mas de 30 opciones adicionales
}Changelog
Ver CHANGELOG.md para el historial completo de versiones.
Paquetes relacionados
@zentto/datagrid— web component<zentto-grid>con UI completa@zentto/datagrid-react— wrapper React@zentto/datagrid-vue— wrapper Vue 3@zentto/datagrid-angular— wrapper Angular
