han-excel-builder 1.0.4 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,250 +1,866 @@
1
1
  # Han Excel Builder
2
2
 
3
- 🚀 **Advanced Excel file generator with TypeScript support, comprehensive styling, and optimized performance**
4
-
5
- A modern, fully-typed library for creating complex Excel reports with multiple worksheets, advanced styling, and high performance.
6
-
7
- ## ✨ Features
8
-
9
- - 📊 **Multiple Worksheets Support** - Create complex workbooks with multiple sheets
10
- - 🎨 **Advanced Styling** - Full control over fonts, colors, borders, and cell formatting
11
- - 📈 **Data Types** - Support for strings, numbers, dates, percentages, and custom formats
12
- - 🔧 **TypeScript First** - Complete type safety with comprehensive interfaces
13
- - **High Performance** - Optimized for large datasets with streaming support
14
- - 🧪 **Fully Tested** - Comprehensive test suite with 100% coverage
15
- - 📚 **Well Documented** - Complete API documentation with examples
16
- - 🛠️ **Developer Friendly** - ESLint, Prettier, and modern tooling
17
-
18
- ## 📦 Installation
3
+ 🚀 **Generador avanzado de archivos Excel con soporte TypeScript, estilos completos y rendimiento optimizado**
4
+
5
+ Una biblioteca moderna y completamente tipada para crear reportes Excel complejos con múltiples hojas de cálculo, estilos avanzados y alto rendimiento.
6
+
7
+ ## ✨ Características
8
+
9
+ ### 📊 Estructura de Datos
10
+ - **Múltiples Hojas de Cálculo** - Crea workbooks complejos con múltiples hojas
11
+ - **Múltiples Tablas por Hoja** - Crea varias tablas independientes en una sola hoja
12
+ - **Headers Anidados** - Soporte completo para headers con múltiples niveles de anidación
13
+ - **Datos Jerárquicos** - Soporte para datos con estructura de children (datos anidados)
14
+
15
+ ### 📈 Tipos de Datos
16
+ - **STRING** - Valores de texto
17
+ - ✅ **NUMBER** - Valores numéricos
18
+ - **BOOLEAN** - Valores verdadero/falso
19
+ - ✅ **DATE** - Valores de fecha
20
+ - ✅ **PERCENTAGE** - Valores de porcentaje
21
+ - ✅ **CURRENCY** - Valores de moneda
22
+ - ✅ **LINK** - Hipervínculos con texto personalizable
23
+ - ✅ **FORMULA** - Fórmulas de Excel
24
+
25
+ ### 🎨 Estilos Avanzados
26
+ - ✅ **API Fluida** - StyleBuilder con métodos encadenables
27
+ - ✅ **Fuentes** - Control completo sobre nombre, tamaño, color, negrita, cursiva, subrayado
28
+ - ✅ **Colores** - Fondos, colores de texto con soporte para hex, RGB y temas
29
+ - ✅ **Bordes** - Bordes personalizables en todos los lados con múltiples estilos
30
+ - ✅ **Alineación** - Horizontal (izquierda, centro, derecha, justificar) y vertical (arriba, medio, abajo)
31
+ - ✅ **Texto** - Ajuste de texto, contracción para ajustar, rotación de texto
32
+ - ✅ **Formatos de Número** - Múltiples formatos predefinidos y personalizados
33
+ - ✅ **Filas Alternadas** - Soporte para rayas alternadas en tablas
34
+
35
+ ### 🔧 Funcionalidades Avanzadas
36
+ - ✅ **TypeScript First** - Seguridad de tipos completa con interfaces exhaustivas
37
+ - ✅ **Sistema de Eventos** - EventEmitter para monitorear el proceso de construcción
38
+ - ✅ **Validación** - Sistema robusto de validación de datos
39
+ - ✅ **Metadata** - Soporte completo para metadata del workbook (autor, título, descripción, etc.)
40
+ - ✅ **Múltiples Formatos de Exportación** - Descarga directa, Buffer, Blob
41
+ - ✅ **Lectura de Excel** - Lee archivos Excel y convierte a JSON
42
+ - ✅ **Hipervínculos** - Creación de enlaces con texto personalizable
43
+ - ✅ **Merge de Celdas** - Fusión horizontal y vertical de celdas
44
+ - ✅ **Dimensiones Personalizadas** - Ancho de columnas y alto de filas personalizables
45
+
46
+ ## 📦 Instalación
19
47
 
20
48
  ```bash
21
49
  npm install han-excel-builder
22
- # or
50
+ # o
23
51
  yarn add han-excel-builder
24
- # or
52
+ # o
25
53
  pnpm add han-excel-builder
26
54
  ```
27
55
 
28
- ## 🚀 Quick Start
56
+ ## 🚀 Inicio Rápido
57
+
58
+ ### Ejemplo Básico
29
59
 
