@niicojs/excel 0.2.3 → 0.2.4

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
@@ -9,6 +9,9 @@ A TypeScript library for Excel/OpenXML manipulation with maximum format preserva
9
9
  - Full formula support (read/write/preserve)
10
10
  - Cell styles (fonts, fills, borders, alignment)
11
11
  - Merged cells
12
+ - Column widths and row heights
13
+ - Freeze panes
14
+ - Pivot tables with fluent API
12
15
  - Sheet operations (add, delete, rename, copy)
13
16
  - Create sheets from arrays of objects (`addSheetFromData`)
14
17
  - Convert sheets to JSON arrays (`toJson`)
@@ -139,6 +142,47 @@ sheet.unmergeCells('A1:C1');
139
142
  console.log(sheet.mergedCells); // ['A1:C3', 'D5:E10', ...]
140
143
  ```
141
144
 
145
+ ## Column Widths and Row Heights
146
+
147
+ ```typescript
148
+ const sheet = wb.sheet(0);
149
+
150
+ // Set column width (by letter or 0-based index)
151
+ sheet.setColumnWidth('A', 20);
152
+ sheet.setColumnWidth(1, 15); // Column B
153
+
154
+ // Get column width
155
+ const width = sheet.getColumnWidth('A'); // 20 or undefined
156
+
157
+ // Set row height (0-based index)
158
+ sheet.setRowHeight(0, 30); // First row
159
+
160
+ // Get row height
161
+ const height = sheet.getRowHeight(0); // 30 or undefined
162
+ ```
163
+
164
+ ## Freeze Panes
165
+
166
+ ```typescript
167
+ const sheet = wb.sheet(0);
168
+
169
+ // Freeze first row (header)
170
+ sheet.freezePane(1, 0);
171
+
172
+ // Freeze first column
173
+ sheet.freezePane(0, 1);
174
+
175
+ // Freeze first row and first column
176
+ sheet.freezePane(1, 1);
177
+
178
+ // Unfreeze
179
+ sheet.freezePane(0, 0);
180
+
181
+ // Get current freeze pane configuration
182
+ const frozen = sheet.getFrozenPane();
183
+ // { row: 1, col: 0 } or null
184
+ ```
185
+
142
186
  ## Sheet Operations
143
187
 
144
188
  ```typescript
@@ -165,6 +209,56 @@ wb.copySheet('RawData', 'RawData_Backup');
165
209
  wb.deleteSheet('Summary');
