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 +717 -94
- package/dist/__vite-browser-external-d06ac358.js +5 -0
- package/dist/__vite-browser-external-d06ac358.js.map +1 -0
- package/dist/__vite-browser-external-e7aec059.cjs +2 -0
- package/dist/__vite-browser-external-e7aec059.cjs.map +1 -0
- package/dist/han-excel.cjs.js +1 -1
- package/dist/han-excel.cjs.js.map +1 -1
- package/dist/han-excel.es.js +637 -0
- package/dist/han-excel.es.js.map +1 -1
- package/dist/index.d.ts +268 -0
- package/package.json +94 -93
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
|
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
-
|
|
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
|
|
72
|
+
const worksheet = builder.addWorksheet('Sales');
|
|
37
73
|
|
|
38
|
-
// Add
|
|
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
|
|
45
|
-
.
|
|
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
|
-
|
|
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.
|
|
63
|
-
|
|
64
|
-
numberFormat:
|
|
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
|
-
{
|
|
71
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
366
|
+
|
|
367
|
+
Represents an individual worksheet.
|
|
95
368
|
|
|
96
369
|
```typescript
|
|
97
|
-
const worksheet = builder.addWorksheet('Sheet
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
|
130
|
-
|
|
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(
|
|
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
|
-
.
|
|
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
|
-
###
|
|
504
|
+
### Multiple Tables in a Sheet
|
|
144
505
|
|
|
145
506
|
```typescript
|
|
146
|
-
import { ExcelBuilder, CellType,
|
|
507
|
+
import { ExcelBuilder, CellType, StyleBuilder, BorderStyle } from 'han-excel-builder';
|
|
147
508
|
|
|
148
|
-
const builder = new ExcelBuilder(
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
|
|
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: '
|
|
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
|
-
//
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
{ key: 'date', value: 'Date', type: CellType.DATE
|
|
167
|
-
{ key: '
|
|
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
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
755
|
+
### Read Excel and Convert to JSON
|
|
190
756
|
|
|
191
757
|
```typescript
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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.
|
|
876
|
+
worksheet.addHeader({...});
|
|
261
877
|
worksheet.addSubHeaders([...]);
|
|
262
|
-
worksheet.
|
|
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/
|
|
270
|
-
3. Commit your changes (`git commit -m 'Add
|
|
271
|
-
4. Push to the branch (`git push origin 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/
|
|
281
|
-
- ๐ [Issues](https://github.com/
|
|
282
|
-
- ๐ฌ [Discussions](https://github.com/
|
|
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
|