30
60
  ```typescript
31
- import { ExcelBuilder, CellType, NumberFormat, StyleBuilder } from 'han-excel-builder';
61
+ import { ExcelBuilder, CellType, NumberFormat, StyleBuilder, BorderStyle } from 'han-excel-builder';
32
62
 
33
- // Create a simple report
34
- const builder = new ExcelBuilder();
63
+ // Crear un reporte simple
64
+ const builder = new ExcelBuilder({
65
+ metadata: {
66
+ title: 'Reporte de Ventas',
67
+ author: 'Mi Empresa',
68
+ description: 'Reporte mensual de ventas'
69
+ }
70
+ });
35
71
 
36
- const worksheet = builder.addWorksheet('Sales Report');
72
+ const worksheet = builder.addWorksheet('Ventas');
37
73
 
38
- // Add headers
74
+ // Agregar header principal
39
75
  worksheet.addHeader({
40
76
  key: 'title',
41
- value: 'Monthly Sales Report',
77
+ value: 'Reporte Mensual de Ventas',
42
78
  type: CellType.STRING,
43
79
  mergeCell: true,
44
- styles: StyleBuilder.create()
45
- .fontBold()
80
+ styles: new StyleBuilder()
81
+ .fontName('Arial')
46
82
  .fontSize(16)
83
+ .fontBold()
84
+ .backgroundColor('#4472C4')
85
+ .fontColor('#FFFFFF')
47
86
  .centerAlign()
87
+ .border(BorderStyle.THIN, '#8EAADB')
48
88
  .build()
49
89
  });
50
90
 
51
- // Add sub-headers
91
+ // Agregar sub-headers
52
92
  worksheet.addSubHeaders([
53
93
  {
54
- key: 'product',
55
- value: 'Product',
94
+ key: 'producto',
95
+ value: 'Producto',
56
96
  type: CellType.STRING,
57
- width: 20
97
+ colWidth: 20,
98
+ styles: new StyleBuilder()
99
+ .fontBold()
100
+ .backgroundColor('#8EAADB')
101
+ .fontColor('#FFFFFF')
102
+ .centerAlign()
103
+ .border(BorderStyle.THIN, '#8EAADB')
104
+ .build()
58
105
  },
59
106
  {
60
- key: 'sales',
61
- value: 'Sales',
62
- type: CellType.NUMBER,
63
- width: 15,
64
- numberFormat: NumberFormat.CURRENCY
107
+ key: 'ventas',
108
+ value: 'Ventas',
109
+ type: CellType.CURRENCY,
110
+ colWidth: 15,
111
+ numberFormat: '$#,##0',
112
+ styles: new StyleBuilder()
113
+ .fontBold()
114
+ .backgroundColor('#8EAADB')
115
+ .fontColor('#FFFFFF')
116
+ .centerAlign()
117
+ .border(BorderStyle.THIN, '#8EAADB')
118
+ .build()
65
119
  }
66
120
  ]);
67
121
 
68
- // Add data
122
+ // Agregar datos
69
123
  worksheet.addRow([
70
- { key: 'product', value: 'Product A', type: CellType.STRING },
71
- { key: 'sales', value: 1500.50, type: CellType.NUMBER }
124
+ {
125
+ key: 'producto-1',
126
+ value: 'Producto A',
127
+ type: CellType.STRING,
128
+ header: 'Producto'
129
+ },
130
+ {
131
+ key: 'ventas-1',
132
+ value: 1500.50,
133
+ type: CellType.CURRENCY,
134
+ header: 'Ventas',
135
+ numberFormat: '$#,##0.00'
136
+ }
72
137
  ]);
73
138
 
74
- // Generate and download
75
- await builder.generateAndDownload('sales-report');
139
+ // Generar y descargar
140
+ await builder.generateAndDownload('reporte-ventas.xlsx');
76
141
  ```
77
142
 
78
- ## 📚 API Documentation
143
+ ## 📚 Documentación de API
79
144
 
80
- ### Core Classes
145
+ ### Clases Principales
81
146
 
82
147
  #### `ExcelBuilder`
83
- Main class for creating Excel workbooks.
148
+
149
+ Clase principal para crear workbooks de Excel.
84
150
 