166
210
  ```
167
211
 
212
+ ## Pivot Tables
213
+
214
+ Create pivot tables with a fluent API:
215
+
216
+ ```typescript
217
+ const wb = await Workbook.fromFile('sales-data.xlsx');
218
+
219
+ // Create a pivot table from source data
220
+ const pivot = wb.createPivotTable({
221
+ name: 'SalesPivot',
222
+ source: 'Data!A1:E100', // Source range with headers
223
+ target: 'Summary!A3', // Where to place the pivot table
224
+ refreshOnLoad: true, // Refresh when file opens (default: true)
225
+ });
226
+
227
+ // Configure fields using fluent API
228
+ pivot
229
+ .addRowField('Region') // Group by region
230
+ .addRowField('Product') // Then by product
231
+ .addColumnField('Year') // Columns by year
232
+ .addValueField('Sales', 'sum', 'Total Sales') // Sum of sales
233
+ .addValueField('Quantity', 'count', 'Order Count') // Count of orders
234
+ .addFilterField('Category'); // Page filter
235
+
236
+ // Sort and filter fields
237
+ pivot
238
+ .sortField('Region', 'asc') // Sort ascending
239
+ .filterField('Product', { include: ['Widget', 'Gadget'] }); // Include only these
240
+
241
+ await wb.toFile('report.xlsx');
242
+ ```
243
+
244
+ ### Pivot Table API
245
+
246
+ ```typescript
247
+ // Add fields to different areas
248
+ pivot.addRowField(fieldName: string): PivotTable
249
+ pivot.addColumnField(fieldName: string): PivotTable
250
+ pivot.addValueField(fieldName: string, aggregation?: AggregationType, displayName?: string): PivotTable
251
+ pivot.addFilterField(fieldName: string): PivotTable
252
+
253
+ // Aggregation types: 'sum' | 'count' | 'average' | 'min' | 'max'
254
+
255
+ // Sort a row or column field
256
+ pivot.sortField(fieldName: string, order: 'asc' | 'desc'): PivotTable
257
+
258
+ // Filter field values
259
+ pivot.filterField(fieldName: string, filter: { include?: string[] } | { exclude?: string[] }): PivotTable
260
+ ```
261
+
168
262
  ## Creating Sheets from Data
169
263
 
170
264
  Create sheets directly from arrays of objects with `addSheetFromData`:
@@ -226,7 +320,7 @@ const data = sheet.toJson();
226
320
  // [{ name: 'Alice', age: 30 }, { name: 'Bob', age: 25 }]
227
321
 
228
322
  // Using custom field names (first row is data, not headers)
229
- const data = sheet.toJson({
323
+ const data2 = sheet.toJson({
230
324
  fields: ['name', 'age', 'city'],
231
325
  });
232
326
 
@@ -238,21 +332,26 @@ interface Person {
238
332
  const people = sheet.toJson<Person>();
239
333
 
240
334
  // Starting from a specific position
241
- const data = sheet.toJson({
335
+ const data3 = sheet.toJson({
242
336
  startRow: 2, // Skip first 2 rows (0-based)
243
337
  startCol: 1, // Start from column B
244
338
  });
245
339
 
246
340
  // Limiting the range
247
- const data = sheet.toJson({
341
+ const data4 = sheet.toJson({
248
342
  endRow: 10, // Stop at row 11 (0-based, inclusive)
249
343
  endCol: 3, // Only read columns A-D
250
344
  });
251
345
 
252
346
  // Continue past empty rows
253
- const data = sheet.toJson({
347
+ const data5 = sheet.toJson({
254
348
  stopOnEmptyRow: false, // Default is true
255
349
  });
350
+
351
+ // Control how dates are serialized
352
+ const data6 = sheet.toJson({
353
+ dateHandling: 'isoString', // 'jsDate' | 'excelSerial' | 'isoString'
354
+ });
256
355
  ```
257
356
 
258
357
  ### Roundtrip Example
@@ -277,11 +376,24 @@ const readData = sheet.toJson();
277
376
  ## Saving
278
377
 
279
378
  ```typescript
280
- // Save to file
281
- await wb.toFile('output.xlsx');
379
+ // Load from file
380
+ const wb = await Workbook.fromFile('template.xlsx');
381
+
382
+ // Or load from buffer
383
+ const buffer = await fetch('https://example.com/file.xlsx').then((r) => r.arrayBuffer());
384
+ const wb2 = await Workbook.fromBuffer(new Uint8Array(buffer));
385
+
386
+ // Read data
387
+ const sheet = wb.sheet('Sheet1');
388
+ console.log(sheet.cell('A1').value); // The cell value
389
+ console.log(sheet.cell('A1').formula); // The formula (if any)
390
+ console.log(sheet.cell('A1').type); // 'string' | 'number' | 'boolean' | 'date' | 'error' | 'empty'
282
391
 
283
- // Save to buffer (Uint8Array)
284
- const buffer = await wb.toBuffer();
392
+ // Check if a cell exists without creating it
393
+ const existingCell = sheet.getCellIfExists('A1');
394
+ if (existingCell) {
395
+ console.log(existingCell.value);
396
+ }
285
397
  ```
286
398
 
287
399
  ## Type Definitions
@@ -330,9 +442,121 @@ interface SheetToJsonConfig {
330
442
  endRow?: number;
331
443
  endCol?: number;
332
444
  stopOnEmptyRow?: boolean; // Default: true
445
+ dateHandling?: 'jsDate' | 'excelSerial' | 'isoString'; // Default: 'jsDate'
446
+ }
447
+
448
+ // Pivot table configuration
449
+ interface PivotTableConfig {
450
+ name: string;
451
+ source: string; // e.g., "Sheet1!A1:D100"
452
+ target: string; // e.g., "Sheet2!A3"
453
+ refreshOnLoad?: boolean; // Default: true
454
+ }
455
+
456
+ type AggregationType = 'sum' | 'count' | 'average' | 'min' | 'max';
457
+ type PivotSortOrder = 'asc' | 'desc';
458
+ interface PivotFieldFilter {
459
+ include?: string[];
460
+ exclude?: string[];
333
461
  }
