han-excel-builder 1.0.5 โ†’ 1.1.1

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
@@ -6,14 +6,42 @@ A modern, fully-typed library for creating complex Excel reports with multiple w
6
6
 
7
7
  ## โœจ Features
8
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
9
+ ### ๐Ÿ“Š Data Structure
10
+ - โœ… **Multiple Worksheets** - Create complex workbooks with multiple sheets
11
+ - โœ… **Multiple Tables per Sheet** - Create multiple independent tables in a single sheet
12
+ - โœ… **Nested Headers** - Full support for headers with multiple nesting levels
13
+ - โœ… **Hierarchical Data** - Support for data with children structure (nested data)
14
+
15
+ ### ๐Ÿ“ˆ Data Types
16
+ - โœ… **STRING** - Text values
17
+ - โœ… **NUMBER** - Numeric values
18
+ - โœ… **BOOLEAN** - True/false values
19
+ - โœ… **DATE** - Date values
20
+ - โœ… **PERCENTAGE** - Percentage values
21
+ - โœ… **CURRENCY** - Currency values
22
+ - โœ… **LINK** - Hyperlinks with customizable text
23
+ - โœ… **FORMULA** - Excel formulas
24
+
25
+ ### ๐ŸŽจ Advanced Styling
26
+ - โœ… **Fluent API** - StyleBuilder with chainable methods
27
+ - โœ… **Fonts** - Full control over name, size, color, bold, italic, underline
28
+ - โœ… **Colors** - Backgrounds, text colors with support for hex, RGB and themes
29
+ - โœ… **Borders** - Customizable borders on all sides with multiple styles
30
+ - โœ… **Alignment** - Horizontal (left, center, right, justify) and vertical (top, middle, bottom)
31
+ - โœ… **Text** - Text wrapping, shrink to fit, text rotation
32
+ - โœ… **Number Formats** - Multiple predefined and custom formats
33
+ - โœ… **Alternating Rows** - Support for alternating stripes in tables
34
+
35
+ ### ๐Ÿ”ง Advanced Features
36
+ - โœ… **TypeScript First** - Complete type safety with comprehensive interfaces
37
+ - โœ… **Event System** - EventEmitter to monitor the build process
38
+ - โœ… **Validation** - Robust data validation system
39
+ - โœ… **Metadata** - Full support for workbook metadata (author, title, description, etc.)
40
+ - โœ… **Multiple Export Formats** - Direct download, Buffer, Blob
41
+ - โœ… **Excel Reading** - Read Excel files and convert to JSON
42
+ - โœ… **Hyperlinks** - Create links with customizable text
43
+ - โœ… **Cell Merging** - Horizontal and vertical cell merging
44
+ - โœ… **Custom Dimensions** - Customizable column width and row height
17
45
 
18
46
  ## ๐Ÿ“ฆ Installation
19
47
 
@@ -27,24 +55,36 @@ pnpm add han-excel-builder
27
55
 
28
56
  ## ๐Ÿš€ Quick Start
29
57
 
58
+ ### Basic Example
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
63
  // Create a simple report
34
- const builder = new ExcelBuilder();
64
+ const builder = new ExcelBuilder({
65
+ metadata: {
66
+ title: 'Sales Report',
67
+ author: 'My Company',
68
+ description: 'Monthly sales report'
69
+ }
70
+ });
35
71
 
36
- const worksheet = builder.addWorksheet('Sales Report');
72
+ const worksheet = builder.addWorksheet('Sales');
37
73
 
38
- // Add headers
74
+ // Add main header
39
75
  worksheet.addHeader({
40
76
  key: 'title',
41
77
  value: 'Monthly Sales Report',
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
 
@@ -54,25 +94,50 @@ worksheet.addSubHeaders([
54
94
  key: 'product',
55
95
  value: 'Product',
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
107
  key: 'sales',
61
108
  value: 'Sales',
62
- type: CellType.NUMBER,
63
- width: 15,
64
- numberFormat: NumberFormat.CURRENCY
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
122
  // Add data
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: 'product-1',
126
+ value: 'Product A',
127
+ type: CellType.STRING,
128
+ header: 'Product'
129
+ },
130
+ {
131
+ key: 'sales-1',
132
+ value: 1500.50,
133
+ type: CellType.CURRENCY,
134
+ header: 'Sales',
135
+ numberFormat: '$#,##0.00'
136
+ }
72
137
  ]);
73
138
 
74
139
  // Generate and download
75
- await builder.generateAndDownload('sales-report');
140
+ await builder.generateAndDownload('sales-report.xlsx');
76
141
  ```
77
142
 
78
143
  ## ๐Ÿ“š API Documentation
@@ -80,126 +145,674 @@ await builder.generateAndDownload('sales-report');
80
145
  ### Core Classes
81
146
 
82
147
  #### `ExcelBuilder`
148
+
83
149
  Main class for creating Excel workbooks.
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: 'My Report',
155
+ author: 'My Name',
156
+ company: 'My Company',
157
+ description: 'Report description',
158
+ keywords: 'excel, report, data',
159
+ created: new Date(),
160
+ modified: new Date()
161
+ },
162
+ enableValidation: true,
163
+ enableEvents: true,
164
+ maxWorksheets: 255,
165
+ maxRowsPerWorksheet: 1048576,
166
+ maxColumnsPerWorksheet: 16384
167
+ });
168
+
169
+ // Main methods
170
+ builder.addWorksheet(name, config); // Add a worksheet
171
+ builder.getWorksheet(name); // Get a worksheet
172
+ builder.removeWorksheet(name); // Remove a worksheet
173
+ builder.setCurrentWorksheet(name); // Set current worksheet
174
+ builder.build(options); // Build and get ArrayBuffer
175
+ builder.generateAndDownload(fileName); // Generate and download
176
+ builder.toBuffer(options); // Get as Buffer
177
+ builder.toBlob(options); // Get as Blob
178
+ builder.validate(); // Validate workbook
179
+ builder.clear(); // Clear all worksheets
180
+ builder.getStats(); // Get statistics
181
+
182
+ // Event system
183
+ builder.on(eventType, listener);
184
+ builder.off(eventType, listenerId);
185
+ builder.removeAllListeners(eventType);
186
+ ```
187
+
188
+ #### `ExcelReader`
189
+
190
+ Class for reading Excel files and converting them to JSON with 3 different output formats.
191
+
192
+ **Available formats:**
193
+ - `worksheet` (default) - Complete structure with sheets, rows and cells
194
+ - `detailed` - Each cell with position information (text, column, row)
195
+ - `flat` - Just the data, without structure
196
+
197
+ ```typescript
198
+ import { ExcelReader, OutputFormat } from 'han-excel-builder';
199
+
200
+ // ===== FORMAT 1: WORKSHEET (default) =====
201
+ // Complete structure organized by sheets
202
+ const result = await ExcelReader.fromFile(file, {
203
+ outputFormat: OutputFormat.WORKSHEET, // or 'worksheet'
204
+ useFirstRowAsHeaders: true
205
+ });
206
+
207
+ if (result.success) {
208
+ const workbook = result.data;
209
+ // workbook.sheets[] - Array of sheets
210
+ // workbook.sheets[0].rows[] - Array of rows
211
+ // workbook.sheets[0].rows[0].cells[] - Array of cells
212
+ // workbook.sheets[0].rows[0].data - Object with data (if useFirstRowAsHeaders)
213
+ }
214
+
215
+ // ===== FORMAT 2: DETAILED =====
216
+ // Each cell with position information
217
+ const result = await ExcelReader.fromFile(file, {
218
+ outputFormat: OutputFormat.DETAILED, // or 'detailed'
219
+ includeFormatting: true
220
+ });
221
+
222
+ if (result.success) {
223
+ const detailed = result.data;
224
+ // detailed.cells[] - Array of all cells with:
225
+ // - value: cell value
226
+ // - text: cell text
227
+ // - column: column number (1-based)
228
+ // - columnLetter: column letter (A, B, C...)
229
+ // - row: row number (1-based)
230
+ // - reference: cell reference (A1, B2...)
231
+ // - sheet: sheet name
232
+ detailed.cells.forEach(cell => {
233
+ console.log(`${cell.sheet}!${cell.reference}: ${cell.text}`);
234
+ });
235
+ }
236
+
237
+ // ===== FORMAT 3: FLAT =====
238
+ // Just the data, without structure
239
+ const result = await ExcelReader.fromFile(file, {
240
+ outputFormat: OutputFormat.FLAT, // or 'flat'
241
+ useFirstRowAsHeaders: true
242
+ });
243
+
244
+ if (result.success) {
245
+ const flat = result.data;
246
+
247
+ // If single sheet:
248
+ if ('data' in flat) {
249
+ // flat.data[] - Array of objects or arrays
250
+ // flat.headers[] - Headers (if useFirstRowAsHeaders)
251
+ flat.data.forEach(row => {
252
+ console.log(row); // { Product: 'A', Price: 100 } or ['A', 100]
253
+ });
254
+ }
255
+
256
+ // If multiple sheets:
257
+ if ('sheets' in flat) {
258
+ // flat.sheets['SheetName'].data[] - Data by sheet
259
+ Object.keys(flat.sheets).forEach(sheetName => {
260
+ console.log(`Sheet: ${sheetName}`);
261
+ flat.sheets[sheetName].data.forEach(row => {
262
+ console.log(row);
263
+ });
264
+ });
265
+ }
266
+ }
267
+
268
+ // ===== USING MAPPER TO TRANSFORM DATA =====
269
+ // The mapper allows transforming the response before returning it
270
+ const result = await ExcelReader.fromFile(file, {
271
+ outputFormat: OutputFormat.WORKSHEET,
272
+ useFirstRowAsHeaders: true,
273
+ // Mapper receives the payload and returns the transformation
274
+ mapper: (data) => {
275
+ // Transform data according to needs
276
+ const transformed = {
277
+ totalSheets: data.totalSheets,
278
+ sheets: data.sheets.map(sheet => ({
279
+ name: sheet.name,
280
+ // Convert rows to objects with transformed data
281
+ rows: sheet.rows.map(row => {
282
+ if (row.data) {
283
+ // Transform each field
284
+ return {
285
+ ...row.data,
286
+ // Add calculated fields
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
+ // Example with FLAT format and mapper
301
+ const result = await ExcelReader.fromFile(file, {
302
+ outputFormat: OutputFormat.FLAT,
303
+ useFirstRowAsHeaders: true,
304
+ mapper: (data) => {
305
+ // If flat format from single sheet
306
+ if ('data' in data && Array.isArray(data.data)) {
307
+ return data.data.map((row: any) => ({
308
+ ...row,
309
+ // Add validations or transformations
310
+ isValid: Object.values(row).every(val => val !== null && val !== undefined)
311
+ }));
312
+ }
313
+ return data;
314
+ }
315
+ });
316
+
317
+ // Example with DETAILED format and mapper
318
+ const result = await ExcelReader.fromFile(file, {
319
+ outputFormat: OutputFormat.DETAILED,
320
+ mapper: (data) => {
321
+ // Group cells by sheet
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
+ }
90
336
  });
91
337
  ```
92
338
 
339
+ **Reading options:**
340
+
341
+ ```typescript
342
+ interface IExcelReaderOptions {
343
+ outputFormat?: 'worksheet' | 'detailed' | 'flat' | OutputFormat; // Output format
344
+ mapper?: (data: IJsonWorkbook | IDetailedFormat | IFlatFormat | IFlatFormatMultiSheet) => unknown; // Function to transform the response
345
+ useFirstRowAsHeaders?: boolean; // Use first row as headers
346
+ includeEmptyRows?: boolean; // Include empty rows
347
+ headers?: string[] | Record<number, string>; // Custom headers
348
+ sheetName?: string | number; // Sheet name or index
349
+ startRow?: number; // Starting row (1-based)
350
+ endRow?: number; // Ending row (1-based)
351
+ startColumn?: number; // Starting column (1-based)
352
+ endColumn?: number; // Ending column (1-based)
353
+ includeFormatting?: boolean; // Include formatting information
354
+ includeFormulas?: boolean; // Include formulas
355
+ datesAsISO?: boolean; // Convert dates to ISO string
356
+ }
357
+ ```
358
+
359
+ **Output formats:**
360
+
361
+ - **`worksheet`** (default): Complete structure with sheets, rows and cells
362
+ - **`detailed`**: Array of cells with position information (text, column, row, reference)
363
+ - **`flat`**: Just the data, without structure (flat arrays or objects)
364
+
93
365
  #### `Worksheet`
94
- Represents a single worksheet in the workbook.
366
+
367
+ Represents an individual worksheet.
95
368
 
96
369
  ```typescript
97
- const worksheet = builder.addWorksheet('Sheet Name', {
370
+ const worksheet = builder.addWorksheet('My Sheet', {
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
+ // Main methods
381
+ worksheet.addHeader(header); // Add main header
382
+ worksheet.addSubHeaders(headers); // Add sub-headers
383
+ worksheet.addRow(row); // Add data row
384
+ worksheet.addFooter(footer); // Add footer
385
+ worksheet.addTable(config); // Create new table
386
+ worksheet.finalizeTable(); // Finalize current table
387
+ worksheet.getTable(name); // Get table by name
388
+ worksheet.validate(); // Validate sheet
102
389
  ```
103
390
 
104
391
  ### Data Types
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', // Text
398
+ NUMBER = 'number', // Number
399
+ BOOLEAN = 'boolean', // True/False
400
+ DATE = 'date', // Date
401
+ PERCENTAGE = 'percentage', // Percentage
402
+ CURRENCY = 'currency', // Currency
403
+ LINK = 'link', // Hyperlink
404
+ FORMULA = 'formula' // Formula
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
409
+
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
+ ```
122
425
 
123
426
  ### Styling
124
427
 
125
428
  #### `StyleBuilder`
429
+
126
430
  Fluent API for creating cell styles.
127
431
 
128
432
  ```typescript
129
- const style = StyleBuilder.create()
130
- .fontBold()
433
+ const style = new StyleBuilder()
434
+ // Fonts
435
+ .fontName('Arial')
131
436
  .fontSize(12)
437
+ .fontBold()
438
+ .fontItalic()
439
+ .fontUnderline()
132
440
  .fontColor('#FF0000')
441
+
442
+ // Backgrounds and borders
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
+ // Alignment
135
451
  .centerAlign()
136
- .verticalAlign('middle')
452
+ .leftAlign()
453
+ .rightAlign()
454
+ .horizontalAlign(HorizontalAlignment.CENTER)
455
+ .verticalAlign(VerticalAlignment.MIDDLE)
137
456
  .wrapText()
457
+
458
+ // Formats
459
+ .numberFormat('$#,##0.00')
460
+ .striped()
461
+
462
+ // Conditional formatting
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
+ // Alternative static method
476
+ const style2 = StyleBuilder.create()
477
+ .fontBold()
478
+ .fontSize(14)
138
479
  .build();
139
480
  ```
140
481
 
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
+
141
502
  ## ๐ŸŽฏ Advanced Examples
142
503
 
143
- ### Complex Report with Multiple Worksheets
504
+ ### Multiple Tables in a Sheet
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('Complete Report');
511
+
512
+ // ===== FIRST TABLE =====
513
+ worksheet.addTable({
514
+ name: 'Sales',
515
+ showBorders: true,
516
+ showStripes: true,
517
+ style: 'TableStyleLight1'
518
+ });
519
+
520
+ worksheet.addHeader({
521
+ key: 'header-sales',
522
+ type: CellType.STRING,
523
+ value: 'SALES SUMMARY',
524
+ mergeCell: true,
525
+ styles: new StyleBuilder()
526
+ .fontBold()
527
+ .fontSize(16)
528
+ .backgroundColor('#4472C4')
529
+ .fontColor('#FFFFFF')
530
+ .centerAlign()
531
+ .build()
532
+ });
533
+
534
+ worksheet.addSubHeaders([
535
+ { key: 'product', type: CellType.STRING, value: 'Product' },
536
+ { key: 'sales', type: CellType.CURRENCY, value: 'Sales' }
537
+ ]);
538
+
539
+ worksheet.addRow([
540
+ { key: 'p1', type: CellType.STRING, value: 'Product A', header: 'Product' },
541
+ { key: 'v1', type: CellType.CURRENCY, value: 1500, header: 'Sales' }
542
+ ]);
543
+
544
+ worksheet.finalizeTable();
545
+
546
+ // ===== SECOND TABLE =====
547
+ worksheet.addTable({
548
+ name: 'Employees',
549
+ showBorders: true,
550
+ showStripes: true,
551
+ style: 'TableStyleMedium1'
151
552
  });
152
553
 
153
- // Summary worksheet
554
+ worksheet.addHeader({
555
+ key: 'header-employees',
556
+ type: CellType.STRING,
557
+ value: 'TOP EMPLOYEES',
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: 'name', type: CellType.STRING, value: 'Name' },
570
+ { key: 'sales', type: CellType.CURRENCY, value: 'Sales' }
571
+ ]);
572
+
573
+ worksheet.addRow([
574
+ { key: 'e1', type: CellType.STRING, value: 'John Doe', header: 'Name' },
575
+ { key: 've1', type: CellType.CURRENCY, value: 150000, header: 'Sales' }
576
+ ]);
577
+
578
+ worksheet.finalizeTable();
579
+
580
+ await builder.generateAndDownload('multiple-tables.xlsx');
581
+ ```
582
+
583
+ ### Nested Headers
584
+
585
+ ```typescript
586
+ worksheet.addSubHeaders([
587
+ {
588
+ key: 'sales',
589
+ value: 'Sales',
590
+ type: CellType.STRING,
591
+ children: [
592
+ {
593
+ key: 'sales-q1',
594
+ value: 'Q1',
595
+ type: CellType.STRING
596
+ },
597
+ {
598
+ key: 'sales-q2',
599
+ value: 'Q2',
600
+ type: CellType.STRING
601
+ }
602
+ ]
603
+ },
604
+ {
605
+ key: 'expenses',
606
+ value: 'Expenses',
607
+ type: CellType.STRING,
608
+ children: [
609
+ {
610
+ key: 'expenses-q1',
611
+ value: 'Q1',
612
+ type: CellType.STRING
613
+ },
614
+ {
615
+ key: 'expenses-q2',
616
+ value: 'Q2',
617
+ type: CellType.STRING
618
+ }
619
+ ]
620
+ }
621
+ ]);
622
+ ```
623
+
624
+ ### Hyperlinks
625
+
626
+ ```typescript
627
+ worksheet.addRow([
628
+ {
629
+ key: 'link-1',
630
+ type: CellType.LINK,
631
+ value: 'Visit site',
632
+ link: 'https://example.com',
633
+ mask: 'Click here', // Visible text
634
+ header: 'Link'
635
+ }
636
+ ]);
637
+ ```
638
+
639
+ ### Data with Children (Hierarchical Structure)
640
+
641
+ ```typescript
642
+ worksheet.addRow([
643
+ {
644
+ key: 'row-1',
645
+ type: CellType.STRING,
646
+ value: 'Main Category',
647
+ header: 'Category',
648
+ children: [
649
+ {
650
+ key: 'child-1',
651
+ type: CellType.STRING,
652
+ value: 'Subcategory 1',
653
+ header: 'Subcategory'
654
+ },
655
+ {
656
+ key: 'child-2',
657
+ type: CellType.NUMBER,
658
+ value: 100,
659
+ header: 'Value'
660
+ }
661
+ ]
662
+ }
663
+ ]);
664
+ ```
665
+
666
+ ### Conditional Formatting
667
+
668
+ ```typescript
669
+ worksheet.addRow([
670
+ {
671
+ key: 'sales-1',
672
+ type: CellType.NUMBER,
673
+ value: 1500,
674
+ header: 'Sales',
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
+ })
685
+ .build()
686
+ }
687
+ ]);
688
+ ```
689
+
690
+ ### Multiple Worksheets
691
+
692
+ ```typescript
693
+ const builder = new ExcelBuilder();
694
+
695
+ // Sheet 1: Summary
154
696
  const summarySheet = builder.addWorksheet('Summary');
155
697
  summarySheet.addHeader({
156
698
  key: 'title',
157
- value: 'Annual Report Summary',
699
+ value: 'Executive Summary',
158
700
  type: CellType.STRING,
159
- mergeCell: true,
160
- styles: StyleBuilder.create().fontBold().fontSize(18).centerAlign().build()
701
+ mergeCell: true
161
702
  });
162
703
 
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 }
704
+ // Sheet 2: Details
705
+ const detailsSheet = builder.addWorksheet('Details');
706
+ detailsSheet.addSubHeaders([
707
+ { key: 'date', value: 'Date', type: CellType.DATE },
708
+ { key: 'amount', value: 'Amount', type: CellType.CURRENCY }
170
709
  ]);
171
710
 
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);
711
+ await builder.generateAndDownload('multi-sheet-report.xlsx');
712
+ ```
713
+
714
+ ### Export in Different Formats
715
+
716
+ ```typescript
717
+ // Direct download (browser)
718
+ await builder.generateAndDownload('report.xlsx');
719
+
720
+ // Get as Buffer
721
+ const bufferResult = await builder.toBuffer();
722
+ if (bufferResult.success) {
723
+ const buffer = bufferResult.data;
724
+ // Use buffer...
725
+ }
726
+
727
+ // Get as Blob
728
+ const blobResult = await builder.toBlob();
729
+ if (blobResult.success) {
730
+ const blob = blobResult.data;
731
+ // Use blob...
732
+ }
733
+ ```
734
+
735
+ ### Event System
736
+
737
+ ```typescript
738
+ builder.on('build:started', (event) => {
739
+ console.log('Build started');
184
740
  });
185
741
 
186
- await builder.generateAndDownload('annual-report');
742
+ builder.on('build:completed', (event) => {
743
+ console.log('Build completed', event.data);
744
+ });
745
+
746
+ builder.on('build:error', (event) => {
747
+ console.error('Build error', event.data.error);
748
+ });
749
+
750
+ // Remove listener
751
+ const listenerId = builder.on('build:started', handler);
752
+ builder.off('build:started', listenerId);
187
753
  ```
188
754
 
189
- ### Conditional Styling
755
+ ### Read Excel and Convert to JSON
190
756
 
191
757
  ```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')
200
- .build()
201
- })
202
- .build();
758
+ import { ExcelReader } from 'han-excel-builder';
759
+
760
+ // Read from a file (browser)
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
+ // Process each sheet
776
+ workbook.sheets.forEach(sheet => {
777
+ console.log(`Processing sheet: ${sheet.name}`);
778
+
779
+ // Convert to array of objects (if using headers)
780
+ const data = sheet.rows.map(row => row.data || {});
781
+ console.log('Data:', data);
782
+ });
783
+ }
784
+ });
785
+
786
+ // Read from ArrayBuffer (from 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: 'Sales' // Read only 'Sales' sheet
794
+ });
795
+
796
+ if (result.success) {
797
+ const sheet = result.data.sheets[0];
798
+ const sales = sheet.rows.map(row => row.data);
799
+ return sales;
800
+ }
801
+ }
802
+
803
+ // Read from path (Node.js)
804
+ async function readExcelFromPath() {
805
+ const result = await ExcelReader.fromPath('./report.xlsx', {
806
+ useFirstRowAsHeaders: true,
807
+ startRow: 2, // Skip header
808
+ includeFormulas: true
809
+ });
810
+
811
+ if (result.success) {
812
+ console.log(`Processing time: ${result.processingTime}ms`);
813
+ return result.data;
814
+ }
815
+ }
203
816
  ```
204
817
 
205
818
  ## ๐Ÿงช Testing
@@ -233,6 +846,9 @@ npm run lint
233
846
  # Format code
234
847
  npm run format
235
848
 
849
+ # Type checking
850
+ npm run type-check
851
+
236
852
  # Generate documentation
237
853
  npm run docs
238
854
  ```
@@ -257,18 +873,25 @@ await fileBuilder(worksheets, "report");
257
873
  // New way
258
874
  const builder = new ExcelBuilder();
259
875
  const worksheet = builder.addWorksheet('Report');
260
- worksheet.addHeaders([...]);
876
+ worksheet.addHeader({...});
261
877
  worksheet.addSubHeaders([...]);
262
- worksheet.addRows([...]);
878
+ worksheet.addRow([...]);
879
+ worksheet.addFooter([...]);
263
880
  await builder.generateAndDownload('report');
264
881
  ```
265
882
 
883
+ ## ๐Ÿ“š Additional Resources
884
+
885
+ - ๐Ÿ“– [Multiple Tables Guide](./MULTIPLE-TABLES-GUIDE.md)
886
+ - ๐Ÿ“– [Implemented Improvements](./IMPROVEMENTS.md)
887
+ - ๐Ÿ“– [Test Results](./TEST-RESULTS.md)
888
+
266
889
  ## ๐Ÿค Contributing
267
890
 
268
891
  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`)
892
+ 2. Create a feature branch (`git checkout -b feature/my-feature`)
893
+ 3. Commit your changes (`git commit -m 'Add my feature'`)
894
+ 4. Push to the branch (`git push origin feature/my-feature`)
272
895
  5. Open a Pull Request
273
896
 
274
897
  ## ๐Ÿ“„ License
@@ -277,10 +900,10 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
277
900
 
278
901
  ## ๐Ÿ†˜ Support
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
+ - ๐Ÿ“– [Documentation](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
+ Made with โค๏ธ by the Han Excel Team