85
151
  ```typescript
86
152
  const builder = new ExcelBuilder({
87
- author: 'Your Name',
88
- company: 'Your Company',
89
- created: new Date()
153
+ metadata: {
154
+ title: 'Mi Reporte',
155
+ author: 'Mi Nombre',
156
+ company: 'Mi Empresa',
157
+ description: 'Descripción del reporte',
158
+ keywords: 'excel, reporte, datos',
159
+ created: new Date(),
160
+ modified: new Date()
161
+ },
162
+ enableValidation: true,
163
+ enableEvents: true,
164
+ maxWorksheets: 255,
165
+ maxRowsPerWorksheet: 1048576,
166
+ maxColumnsPerWorksheet: 16384
90
167
  });
168
+
169
+ // Métodos principales
170
+ builder.addWorksheet(name, config); // Agregar una hoja
171
+ builder.getWorksheet(name); // Obtener una hoja
172
+ builder.removeWorksheet(name); // Eliminar una hoja
173
+ builder.setCurrentWorksheet(name); // Establecer hoja actual
174
+ builder.build(options); // Construir y obtener ArrayBuffer
175
+ builder.generateAndDownload(fileName); // Generar y descargar
176
+ builder.toBuffer(options); // Obtener como Buffer
177
+ builder.toBlob(options); // Obtener como Blob
178
+ builder.validate(); // Validar workbook
179
+ builder.clear(); // Limpiar todas las hojas
180
+ builder.getStats(); // Obtener estadísticas
181
+
182
+ // Sistema de eventos
183
+ builder.on(eventType, listener);
184
+ builder.off(eventType, listenerId);
185
+ builder.removeAllListeners(eventType);
186
+ ```
187
+
188
+ #### `ExcelReader`
189
+
190
+ Clase para leer archivos Excel y convertirlos a JSON con 3 formatos de salida diferentes.
191
+
192
+ **Formatos disponibles:**
193
+ - `worksheet` (por defecto) - Estructura completa con hojas, filas y celdas
194
+ - `detailed` - Cada celda con información de posición (texto, columna, fila)
195
+ - `flat` - Solo los datos, sin estructura
196
+
197
+ ```typescript
198
+ import { ExcelReader, OutputFormat } from 'han-excel-builder';
199
+
200
+ // ===== FORMATO 1: WORKSHEET (por defecto) =====
201
+ // Estructura completa organizada por hojas
202
+ const result = await ExcelReader.fromFile(file, {
203
+ outputFormat: OutputFormat.WORKSHEET, // o 'worksheet'
204
+ useFirstRowAsHeaders: true
205
+ });
206
+
207
+ if (result.success) {
208
+ const workbook = result.data;
209
+ // workbook.sheets[] - Array de hojas
210
+ // workbook.sheets[0].rows[] - Array de filas
211
+ // workbook.sheets[0].rows[0].cells[] - Array de celdas
212
+ // workbook.sheets[0].rows[0].data - Objeto con datos (si useFirstRowAsHeaders)
213
+ }
214
+
215
+ // ===== FORMATO 2: DETAILED =====
216
+ // Cada celda con información de posición
217
+ const result = await ExcelReader.fromFile(file, {
218
+ outputFormat: OutputFormat.DETAILED, // o 'detailed'
219
+ includeFormatting: true
220
+ });
221
+
222
+ if (result.success) {
223
+ const detailed = result.data;
224
+ // detailed.cells[] - Array de todas las celdas con:
225
+ // - value: valor de la celda
226
+ // - text: texto de la celda
227
+ // - column: número de columna (1-based)
228
+ // - columnLetter: letra de columna (A, B, C...)
229
+ // - row: número de fila (1-based)
230
+ // - reference: referencia de celda (A1, B2...)
231
+ // - sheet: nombre de la hoja
232
+ detailed.cells.forEach(cell => {
233
+ console.log(`${cell.sheet}!${cell.reference}: ${cell.text}`);
234
+ });
235
+ }
236
+
237
+ // ===== FORMATO 3: FLAT =====
238
+ // Solo los datos, sin estructura
239
+ const result = await ExcelReader.fromFile(file, {
240
+ outputFormat: OutputFormat.FLAT, // o 'flat'
241
+ useFirstRowAsHeaders: true
242
+ });
243
+
244
+ if (result.success) {
245
+ const flat = result.data;
246
+
247
+ // Si es una sola hoja:
248
+ if ('data' in flat) {
249
+ // flat.data[] - Array de objetos o arrays
250
+ // flat.headers[] - Headers (si useFirstRowAsHeaders)
251
+ flat.data.forEach(row => {
252
+ console.log(row); // { Producto: 'A', Precio: 100 } o ['A', 100]
253
+ });
254
+ }
255
+
256
+ // Si son múltiples hojas:
257
+ if ('sheets' in flat) {
258
+ // flat.sheets['NombreHoja'].data[] - Datos por hoja
259
+ Object.keys(flat.sheets).forEach(sheetName => {
260
+ console.log(`Hoja: ${sheetName}`);
261
+ flat.sheets[sheetName].data.forEach(row => {
262
+ console.log(row);
263
+ });
264
+ });
265
+ }
266
+ }
267
+
268
+ // ===== USANDO MAPPER PARA TRANSFORMAR DATOS =====
269
+ // El mapper permite transformar la respuesta antes de devolverla
270
+ const result = await ExcelReader.fromFile(file, {
271
+ outputFormat: OutputFormat.WORKSHEET,
272
+ useFirstRowAsHeaders: true,
273
+ // Mapper recibe el payload y devuelve la transformación
274
+ mapper: (data) => {
275
+ // Transformar datos según necesidades
276
+ const transformed = {
277
+ totalSheets: data.totalSheets,
278
+ sheets: data.sheets.map(sheet => ({
279
+ name: sheet.name,
280
+ // Convertir filas a objetos con datos transformados
281
+ rows: sheet.rows.map(row => {
282
+ if (row.data) {
283
+ // Transformar cada campo
284
+ return {
285
+ ...row.data,
286
+ // Agregar campos calculados
287
+ total: Object.values(row.data).reduce((sum, val) => {
288
+ return sum + (typeof val === 'number' ? val : 0);
289
+ }, 0)
290
+ };
291
+ }
292
+ return row;
293
+ })
294
+ }))
295
+ };
296
+ return transformed;
297
+ }
298
+ });
299
+
300
+ // Ejemplo con formato FLAT y mapper
301
+ const result = await ExcelReader.fromFile(file, {
302
+ outputFormat: OutputFormat.FLAT,
303
+ useFirstRowAsHeaders: true,
304
+ mapper: (data) => {
305
+ // Si es formato flat de una sola hoja
306
+ if ('data' in data && Array.isArray(data.data)) {
307
+ return data.data.map((row: any) => ({
308
+ ...row,
309
+ // Agregar validaciones o transformaciones
310
+ isValid: Object.values(row).every(val => val !== null && val !== undefined)
311
+ }));
312
+ }
313
+ return data;
314
+ }
315
+ });
316
+
317
+ // Ejemplo con formato DETAILED y mapper
318
+ const result = await ExcelReader.fromFile(file, {
319
+ outputFormat: OutputFormat.DETAILED,
320
+ mapper: (data) => {
321
+ // Agrupar celdas por hoja
322
+ const groupedBySheet: Record<string, typeof data.cells> = {};
323
+ data.cells.forEach(cell => {
324
+ if (!groupedBySheet[cell.sheet]) {
325
+ groupedBySheet[cell.sheet] = [];
326
+ }
327
+ groupedBySheet[cell.sheet].push(cell);
328
+ });
329
+ return {
330
+ sheets: Object.keys(groupedBySheet).map(sheetName => ({
331
+ name: sheetName,
332
+ cells: groupedBySheet[sheetName]
333
+ }))
334
+ };
335
+ }
336
+ });
337
+ ```
338
+
339
+ **Opciones de lectura:**
340
+
341
+ ```typescript
342
+ interface IExcelReaderOptions {
343
+ outputFormat?: 'worksheet' | 'detailed' | 'flat' | OutputFormat; // Formato de salida
344
+ mapper?: (data: IJsonWorkbook | IDetailedFormat | IFlatFormat | IFlatFormatMultiSheet) => unknown; // Función para transformar la respuesta
345
+ useFirstRowAsHeaders?: boolean; // Usar primera fila como headers
346
+ includeEmptyRows?: boolean; // Incluir filas vacías
347
+ headers?: string[] | Record<number, string>; // Headers personalizados
348
+ sheetName?: string | number; // Nombre o índice de hoja
349
+ startRow?: number; // Fila inicial (1-based)
350
+ endRow?: number; // Fila final (1-based)
351
+ startColumn?: number; // Columna inicial (1-based)
352
+ endColumn?: number; // Columna final (1-based)
353
+ includeFormatting?: boolean; // Incluir información de formato
354
+ includeFormulas?: boolean; // Incluir fórmulas
355
+ datesAsISO?: boolean; // Convertir fechas a ISO string
356
+ }
91
357
  ```
92
358
 
359
+ **Formatos de salida:**
360
+
361
+ - **`worksheet`** (por defecto): Estructura completa con hojas, filas y celdas
362
+ - **`detailed`**: Array de celdas con información de posición (texto, columna, fila, referencia)
363
+ - **`flat`**: Solo los datos, sin estructura (arrays u objetos planos)
364
+
93
365
  #### `Worksheet`
94
- Represents a single worksheet in the workbook.
366
+
367
+ Representa una hoja de cálculo individual.
95
368
 
96
369
  ```typescript
97
- const worksheet = builder.addWorksheet('Sheet Name', {
370
+ const worksheet = builder.addWorksheet('Mi Hoja', {
98
371
  tabColor: '#FF0000',
99
372
  defaultRowHeight: 20,
100
- defaultColWidth: 15
373
+ defaultColWidth: 15,
374
+ pageSetup: {
375
+ orientation: 'portrait',
376
+ paperSize: 9
377
+ }
101
378
  });
379
+
380
+ // Métodos principales
381
+ worksheet.addHeader(header); // Agregar header principal
382
+ worksheet.addSubHeaders(headers); // Agregar sub-headers
383
+ worksheet.addRow(row); // Agregar fila de datos
384
+ worksheet.addFooter(footer); // Agregar footer
385
+ worksheet.addTable(config); // Crear nueva tabla
386
+ worksheet.finalizeTable(); // Finalizar tabla actual
387
+ worksheet.getTable(name); // Obtener tabla por nombre
388
+ worksheet.validate(); // Validar hoja
102
389
  ```
103
390
 
104
- ### Data Types
391
+ ### Tipos de Datos
105
392
 
106
393
  #### `CellType`
107
- - `STRING` - Text values
108
- - `NUMBER` - Numeric values
109
- - `BOOLEAN` - True/false values
110
- - `DATE` - Date values
111
- - `PERCENTAGE` - Percentage values
112
- - `CURRENCY` - Currency values
394
+
395
+ ```typescript
396
+ enum CellType {
397
+ STRING = 'string', // Texto
398
+ NUMBER = 'number', // Número
399
+ BOOLEAN = 'boolean', // Verdadero/Falso
400
+ DATE = 'date', // Fecha
401
+ PERCENTAGE = 'percentage', // Porcentaje
402
+ CURRENCY = 'currency', // Moneda
403
+ LINK = 'link', // Hipervínculo
404
+ FORMULA = 'formula' // Fórmula
405
+ }
406
+ ```
113
407
 
114
408
  #### `NumberFormat`
115
- - `GENERAL` - Default format
116
- - `NUMBER` - Number with optional decimals
117
- - `CURRENCY` - Currency format
118
- - `PERCENTAGE` - Percentage format
119
- - `DATE` - Date format
120
- - `TIME` - Time format
121
- - `CUSTOM` - Custom format string
122
409
 
123
- ### Styling
410
+ ```typescript
411
+ enum NumberFormat {
412
+ GENERAL = 'General',
413
+ NUMBER = '#,##0',
414
+ NUMBER_DECIMALS = '#,##0.00',
415
+ CURRENCY = '$#,##0.00',
416
+ CURRENCY_INTEGER = '$#,##0',
417
+ PERCENTAGE = '0%',
418
+ PERCENTAGE_DECIMALS = '0.00%',
419
+ DATE = 'dd/mm/yyyy',
420
+ DATE_TIME = 'dd/mm/yyyy hh:mm',
421
+ TIME = 'hh:mm:ss',
422
+ CUSTOM = 'custom'
423
+ }
424
+ ```
425
+
426
+ ### Estilos
124
427
 
125
428
  #### `StyleBuilder`
126
- Fluent API for creating cell styles.
429
+
430
+ API fluida para crear estilos de celdas.
127
431
 
128
432
  ```typescript
129
- const style = StyleBuilder.create()
130
- .fontBold()
433
+ const style = new StyleBuilder()
434
+ // Fuentes
435
+ .fontName('Arial')
131
436
  .fontSize(12)
437
+ .fontBold()
438
+ .fontItalic()
439
+ .fontUnderline()
132
440
  .fontColor('#FF0000')
441
+
442
+ // Fondos y bordes
133
443
  .backgroundColor('#FFFF00')
134
- .border('thin', '#000000')
444
+ .border(BorderStyle.THIN, '#000000')
445
+ .borderTop(BorderStyle.MEDIUM, '#000000')
446
+ .borderLeft(BorderStyle.THIN, '#000000')
447
+ .borderBottom(BorderStyle.THIN, '#000000')
448
+ .borderRight(BorderStyle.THIN, '#000000')
449
+
450
+ // Alineación
135
451
  .centerAlign()
136
- .verticalAlign('middle')
452
+ .leftAlign()
453
+ .rightAlign()
454
+ .horizontalAlign(HorizontalAlignment.CENTER)
455
+ .verticalAlign(VerticalAlignment.MIDDLE)
137
456
  .wrapText()
457
+
458
+ // Formatos
459
+ .numberFormat('$#,##0.00')
460
+ .striped()
461
+
462
+ // Formato condicional
463
+ .conditionalFormat({
464
+ type: 'cellIs',
465
+ operator: 'greaterThan',
466
+ values: [1000],
467
+ style: StyleBuilder.create()
468
+ .backgroundColor('#90EE90')
469
+ .fontColor('#006400')
470
+ .build()
471
+ })
472
+
473
+ .build();
474
+
475
+ // Método estático alternativo
476
+ const style2 = StyleBuilder.create()
477
+ .fontBold()
478
+ .fontSize(14)
138
479
  .build();
139
480
  ```
140
481
 
141
- ## 🎯 Advanced Examples
482
+ #### `BorderStyle`
483
+
484
+ ```typescript
485
+ enum BorderStyle {
486
+ THIN = 'thin',
487
+ MEDIUM = 'medium',
488
+ THICK = 'thick',
489
+ DOTTED = 'dotted',
490
+ DASHED = 'dashed',
491
+ DOUBLE = 'double',
492
+ HAIR = 'hair',
493
+ MEDIUM_DASHED = 'mediumDashed',
494
+ DASH_DOT = 'dashDot',
495
+ MEDIUM_DASH_DOT = 'mediumDashDot',
496
+ DASH_DOT_DOT = 'dashDotDot',
497
+ MEDIUM_DASH_DOT_DOT = 'mediumDashDotDot',
498
+ SLANT_DASH_DOT = 'slantDashDot'
499
+ }
500
+ ```
501
+
502
+ ## 🎯 Ejemplos Avanzados
142
503
 
143
- ### Complex Report with Multiple Worksheets
504
+ ### Múltiples Tablas en una Hoja
144
505
 
145
506
  ```typescript
146
- import { ExcelBuilder, CellType, NumberFormat, StyleBuilder } from 'han-excel-builder';
507
+ import { ExcelBuilder, CellType, StyleBuilder, BorderStyle } from 'han-excel-builder';
147
508
 
148
- const builder = new ExcelBuilder({
149
- author: 'Report Generator',
150
- company: 'Your Company'
509
+ const builder = new ExcelBuilder();
510
+ const worksheet = builder.addWorksheet('Reporte Completo');
511
+
512
+ // ===== PRIMERA TABLA =====
513
+ worksheet.addTable({
514
+ name: 'Ventas',
515
+ showBorders: true,
516
+ showStripes: true,
517
+ style: 'TableStyleLight1'
151
518
  });
152
519
 
153
- // Summary worksheet
154
- const summarySheet = builder.addWorksheet('Summary');
155
- summarySheet.addHeader({
156
- key: 'title',
157
- value: 'Annual Report Summary',
520
+ worksheet.addHeader({
521
+ key: 'header-ventas',
158
522
  type: CellType.STRING,
523
+ value: 'RESUMEN DE VENTAS',
159
524
  mergeCell: true,
160
- styles: StyleBuilder.create().fontBold().fontSize(18).centerAlign().build()
525
+ styles: new StyleBuilder()
526
+ .fontBold()
527
+ .fontSize(16)
528
+ .backgroundColor('#4472C4')
529
+ .fontColor('#FFFFFF')
530
+ .centerAlign()
531
+ .build()
161
532
  });
162
533
 
163
- // Detailed worksheet
164
- const detailSheet = builder.addWorksheet('Details');
165
- detailSheet.addSubHeaders([
166
- { key: 'date', value: 'Date', type: CellType.DATE, width: 12 },
167
- { key: 'category', value: 'Category', type: CellType.STRING, width: 15 },
168
- { key: 'amount', value: 'Amount', type: CellType.NUMBER, width: 12, numberFormat: NumberFormat.CURRENCY },
169
- { key: 'percentage', value: '%', type: CellType.PERCENTAGE, width: 8 }
534
+ worksheet.addSubHeaders([
535
+ { key: 'producto', type: CellType.STRING, value: 'Producto' },
536
+ { key: 'ventas', type: CellType.CURRENCY, value: 'Ventas' }
170
537
  ]);
171
538
 
172
- // Add data with alternating row colors
173
- data.forEach((row, index) => {
174
- const rowStyle = index % 2 === 0
175
- ? StyleBuilder.create().backgroundColor('#F0F0F0').build()
176
- : undefined;
177
-
178
- detailSheet.addRow([
179
- { key: 'date', value: row.date, type: CellType.DATE },
180
- { key: 'category', value: row.category, type: CellType.STRING },
181
- { key: 'amount', value: row.amount, type: CellType.NUMBER },
182
- { key: 'percentage', value: row.percentage, type: CellType.PERCENTAGE }
183
- ], rowStyle);
539
+ worksheet.addRow([
540
+ { key: 'p1', type: CellType.STRING, value: 'Producto A', header: 'Producto' },
541
+ { key: 'v1', type: CellType.CURRENCY, value: 1500, header: 'Ventas' }
542
+ ]);
543
+
544
+ worksheet.finalizeTable();
545
+
546
+ // ===== SEGUNDA TABLA =====
547
+ worksheet.addTable({
548
+ name: 'Empleados',
549
+ showBorders: true,
550
+ showStripes: true,
551
+ style: 'TableStyleMedium1'
184
552
  });
185
553
 
186
- await builder.generateAndDownload('annual-report');
554
+ worksheet.addHeader({
555
+ key: 'header-empleados',
556
+ type: CellType.STRING,
557
+ value: 'TOP EMPLEADOS',
558
+ mergeCell: true,
559
+ styles: new StyleBuilder()
560
+ .fontBold()
561
+ .fontSize(16)
562
+ .backgroundColor('#70AD47')
563
+ .fontColor('#FFFFFF')
564
+ .centerAlign()
565
+ .build()
566
+ });
567
+
568
+ worksheet.addSubHeaders([
569
+ { key: 'nombre', type: CellType.STRING, value: 'Nombre' },
570
+ { key: 'ventas', type: CellType.CURRENCY, value: 'Ventas' }
571
+ ]);
572
+
573
+ worksheet.addRow([
574
+ { key: 'e1', type: CellType.STRING, value: 'Juan Pérez', header: 'Nombre' },
575
+ { key: 've1', type: CellType.CURRENCY, value: 150000, header: 'Ventas' }
576
+ ]);
577
+
578
+ worksheet.finalizeTable();
579
+
580
+ await builder.generateAndDownload('multiple-tables.xlsx');
187
581
  ```
188
582
 
189
- ### Conditional Styling
583
+ ### Headers Anidados
190
584
 
191
585
  ```typescript
192
- const style = StyleBuilder.create()
193
- .conditionalFormat({
194
- type: 'cellIs',
195
- operator: 'greaterThan',
196
- values: [1000],
197
- style: StyleBuilder.create()
198
- .backgroundColor('#90EE90')
199
- .fontColor('#006400')
586
+ worksheet.addSubHeaders([
587
+ {
588
+ key: 'ventas',
589
+ value: 'Ventas',
590
+ type: CellType.STRING,
591
+ children: [
592
+ {
593
+ key: 'ventas-q1',
594
+ value: 'Q1',
595
+ type: CellType.STRING
596
+ },
597
+ {
598
+ key: 'ventas-q2',
599
+ value: 'Q2',
600
+ type: CellType.STRING
601
+ }
602
+ ]
603
+ },
604
+ {
605
+ key: 'gastos',
606
+ value: 'Gastos',
607
+ type: CellType.STRING,
608
+ children: [
609
+ {
610
+ key: 'gastos-q1',
611
+ value: 'Q1',
612
+ type: CellType.STRING
613
+ },
614
+ {
615
+ key: 'gastos-q2',
616
+ value: 'Q2',
617
+ type: CellType.STRING
618
+ }
619
+ ]
620
+ }
621
+ ]);
622
+ ```
623
+
624
+ ### Hipervínculos
625
+
626
+ ```typescript
627
+ worksheet.addRow([
628
+ {
629
+ key: 'link-1',
630
+ type: CellType.LINK,
631
+ value: 'Visitar sitio',
632
+ link: 'https://example.com',
633
+ mask: 'Haz clic aquí', // Texto visible
634
+ header: 'Enlace'
635
+ }
636
+ ]);
637
+ ```
638
+
639
+ ### Datos con Children (Estructura Jerárquica)
640
+
641
+ ```typescript
642
+ worksheet.addRow([
643
+ {
644
+ key: 'row-1',
645
+ type: CellType.STRING,
646
+ value: 'Categoría Principal',
647
+ header: 'Categoría',
648
+ children: [
649
+ {
650
+ key: 'child-1',
651
+ type: CellType.STRING,
652
+ value: 'Subcategoría 1',
653
+ header: 'Subcategoría'
654
+ },
655
+ {
656
+ key: 'child-2',
657
+ type: CellType.NUMBER,
658
+ value: 100,
659
+ header: 'Valor'
660
+ }
661
+ ]
662
+ }
663
+ ]);
664
+ ```
665
+
666
+ ### Formato Condicional
667
+
668
+ ```typescript
669
+ worksheet.addRow([
670
+ {
671
+ key: 'ventas-1',
672
+ type: CellType.NUMBER,
673
+ value: 1500,
674
+ header: 'Ventas',
675
+ styles: new StyleBuilder()
676
+ .conditionalFormat({
677
+ type: 'cellIs',
678
+ operator: 'greaterThan',
679
+ values: [1000],
680
+ style: StyleBuilder.create()
681
+ .backgroundColor('#90EE90')
682
+ .fontColor('#006400')
683
+ .build()
684
+ })
200
685
  .build()
201
- })
202
- .build();
686
+ }
687
+ ]);
688
+ ```
689
+
690
+ ### Múltiples Hojas de Cálculo
691
+
692
+ ```typescript
693
+ const builder = new ExcelBuilder();
694
+
695
+ // Hoja 1: Resumen
696
+ const summarySheet = builder.addWorksheet('Resumen');
697
+ summarySheet.addHeader({
698
+ key: 'title',
699
+ value: 'Resumen Ejecutivo',
700
+ type: CellType.STRING,
701
+ mergeCell: true
702
+ });
703
+
704
+ // Hoja 2: Detalles
705
+ const detailsSheet = builder.addWorksheet('Detalles');
706
+ detailsSheet.addSubHeaders([
707
+ { key: 'fecha', value: 'Fecha', type: CellType.DATE },
708
+ { key: 'monto', value: 'Monto', type: CellType.CURRENCY }
709
+ ]);
710
+
711
+ await builder.generateAndDownload('multi-sheet-report.xlsx');
712
+ ```
713
+
714
+ ### Exportación en Diferentes Formatos
715
+
716
+ ```typescript
717
+ // Descarga directa (navegador)
718
+ await builder.generateAndDownload('reporte.xlsx');
719
+
720
+ // Obtener como Buffer
721
+ const bufferResult = await builder.toBuffer();
722
+ if (bufferResult.success) {
723
+ const buffer = bufferResult.data;
724
+ // Usar buffer...
725
+ }
726
+
727
+ // Obtener como Blob
728
+ const blobResult = await builder.toBlob();
729
+ if (blobResult.success) {
730
+ const blob = blobResult.data;
731
+ // Usar blob...
732
+ }
733
+ ```
734
+
735
+ ### Sistema de Eventos
736
+
737
+ ```typescript
738
+ builder.on('build:started', (event) => {
739
+ console.log('Construcción iniciada');
740
+ });
741
+
742
+ builder.on('build:completed', (event) => {
743
+ console.log('Construcción completada', event.data);
744
+ });
745
+
746
+ builder.on('build:error', (event) => {
747
+ console.error('Error en construcción', event.data.error);
748
+ });
749
+
750
+ // Remover listener
751
+ const listenerId = builder.on('build:started', handler);
752
+ builder.off('build:started', listenerId);
753
+ ```
754
+
755
+ ### Leer Excel y Convertir a JSON
756
+
757
+ ```typescript
758
+ import { ExcelReader } from 'han-excel-builder';
759
+
760
+ // Leer desde un archivo (navegador)
761
+ const fileInput = document.querySelector('input[type="file"]');
762
+ fileInput.addEventListener('change', async (e) => {
763
+ const file = (e.target as HTMLInputElement).files?.[0];
764
+ if (!file) return;
765
+
766
+ const result = await ExcelReader.fromFile(file, {
767
+ useFirstRowAsHeaders: true,
768
+ datesAsISO: true,
769
+ includeFormatting: false
770
+ });
771
+
772
+ if (result.success) {
773
+ const workbook = result.data;
774
+
775
+ // Procesar cada hoja
776
+ workbook.sheets.forEach(sheet => {
777
+ console.log(`Procesando hoja: ${sheet.name}`);
778
+
779
+ // Convertir a array de objetos (si usamos headers)
780
+ const data = sheet.rows.map(row => row.data || {});
781
+ console.log('Datos:', data);
782
+ });
783
+ }
784
+ });
785
+
786
+ // Leer desde ArrayBuffer (desde API)
787
+ async function readExcelFromAPI() {
788
+ const response = await fetch('/api/excel-file');
789
+ const buffer = await response.arrayBuffer();
790
+
791
+ const result = await ExcelReader.fromBuffer(buffer, {
792
+ useFirstRowAsHeaders: true,
793
+ sheetName: 'Ventas' // Leer solo la hoja 'Ventas'
794
+ });
795
+
796
+ if (result.success) {
797
+ const sheet = result.data.sheets[0];
798
+ const ventas = sheet.rows.map(row => row.data);
799
+ return ventas;
800
+ }
801
+ }
802
+
803
+ // Leer desde ruta (Node.js)
804
+ async function readExcelFromPath() {
805
+ const result = await ExcelReader.fromPath('./reporte.xlsx', {
806
+ useFirstRowAsHeaders: true,
807
+ startRow: 2, // Saltar header
808
+ includeFormulas: true
809
+ });
810
+
811
+ if (result.success) {
812
+ console.log(`Tiempo de procesamiento: ${result.processingTime}ms`);
813
+ return result.data;
814
+ }
815
+ }
203
816
  ```
204
817
 
205
818
  ## 🧪 Testing
206
819
 
207
820
  ```bash
208
- # Run tests
821
+ # Ejecutar tests
209
822
  npm test
210
823
 
211
- # Run tests with coverage
824
+ # Ejecutar tests con cobertura
212
825
  npm run test:coverage
213
826
 
214
- # Run tests in watch mode
827
+ # Ejecutar tests en modo watch
215
828
  npm run test:watch
216
829
  ```
217
830
 
218
- ## 🛠️ Development
831
+ ## 🛠️ Desarrollo
219
832
 
220
833
  ```bash
221
- # Install dependencies
834
+ # Instalar dependencias
222
835
  npm install
223
836
 
224
- # Start development server
837
+ # Iniciar servidor de desarrollo
225
838
  npm run dev
226
839
 
227
- # Build for production
840
+ # Construir para producción
228
841
  npm run build
229
842
 
230
- # Run linting
843
+ # Ejecutar linting
231
844
  npm run lint
232
845
 
233
- # Format code
846
+ # Formatear código
234
847
  npm run format
235
848
 
236
- # Generate documentation
849
+ # Verificar tipos
850
+ npm run type-check
851
+
852
+ # Generar documentación
237
853
  npm run docs
238
854
  ```
239
855
 
240
- ## 📋 Migration from legacy-excel
856
+ ## 📋 Migración desde legacy-excel
241
857
 
242
- If you're migrating from the legacy version, here's a quick comparison:
858
+ Si estás migrando desde la versión legacy, aquí hay una comparación rápida:
243
859
 
244
860
  ```typescript
245
- // Legacy way
861
+ // Forma legacy
246
862
  const worksheets: IWorksheets[] = [{
247
- name: "Report",
863
+ name: "Reporte",
248
864
  tables: [{
249
865
  headers: [...],
250
866
  subHeaders: [...],
@@ -252,35 +868,42 @@ const worksheets: IWorksheets[] = [{
252
868
  footers: [...]
253
869
  }]
254
870
  }];
255
- await fileBuilder(worksheets, "report");
871
+ await fileBuilder(worksheets, "reporte");
256
872
 
257
- // New way
873
+ // Nueva forma
258
874
  const builder = new ExcelBuilder();
259
- const worksheet = builder.addWorksheet('Report');
260
- worksheet.addHeaders([...]);
875
+ const worksheet = builder.addWorksheet('Reporte');
876
+ worksheet.addHeader({...});
261
877
  worksheet.addSubHeaders([...]);
262
- worksheet.addRows([...]);
263
- await builder.generateAndDownload('report');
878
+ worksheet.addRow([...]);
879
+ worksheet.addFooter([...]);
880
+ await builder.generateAndDownload('reporte');
264
881
  ```
265
882
 
266
- ## 🤝 Contributing
883
+ ## 📚 Recursos Adicionales
884
+
885
+ - 📖 [Guía de Múltiples Tablas](./MULTIPLE-TABLES-GUIDE.md)
886
+ - 📖 [Mejoras Implementadas](./IMPROVEMENTS.md)
887
+ - 📖 [Resultados de Pruebas](./TEST-RESULTS.md)
888
+
889
+ ## 🤝 Contribuir
267
890
 
268
- 1. Fork the repository
269
- 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
270
- 3. Commit your changes (`git commit -m 'Add amazing feature'`)
271
- 4. Push to the branch (`git push origin feature/amazing-feature`)
272
- 5. Open a Pull Request
891
+ 1. Fork el repositorio
892
+ 2. Crea una rama de feature (`git checkout -b feature/mi-caracteristica`)
893
+ 3. Commit tus cambios (`git commit -m 'Agregar mi característica'`)
894
+ 4. Push a la rama (`git push origin feature/mi-caracteristica`)
895
+ 5. Abre un Pull Request
273
896
 
274
- ## 📄 License
897
+ ## 📄 Licencia
275
898
 
276
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
899
+ Este proyecto está licenciado bajo la Licencia MIT - ver el archivo [LICENSE](LICENSE) para más detalles.
277
900
 
278
- ## 🆘 Support
901
+ ## 🆘 Soporte
279
902
 
280
- - 📖 [Documentation](https://github.com/your-org/han-excel-builder/docs)
281
- - 🐛 [Issues](https://github.com/your-org/han-excel-builder/issues)
282
- - 💬 [Discussions](https://github.com/your-org/han-excel-builder/discussions)
903
+ - 📖 [Documentación](https://github.com/hannndler/-han-excel)
904
+ - 🐛 [Issues](https://github.com/hannndler/-han-excel/issues)
905
+ - 💬 [Discussions](https://github.com/hannndler/-han-excel/discussions)
283
906
 
284
907
  ---
285
908
 
286
- Made with ❤️ by the Han Excel Team
909
+ Hecho con ❤️ por el equipo de Han Excel