334
462
  ```
335
463
 
464
+ ## Address Utilities
465
+
466
+ Helper functions for working with Excel cell addresses:
467
+
468
+ ```typescript
469
+ import {
470
+ colToLetter,
471
+ letterToCol,
472
+ parseAddress,
473
+ toAddress,
474
+ parseRange,
475
+ toRange,
476
+ normalizeRange,
477
+ isInRange,
478
+ } from '@niicojs/excel';
479
+
480
+ // Convert column index to letter (0-based)
481
+ colToLetter(0); // 'A'
482
+ colToLetter(25); // 'Z'
483
+ colToLetter(26); // 'AA'
484
+
485
+ // Convert column letter to index (0-based)
486
+ letterToCol('A'); // 0
487
+ letterToCol('Z'); // 25
488
+ letterToCol('AA'); // 26
489
+
490
+ // Parse cell address to row/col
491
+ parseAddress('B3'); // { row: 2, col: 1 }
492
+ parseAddress('$A$1'); // { row: 0, col: 0 } (absolute refs supported)
493
+
494
+ // Convert row/col to address
495
+ toAddress(0, 0); // 'A1'
496
+ toAddress(9, 2); // 'C10'
497
+
498
+ // Parse range string
499
+ parseRange('A1:C10'); // { start: { row: 0, col: 0 }, end: { row: 9, col: 2 } }
500
+
501
+ // Convert range object to string
502
+ toRange({ start: { row: 0, col: 0 }, end: { row: 9, col: 2 } }); // 'A1:C10'
503
+
504
+ // Normalize range (ensure start is top-left, end is bottom-right)
505
+ normalizeRange({ start: { row: 5, col: 3 }, end: { row: 0, col: 0 } });
506
+ // { start: { row: 0, col: 0 }, end: { row: 5, col: 3 } }
507
+
508
+ // Check if address is within a range
509
+ isInRange({ row: 2, col: 1 }, { start: { row: 0, col: 0 }, end: { row: 5, col: 5 } }); // true
510
+ isInRange({ row: 10, col: 0 }, { start: { row: 0, col: 0 }, end: { row: 5, col: 5 } }); // false
511
+ ```
512
+
513
+ ## Style Schema
514
+
515
+ Supported style properties (CellStyle):
516
+
517
+ ```typescript
518
+ interface CellStyle {
519
+ bold?: boolean;
520
+ italic?: boolean;
521
+ underline?: boolean | 'single' | 'double';
522
+ strike?: boolean;
523
+ fontSize?: number;
524
+ fontName?: string;
525
+ fontColor?: string; // Hex (RGB/RRGGBB/AARRGGBB)
526
+ fill?: string; // Hex (RGB/RRGGBB/AARRGGBB)
527
+ border?: {
528
+ top?: 'thin' | 'medium' | 'thick' | 'double' | 'dotted' | 'dashed';
529
+ bottom?: 'thin' | 'medium' | 'thick' | 'double' | 'dotted' | 'dashed';
530
+ left?: 'thin' | 'medium' | 'thick' | 'double' | 'dotted' | 'dashed';
531
+ right?: 'thin' | 'medium' | 'thick' | 'double' | 'dotted' | 'dashed';
532
+ };
533
+ alignment?: {
534
+ horizontal?: 'left' | 'center' | 'right' | 'justify';
535
+ vertical?: 'top' | 'middle' | 'bottom';
536
+ wrapText?: boolean;
537
+ textRotation?: number;
538
+ };
539
+ numberFormat?: string; // Excel format code
540
+ }
541
+ ```
542
+
543
+ ## Performance and Large Files
544
+
545
+ Tips for large sheets and high-volume writes:
546
+
547
+ - Prefer `addSheetFromData` for bulk writes when possible.
548
+ - Use `range.getValues({ createMissing: false })` to avoid creating empty cells during reads.
549
+ - Keep shared strings small: prefer numbers/booleans where applicable.
550
+ - Avoid frequent `toBuffer()` calls in loops; batch writes and serialize once.
551
+
552
+ ## Limitations
553
+
554
+ The library focuses on preserving existing structure and editing common parts of workbooks.
555
+
556
+ - Chart editing is not supported (charts are preserved only).
557
+ - Conditional formatting and data validation are preserved but not editable yet.
558
+ - Some advanced Excel features (sparklines, slicers, macros) are preserved only.
559
+
336
560
  ## Format Preservation
337
561
 
338
562
  When modifying existing Excel files, this library preserves: