@devmm/puredocs-excel-angular 1.0.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/LICENSE +21 -0
- package/dist/index.cjs +193 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +118 -0
- package/dist/index.d.ts +118 -0
- package/dist/index.js +193 -0
- package/dist/index.js.map +1 -0
- package/package.json +45 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 TVE
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@angular/core');
|
|
4
|
+
var puredocsExcel = require('@devmm/puredocs-excel');
|
|
5
|
+
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
8
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
9
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
10
|
+
if (decorator = decorators[i])
|
|
11
|
+
result = (decorator(result)) || result;
|
|
12
|
+
return result;
|
|
13
|
+
};
|
|
14
|
+
exports.ExcelService = class ExcelService {
|
|
15
|
+
// ── Read ────────────────────────────────────────────────────────────────────
|
|
16
|
+
/**
|
|
17
|
+
* Reads an Excel file from a browser File object.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // In a component
|
|
21
|
+
* async onFileSelected(event: Event) {
|
|
22
|
+
* const file = (event.target as HTMLInputElement).files![0];
|
|
23
|
+
* const wb = await this.excel.readFile(file);
|
|
24
|
+
* const sheet = wb.worksheets[0];
|
|
25
|
+
* console.log(sheet.getCell('A1').getText());
|
|
26
|
+
* }
|
|
27
|
+
*/
|
|
28
|
+
async readFile(file) {
|
|
29
|
+
const buffer = await file.arrayBuffer();
|
|
30
|
+
return puredocsExcel.Workbook.fromBuffer(buffer);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Reads an Excel file from an ArrayBuffer or Uint8Array.
|
|
34
|
+
* Useful when data comes from an HTTP response.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* const response = await fetch('/api/report.xlsx');
|
|
38
|
+
* const buffer = await response.arrayBuffer();
|
|
39
|
+
* const wb = await this.excel.readBuffer(buffer);
|
|
40
|
+
*/
|
|
41
|
+
readBuffer(buffer) {
|
|
42
|
+
return puredocsExcel.Workbook.fromBuffer(buffer);
|
|
43
|
+
}
|
|
44
|
+
// ── Create ──────────────────────────────────────────────────────────────────
|
|
45
|
+
/**
|
|
46
|
+
* Creates a new empty workbook.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* const wb = this.excel.createWorkbook();
|
|
50
|
+
* const sheet = wb.addWorksheet('Report');
|
|
51
|
+
* sheet.getCell('A1').setValue('Hello');
|
|
52
|
+
*/
|
|
53
|
+
createWorkbook() {
|
|
54
|
+
return puredocsExcel.Workbook.create();
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Creates a workbook, applies a configuration callback, and returns it.
|
|
58
|
+
* Convenience method for building workbooks inline.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* const wb = this.excel.buildWorkbook(wb => {
|
|
62
|
+
* const sheet = wb.addWorksheet('Sales');
|
|
63
|
+
* sheet.getCell('A1').setValue('Total');
|
|
64
|
+
* sheet.getCell('B1').setValue(12345);
|
|
65
|
+
* });
|
|
66
|
+
*/
|
|
67
|
+
buildWorkbook(configure) {
|
|
68
|
+
const wb = puredocsExcel.Workbook.create();
|
|
69
|
+
configure(wb);
|
|
70
|
+
return wb;
|
|
71
|
+
}
|
|
72
|
+
// ── Export ──────────────────────────────────────────────────────────────────
|
|
73
|
+
/**
|
|
74
|
+
* Serialises a workbook to a Uint8Array buffer.
|
|
75
|
+
* Use this when you want to upload the file via HTTP.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* const buffer = this.excel.toBuffer(workbook);
|
|
79
|
+
* await this.http.post('/api/upload', buffer, {
|
|
80
|
+
* headers: { 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }
|
|
81
|
+
* }).toPromise();
|
|
82
|
+
*/
|
|
83
|
+
toBuffer(workbook) {
|
|
84
|
+
return workbook.saveAsBuffer();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Triggers a browser download of the workbook.
|
|
88
|
+
* Works in any modern browser via the Blob + anchor trick.
|
|
89
|
+
*
|
|
90
|
+
* @param workbook The workbook to download
|
|
91
|
+
* @param fileName Download filename (default: "export.xlsx")
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* this.excel.download(workbook, 'monthly-report.xlsx');
|
|
95
|
+
*/
|
|
96
|
+
download(workbook, fileName = "export.xlsx") {
|
|
97
|
+
const buffer = workbook.saveAsBuffer();
|
|
98
|
+
this.downloadBuffer(buffer, fileName);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Triggers a browser download from a raw Uint8Array buffer.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* const buffer = someExternalSource.getXlsxBuffer();
|
|
105
|
+
* this.excel.downloadBuffer(buffer, 'data.xlsx');
|
|
106
|
+
*/
|
|
107
|
+
downloadBuffer(buffer, fileName = "export.xlsx") {
|
|
108
|
+
const blob = new Blob([buffer], {
|
|
109
|
+
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
110
|
+
});
|
|
111
|
+
const url = URL.createObjectURL(blob);
|
|
112
|
+
const anchor = document.createElement("a");
|
|
113
|
+
anchor.href = url;
|
|
114
|
+
anchor.download = fileName;
|
|
115
|
+
anchor.style.display = "none";
|
|
116
|
+
document.body.appendChild(anchor);
|
|
117
|
+
anchor.click();
|
|
118
|
+
setTimeout(() => {
|
|
119
|
+
URL.revokeObjectURL(url);
|
|
120
|
+
document.body.removeChild(anchor);
|
|
121
|
+
}, 100);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Returns a Blob from a workbook (useful for FormData uploads).
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* const blob = this.excel.toBlob(workbook);
|
|
128
|
+
* const formData = new FormData();
|
|
129
|
+
* formData.append('file', blob, 'report.xlsx');
|
|
130
|
+
* await this.http.post('/api/upload', formData).toPromise();
|
|
131
|
+
*/
|
|
132
|
+
toBlob(workbook, fileName = "export.xlsx") {
|
|
133
|
+
const buffer = workbook.saveAsBuffer();
|
|
134
|
+
return new Blob([buffer], {
|
|
135
|
+
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
// ── Convenience builders ────────────────────────────────────────────────────
|
|
139
|
+
/**
|
|
140
|
+
* Creates a simple single-sheet workbook from a 2D data array with optional headers.
|
|
141
|
+
* Suitable for quick table exports.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* const data = [
|
|
145
|
+
* ['Alice', 30, 'Engineer'],
|
|
146
|
+
* ['Bob', 25, 'Designer'],
|
|
147
|
+
* ];
|
|
148
|
+
* const headers = ['Name', 'Age', 'Role'];
|
|
149
|
+
* this.excel.download(
|
|
150
|
+
* this.excel.fromTable(data, { headers, sheetName: 'Staff' }),
|
|
151
|
+
* 'staff.xlsx',
|
|
152
|
+
* );
|
|
153
|
+
*/
|
|
154
|
+
fromTable(rows, options) {
|
|
155
|
+
const wb = puredocsExcel.Workbook.create();
|
|
156
|
+
const sheet = wb.addWorksheet(options?.sheetName ?? "Sheet1");
|
|
157
|
+
let dataStartRow = 1;
|
|
158
|
+
if (options?.headers && options.headers.length > 0) {
|
|
159
|
+
options.headers.forEach((h, i) => sheet.getCell(1, i + 1).setValue(h));
|
|
160
|
+
if (options.headerStyle) {
|
|
161
|
+
const range = sheet.getRange(`A1:${colLetter(options.headers.length)}1`);
|
|
162
|
+
range.applyStyle(options.headerStyle);
|
|
163
|
+
}
|
|
164
|
+
dataStartRow = 2;
|
|
165
|
+
}
|
|
166
|
+
rows.forEach((row, rowIdx) => {
|
|
167
|
+
row.forEach((val, colIdx) => {
|
|
168
|
+
const cell = sheet.getCell(dataStartRow + rowIdx, colIdx + 1);
|
|
169
|
+
if (val === null || val === void 0) return;
|
|
170
|
+
if (typeof val === "string") cell.setValue(val);
|
|
171
|
+
else if (typeof val === "number") cell.setValue(val);
|
|
172
|
+
else if (typeof val === "boolean") cell.setValue(val);
|
|
173
|
+
else if (val instanceof Date) cell.setValue(val);
|
|
174
|
+
else cell.setValue(String(val));
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
return wb;
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
exports.ExcelService = __decorateClass([
|
|
181
|
+
core.Injectable({ providedIn: "root" })
|
|
182
|
+
], exports.ExcelService);
|
|
183
|
+
function colLetter(col) {
|
|
184
|
+
let result = "";
|
|
185
|
+
while (col > 0) {
|
|
186
|
+
const rem = (col - 1) % 26;
|
|
187
|
+
result = String.fromCharCode(65 + rem) + result;
|
|
188
|
+
col = Math.floor((col - rem) / 26);
|
|
189
|
+
}
|
|
190
|
+
return result;
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=index.cjs.map
|
|
193
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/excel.service.ts"],"names":["ExcelService","Workbook","Injectable"],"mappings":";;;;;;;;;;;;;AAwBaA,uBAAN,kBAAA,CAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBxB,MAAM,SAAS,IAAA,EAA+B;AAC5C,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,WAAA,EAAY;AACtC,IAAA,OAAOC,sBAAA,CAAS,WAAW,MAAM,CAAA;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,WAAW,MAAA,EAA4C;AACrD,IAAA,OAAOA,sBAAA,CAAS,WAAW,MAAM,CAAA;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,cAAA,GAA2B;AACzB,IAAA,OAAOA,uBAAS,MAAA,EAAO;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,cAAc,SAAA,EAAmD;AAC/D,IAAA,MAAM,EAAA,GAAKA,uBAAS,MAAA,EAAO;AAC3B,IAAA,SAAA,CAAU,EAAE,CAAA;AACZ,IAAA,OAAO,EAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,SAAS,QAAA,EAAgC;AACvC,IAAA,OAAO,SAAS,YAAA,EAAa;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,QAAA,CAAS,QAAA,EAAoB,QAAA,GAAW,aAAA,EAAqB;AAC3D,IAAA,MAAM,MAAA,GAAS,SAAS,YAAA,EAAa;AACrC,IAAA,IAAA,CAAK,cAAA,CAAe,QAAQ,QAAQ,CAAA;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,cAAA,CAAe,MAAA,EAAoB,QAAA,GAAW,aAAA,EAAqB;AACjE,IAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,CAAC,MAAkB,CAAA,EAAG;AAAA,MAC1C,IAAA,EAAM;AAAA,KACP,CAAA;AACD,IAAA,MAAM,GAAA,GAAM,GAAA,CAAI,eAAA,CAAgB,IAAI,CAAA;AACpC,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,GAAG,CAAA;AACzC,IAAA,MAAA,CAAO,IAAA,GAAW,GAAA;AAClB,IAAA,MAAA,CAAO,QAAA,GAAW,QAAA;AAClB,IAAA,MAAA,CAAO,MAAM,OAAA,GAAU,MAAA;AACvB,IAAA,QAAA,CAAS,IAAA,CAAK,YAAY,MAAM,CAAA;AAChC,IAAA,MAAA,CAAO,KAAA,EAAM;AAGb,IAAA,UAAA,CAAW,MAAM;AACf,MAAA,GAAA,CAAI,gBAAgB,GAAG,CAAA;AACvB,MAAA,QAAA,CAAS,IAAA,CAAK,YAAY,MAAM,CAAA;AAAA,IAClC,GAAG,GAAG,CAAA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAA,CAAO,QAAA,EAAoB,QAAA,GAAW,aAAA,EAAqB;AACzD,IAAA,MAAM,MAAA,GAAS,SAAS,YAAA,EAAa;AACrC,IAAA,OAAO,IAAI,IAAA,CAAK,CAAC,MAAkB,CAAA,EAAG;AAAA,MACpC,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,SAAA,CACE,MACA,OAAA,EAKU;AACV,IAAA,MAAM,EAAA,GAAKA,uBAAS,MAAA,EAAO;AAC3B,IAAA,MAAM,KAAA,GAAQ,EAAA,CAAG,YAAA,CAAa,OAAA,EAAS,aAAa,QAAQ,CAAA;AAE5D,IAAA,IAAI,YAAA,GAAe,CAAA;AAEnB,IAAA,IAAI,OAAA,EAAS,OAAA,IAAW,OAAA,CAAQ,OAAA,CAAQ,SAAS,CAAA,EAAG;AAClD,MAAA,OAAA,CAAQ,OAAA,CAAQ,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAA,KAAM,KAAA,CAAM,OAAA,CAAQ,CAAA,EAAG,CAAA,GAAI,CAAC,CAAA,CAAE,QAAA,CAAS,CAAC,CAAC,CAAA;AAGrE,MAAA,IAAI,QAAQ,WAAA,EAAa;AACvB,QAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,CAAS,CAAA,GAAA,EAAM,UAAU,OAAA,CAAQ,OAAA,CAAQ,MAAM,CAAC,CAAA,CAAA,CAAG,CAAA;AACvE,QAAA,KAAA,CAAM,UAAA,CAAW,QAAQ,WAAW,CAAA;AAAA,MACtC;AAEA,MAAA,YAAA,GAAe,CAAA;AAAA,IACjB;AAEA,IAAA,IAAA,CAAK,OAAA,CAAQ,CAAC,GAAA,EAAK,MAAA,KAAW;AAC5B,MAAA,GAAA,CAAI,OAAA,CAAQ,CAAC,GAAA,EAAK,MAAA,KAAW;AAC3B,QAAA,MAAM,OAAO,KAAA,CAAM,OAAA,CAAQ,YAAA,GAAe,MAAA,EAAQ,SAAS,CAAC,CAAA;AAC5D,QAAA,IAAI,GAAA,KAAQ,IAAA,IAAQ,GAAA,KAAQ,MAAA,EAAW;AACvC,QAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAW,IAAA,CAAK,SAAS,GAAG,CAAA;AAAA,aAAA,IACtC,OAAO,GAAA,KAAQ,QAAA,EAAW,IAAA,CAAK,SAAS,GAAG,CAAA;AAAA,aAAA,IAC3C,OAAO,GAAA,KAAQ,SAAA,EAAW,IAAA,CAAK,SAAS,GAAG,CAAA;AAAA,aAAA,IAC3C,GAAA,YAAe,IAAA,EAAW,IAAA,CAAK,QAAA,CAAS,GAAG,CAAA;AAAA,aAC/C,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,MAChC,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAED,IAAA,OAAO,EAAA;AAAA,EACT;AACF;AAlMaD,oBAAA,GAAN,eAAA,CAAA;AAAA,EADNE,eAAA,CAAW,EAAE,UAAA,EAAY,MAAA,EAAQ;AAAA,CAAA,EACrBF,oBAAA,CAAA;AAuMb,SAAS,UAAU,GAAA,EAAqB;AACtC,EAAA,IAAI,MAAA,GAAS,EAAA;AACb,EAAA,OAAO,MAAM,CAAA,EAAG;AACd,IAAA,MAAM,GAAA,GAAA,CAAO,MAAM,CAAA,IAAK,EAAA;AACxB,IAAA,MAAA,GAAS,MAAA,CAAO,YAAA,CAAa,EAAA,GAAK,GAAG,CAAA,GAAI,MAAA;AACzC,IAAA,GAAA,GAAM,IAAA,CAAK,KAAA,CAAA,CAAO,GAAA,GAAM,GAAA,IAAO,EAAE,CAAA;AAAA,EACnC;AACA,EAAA,OAAO,MAAA;AACT","file":"index.cjs","sourcesContent":["/**\n * Angular service for working with Excel files.\n * Wraps @devmm/puredocs-excel with Angular-idiomatic patterns:\n * - Injectable for DI\n * - Returns Observable where appropriate\n * - Handles browser download\n * - Signal-compatible (returns plain values, no Subjects needed)\n *\n * Port concept from TVE.PureDocs.Excel — adapts C# service pattern to Angular.\n */\nimport { Injectable } from '@angular/core';\nimport { Workbook, Worksheet, CellStyle } from '@devmm/puredocs-excel';\n\nexport interface ExcelReadOptions {\n /** If true, reads formula cached values. Default: true. */\n readCachedValues?: boolean;\n}\n\nexport interface ExcelWriteOptions {\n /** File name for download (browser only). Defaults to 'export.xlsx'. */\n fileName?: string;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class ExcelService {\n\n // ── Read ────────────────────────────────────────────────────────────────────\n\n /**\n * Reads an Excel file from a browser File object.\n *\n * @example\n * // In a component\n * async onFileSelected(event: Event) {\n * const file = (event.target as HTMLInputElement).files![0];\n * const wb = await this.excel.readFile(file);\n * const sheet = wb.worksheets[0];\n * console.log(sheet.getCell('A1').getText());\n * }\n */\n async readFile(file: File): Promise<Workbook> {\n const buffer = await file.arrayBuffer();\n return Workbook.fromBuffer(buffer);\n }\n\n /**\n * Reads an Excel file from an ArrayBuffer or Uint8Array.\n * Useful when data comes from an HTTP response.\n *\n * @example\n * const response = await fetch('/api/report.xlsx');\n * const buffer = await response.arrayBuffer();\n * const wb = await this.excel.readBuffer(buffer);\n */\n readBuffer(buffer: ArrayBuffer | Uint8Array): Workbook {\n return Workbook.fromBuffer(buffer);\n }\n\n // ── Create ──────────────────────────────────────────────────────────────────\n\n /**\n * Creates a new empty workbook.\n *\n * @example\n * const wb = this.excel.createWorkbook();\n * const sheet = wb.addWorksheet('Report');\n * sheet.getCell('A1').setValue('Hello');\n */\n createWorkbook(): Workbook {\n return Workbook.create();\n }\n\n /**\n * Creates a workbook, applies a configuration callback, and returns it.\n * Convenience method for building workbooks inline.\n *\n * @example\n * const wb = this.excel.buildWorkbook(wb => {\n * const sheet = wb.addWorksheet('Sales');\n * sheet.getCell('A1').setValue('Total');\n * sheet.getCell('B1').setValue(12345);\n * });\n */\n buildWorkbook(configure: (workbook: Workbook) => void): Workbook {\n const wb = Workbook.create();\n configure(wb);\n return wb;\n }\n\n // ── Export ──────────────────────────────────────────────────────────────────\n\n /**\n * Serialises a workbook to a Uint8Array buffer.\n * Use this when you want to upload the file via HTTP.\n *\n * @example\n * const buffer = this.excel.toBuffer(workbook);\n * await this.http.post('/api/upload', buffer, {\n * headers: { 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }\n * }).toPromise();\n */\n toBuffer(workbook: Workbook): Uint8Array {\n return workbook.saveAsBuffer();\n }\n\n /**\n * Triggers a browser download of the workbook.\n * Works in any modern browser via the Blob + anchor trick.\n *\n * @param workbook The workbook to download\n * @param fileName Download filename (default: \"export.xlsx\")\n *\n * @example\n * this.excel.download(workbook, 'monthly-report.xlsx');\n */\n download(workbook: Workbook, fileName = 'export.xlsx'): void {\n const buffer = workbook.saveAsBuffer();\n this.downloadBuffer(buffer, fileName);\n }\n\n /**\n * Triggers a browser download from a raw Uint8Array buffer.\n *\n * @example\n * const buffer = someExternalSource.getXlsxBuffer();\n * this.excel.downloadBuffer(buffer, 'data.xlsx');\n */\n downloadBuffer(buffer: Uint8Array, fileName = 'export.xlsx'): void {\n const blob = new Blob([buffer as BlobPart], {\n type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement('a');\n anchor.href = url;\n anchor.download = fileName;\n anchor.style.display = 'none';\n document.body.appendChild(anchor);\n anchor.click();\n\n // Cleanup after a short delay to allow the download to start\n setTimeout(() => {\n URL.revokeObjectURL(url);\n document.body.removeChild(anchor);\n }, 100);\n }\n\n /**\n * Returns a Blob from a workbook (useful for FormData uploads).\n *\n * @example\n * const blob = this.excel.toBlob(workbook);\n * const formData = new FormData();\n * formData.append('file', blob, 'report.xlsx');\n * await this.http.post('/api/upload', formData).toPromise();\n */\n toBlob(workbook: Workbook, fileName = 'export.xlsx'): Blob {\n const buffer = workbook.saveAsBuffer();\n return new Blob([buffer as BlobPart], {\n type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n });\n }\n\n // ── Convenience builders ────────────────────────────────────────────────────\n\n /**\n * Creates a simple single-sheet workbook from a 2D data array with optional headers.\n * Suitable for quick table exports.\n *\n * @example\n * const data = [\n * ['Alice', 30, 'Engineer'],\n * ['Bob', 25, 'Designer'],\n * ];\n * const headers = ['Name', 'Age', 'Role'];\n * this.excel.download(\n * this.excel.fromTable(data, { headers, sheetName: 'Staff' }),\n * 'staff.xlsx',\n * );\n */\n fromTable(\n rows: unknown[][],\n options?: {\n headers?: string[];\n sheetName?: string;\n headerStyle?: (style: CellStyle) => void;\n },\n ): Workbook {\n const wb = Workbook.create();\n const sheet = wb.addWorksheet(options?.sheetName ?? 'Sheet1');\n\n let dataStartRow = 1;\n\n if (options?.headers && options.headers.length > 0) {\n options.headers.forEach((h, i) => sheet.getCell(1, i + 1).setValue(h));\n\n // Apply header style if provided\n if (options.headerStyle) {\n const range = sheet.getRange(`A1:${colLetter(options.headers.length)}1`);\n range.applyStyle(options.headerStyle);\n }\n\n dataStartRow = 2;\n }\n\n rows.forEach((row, rowIdx) => {\n row.forEach((val, colIdx) => {\n const cell = sheet.getCell(dataStartRow + rowIdx, colIdx + 1);\n if (val === null || val === undefined) return;\n if (typeof val === 'string') cell.setValue(val);\n else if (typeof val === 'number') cell.setValue(val);\n else if (typeof val === 'boolean') cell.setValue(val);\n else if (val instanceof Date) cell.setValue(val);\n else cell.setValue(String(val));\n });\n });\n\n return wb;\n }\n}\n\n// ── Helpers ────────────────────────────────────────────────────────────────────\n\n/** Converts a 1-based column index to a letter (A, B, … Z, AA …). */\nfunction colLetter(col: number): string {\n let result = '';\n while (col > 0) {\n const rem = (col - 1) % 26;\n result = String.fromCharCode(65 + rem) + result;\n col = Math.floor((col - rem) / 26);\n }\n return result;\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Workbook, CellStyle } from '@devmm/puredocs-excel';
|
|
2
|
+
|
|
3
|
+
interface ExcelReadOptions {
|
|
4
|
+
/** If true, reads formula cached values. Default: true. */
|
|
5
|
+
readCachedValues?: boolean;
|
|
6
|
+
}
|
|
7
|
+
interface ExcelWriteOptions {
|
|
8
|
+
/** File name for download (browser only). Defaults to 'export.xlsx'. */
|
|
9
|
+
fileName?: string;
|
|
10
|
+
}
|
|
11
|
+
declare class ExcelService {
|
|
12
|
+
/**
|
|
13
|
+
* Reads an Excel file from a browser File object.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // In a component
|
|
17
|
+
* async onFileSelected(event: Event) {
|
|
18
|
+
* const file = (event.target as HTMLInputElement).files![0];
|
|
19
|
+
* const wb = await this.excel.readFile(file);
|
|
20
|
+
* const sheet = wb.worksheets[0];
|
|
21
|
+
* console.log(sheet.getCell('A1').getText());
|
|
22
|
+
* }
|
|
23
|
+
*/
|
|
24
|
+
readFile(file: File): Promise<Workbook>;
|
|
25
|
+
/**
|
|
26
|
+
* Reads an Excel file from an ArrayBuffer or Uint8Array.
|
|
27
|
+
* Useful when data comes from an HTTP response.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* const response = await fetch('/api/report.xlsx');
|
|
31
|
+
* const buffer = await response.arrayBuffer();
|
|
32
|
+
* const wb = await this.excel.readBuffer(buffer);
|
|
33
|
+
*/
|
|
34
|
+
readBuffer(buffer: ArrayBuffer | Uint8Array): Workbook;
|
|
35
|
+
/**
|
|
36
|
+
* Creates a new empty workbook.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* const wb = this.excel.createWorkbook();
|
|
40
|
+
* const sheet = wb.addWorksheet('Report');
|
|
41
|
+
* sheet.getCell('A1').setValue('Hello');
|
|
42
|
+
*/
|
|
43
|
+
createWorkbook(): Workbook;
|
|
44
|
+
/**
|
|
45
|
+
* Creates a workbook, applies a configuration callback, and returns it.
|
|
46
|
+
* Convenience method for building workbooks inline.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* const wb = this.excel.buildWorkbook(wb => {
|
|
50
|
+
* const sheet = wb.addWorksheet('Sales');
|
|
51
|
+
* sheet.getCell('A1').setValue('Total');
|
|
52
|
+
* sheet.getCell('B1').setValue(12345);
|
|
53
|
+
* });
|
|
54
|
+
*/
|
|
55
|
+
buildWorkbook(configure: (workbook: Workbook) => void): Workbook;
|
|
56
|
+
/**
|
|
57
|
+
* Serialises a workbook to a Uint8Array buffer.
|
|
58
|
+
* Use this when you want to upload the file via HTTP.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* const buffer = this.excel.toBuffer(workbook);
|
|
62
|
+
* await this.http.post('/api/upload', buffer, {
|
|
63
|
+
* headers: { 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }
|
|
64
|
+
* }).toPromise();
|
|
65
|
+
*/
|
|
66
|
+
toBuffer(workbook: Workbook): Uint8Array;
|
|
67
|
+
/**
|
|
68
|
+
* Triggers a browser download of the workbook.
|
|
69
|
+
* Works in any modern browser via the Blob + anchor trick.
|
|
70
|
+
*
|
|
71
|
+
* @param workbook The workbook to download
|
|
72
|
+
* @param fileName Download filename (default: "export.xlsx")
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* this.excel.download(workbook, 'monthly-report.xlsx');
|
|
76
|
+
*/
|
|
77
|
+
download(workbook: Workbook, fileName?: string): void;
|
|
78
|
+
/**
|
|
79
|
+
* Triggers a browser download from a raw Uint8Array buffer.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* const buffer = someExternalSource.getXlsxBuffer();
|
|
83
|
+
* this.excel.downloadBuffer(buffer, 'data.xlsx');
|
|
84
|
+
*/
|
|
85
|
+
downloadBuffer(buffer: Uint8Array, fileName?: string): void;
|
|
86
|
+
/**
|
|
87
|
+
* Returns a Blob from a workbook (useful for FormData uploads).
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* const blob = this.excel.toBlob(workbook);
|
|
91
|
+
* const formData = new FormData();
|
|
92
|
+
* formData.append('file', blob, 'report.xlsx');
|
|
93
|
+
* await this.http.post('/api/upload', formData).toPromise();
|
|
94
|
+
*/
|
|
95
|
+
toBlob(workbook: Workbook, fileName?: string): Blob;
|
|
96
|
+
/**
|
|
97
|
+
* Creates a simple single-sheet workbook from a 2D data array with optional headers.
|
|
98
|
+
* Suitable for quick table exports.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* const data = [
|
|
102
|
+
* ['Alice', 30, 'Engineer'],
|
|
103
|
+
* ['Bob', 25, 'Designer'],
|
|
104
|
+
* ];
|
|
105
|
+
* const headers = ['Name', 'Age', 'Role'];
|
|
106
|
+
* this.excel.download(
|
|
107
|
+
* this.excel.fromTable(data, { headers, sheetName: 'Staff' }),
|
|
108
|
+
* 'staff.xlsx',
|
|
109
|
+
* );
|
|
110
|
+
*/
|
|
111
|
+
fromTable(rows: unknown[][], options?: {
|
|
112
|
+
headers?: string[];
|
|
113
|
+
sheetName?: string;
|
|
114
|
+
headerStyle?: (style: CellStyle) => void;
|
|
115
|
+
}): Workbook;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export { type ExcelReadOptions, ExcelService, type ExcelWriteOptions };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Workbook, CellStyle } from '@devmm/puredocs-excel';
|
|
2
|
+
|
|
3
|
+
interface ExcelReadOptions {
|
|
4
|
+
/** If true, reads formula cached values. Default: true. */
|
|
5
|
+
readCachedValues?: boolean;
|
|
6
|
+
}
|
|
7
|
+
interface ExcelWriteOptions {
|
|
8
|
+
/** File name for download (browser only). Defaults to 'export.xlsx'. */
|
|
9
|
+
fileName?: string;
|
|
10
|
+
}
|
|
11
|
+
declare class ExcelService {
|
|
12
|
+
/**
|
|
13
|
+
* Reads an Excel file from a browser File object.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // In a component
|
|
17
|
+
* async onFileSelected(event: Event) {
|
|
18
|
+
* const file = (event.target as HTMLInputElement).files![0];
|
|
19
|
+
* const wb = await this.excel.readFile(file);
|
|
20
|
+
* const sheet = wb.worksheets[0];
|
|
21
|
+
* console.log(sheet.getCell('A1').getText());
|
|
22
|
+
* }
|
|
23
|
+
*/
|
|
24
|
+
readFile(file: File): Promise<Workbook>;
|
|
25
|
+
/**
|
|
26
|
+
* Reads an Excel file from an ArrayBuffer or Uint8Array.
|
|
27
|
+
* Useful when data comes from an HTTP response.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* const response = await fetch('/api/report.xlsx');
|
|
31
|
+
* const buffer = await response.arrayBuffer();
|
|
32
|
+
* const wb = await this.excel.readBuffer(buffer);
|
|
33
|
+
*/
|
|
34
|
+
readBuffer(buffer: ArrayBuffer | Uint8Array): Workbook;
|
|
35
|
+
/**
|
|
36
|
+
* Creates a new empty workbook.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* const wb = this.excel.createWorkbook();
|
|
40
|
+
* const sheet = wb.addWorksheet('Report');
|
|
41
|
+
* sheet.getCell('A1').setValue('Hello');
|
|
42
|
+
*/
|
|
43
|
+
createWorkbook(): Workbook;
|
|
44
|
+
/**
|
|
45
|
+
* Creates a workbook, applies a configuration callback, and returns it.
|
|
46
|
+
* Convenience method for building workbooks inline.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* const wb = this.excel.buildWorkbook(wb => {
|
|
50
|
+
* const sheet = wb.addWorksheet('Sales');
|
|
51
|
+
* sheet.getCell('A1').setValue('Total');
|
|
52
|
+
* sheet.getCell('B1').setValue(12345);
|
|
53
|
+
* });
|
|
54
|
+
*/
|
|
55
|
+
buildWorkbook(configure: (workbook: Workbook) => void): Workbook;
|
|
56
|
+
/**
|
|
57
|
+
* Serialises a workbook to a Uint8Array buffer.
|
|
58
|
+
* Use this when you want to upload the file via HTTP.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* const buffer = this.excel.toBuffer(workbook);
|
|
62
|
+
* await this.http.post('/api/upload', buffer, {
|
|
63
|
+
* headers: { 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }
|
|
64
|
+
* }).toPromise();
|
|
65
|
+
*/
|
|
66
|
+
toBuffer(workbook: Workbook): Uint8Array;
|
|
67
|
+
/**
|
|
68
|
+
* Triggers a browser download of the workbook.
|
|
69
|
+
* Works in any modern browser via the Blob + anchor trick.
|
|
70
|
+
*
|
|
71
|
+
* @param workbook The workbook to download
|
|
72
|
+
* @param fileName Download filename (default: "export.xlsx")
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* this.excel.download(workbook, 'monthly-report.xlsx');
|
|
76
|
+
*/
|
|
77
|
+
download(workbook: Workbook, fileName?: string): void;
|
|
78
|
+
/**
|
|
79
|
+
* Triggers a browser download from a raw Uint8Array buffer.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* const buffer = someExternalSource.getXlsxBuffer();
|
|
83
|
+
* this.excel.downloadBuffer(buffer, 'data.xlsx');
|
|
84
|
+
*/
|
|
85
|
+
downloadBuffer(buffer: Uint8Array, fileName?: string): void;
|
|
86
|
+
/**
|
|
87
|
+
* Returns a Blob from a workbook (useful for FormData uploads).
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* const blob = this.excel.toBlob(workbook);
|
|
91
|
+
* const formData = new FormData();
|
|
92
|
+
* formData.append('file', blob, 'report.xlsx');
|
|
93
|
+
* await this.http.post('/api/upload', formData).toPromise();
|
|
94
|
+
*/
|
|
95
|
+
toBlob(workbook: Workbook, fileName?: string): Blob;
|
|
96
|
+
/**
|
|
97
|
+
* Creates a simple single-sheet workbook from a 2D data array with optional headers.
|
|
98
|
+
* Suitable for quick table exports.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* const data = [
|
|
102
|
+
* ['Alice', 30, 'Engineer'],
|
|
103
|
+
* ['Bob', 25, 'Designer'],
|
|
104
|
+
* ];
|
|
105
|
+
* const headers = ['Name', 'Age', 'Role'];
|
|
106
|
+
* this.excel.download(
|
|
107
|
+
* this.excel.fromTable(data, { headers, sheetName: 'Staff' }),
|
|
108
|
+
* 'staff.xlsx',
|
|
109
|
+
* );
|
|
110
|
+
*/
|
|
111
|
+
fromTable(rows: unknown[][], options?: {
|
|
112
|
+
headers?: string[];
|
|
113
|
+
sheetName?: string;
|
|
114
|
+
headerStyle?: (style: CellStyle) => void;
|
|
115
|
+
}): Workbook;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export { type ExcelReadOptions, ExcelService, type ExcelWriteOptions };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { Workbook } from '@devmm/puredocs-excel';
|
|
3
|
+
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
6
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
7
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
8
|
+
if (decorator = decorators[i])
|
|
9
|
+
result = (decorator(result)) || result;
|
|
10
|
+
return result;
|
|
11
|
+
};
|
|
12
|
+
var ExcelService = class {
|
|
13
|
+
// ── Read ────────────────────────────────────────────────────────────────────
|
|
14
|
+
/**
|
|
15
|
+
* Reads an Excel file from a browser File object.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* // In a component
|
|
19
|
+
* async onFileSelected(event: Event) {
|
|
20
|
+
* const file = (event.target as HTMLInputElement).files![0];
|
|
21
|
+
* const wb = await this.excel.readFile(file);
|
|
22
|
+
* const sheet = wb.worksheets[0];
|
|
23
|
+
* console.log(sheet.getCell('A1').getText());
|
|
24
|
+
* }
|
|
25
|
+
*/
|
|
26
|
+
async readFile(file) {
|
|
27
|
+
const buffer = await file.arrayBuffer();
|
|
28
|
+
return Workbook.fromBuffer(buffer);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Reads an Excel file from an ArrayBuffer or Uint8Array.
|
|
32
|
+
* Useful when data comes from an HTTP response.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* const response = await fetch('/api/report.xlsx');
|
|
36
|
+
* const buffer = await response.arrayBuffer();
|
|
37
|
+
* const wb = await this.excel.readBuffer(buffer);
|
|
38
|
+
*/
|
|
39
|
+
readBuffer(buffer) {
|
|
40
|
+
return Workbook.fromBuffer(buffer);
|
|
41
|
+
}
|
|
42
|
+
// ── Create ──────────────────────────────────────────────────────────────────
|
|
43
|
+
/**
|
|
44
|
+
* Creates a new empty workbook.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* const wb = this.excel.createWorkbook();
|
|
48
|
+
* const sheet = wb.addWorksheet('Report');
|
|
49
|
+
* sheet.getCell('A1').setValue('Hello');
|
|
50
|
+
*/
|
|
51
|
+
createWorkbook() {
|
|
52
|
+
return Workbook.create();
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Creates a workbook, applies a configuration callback, and returns it.
|
|
56
|
+
* Convenience method for building workbooks inline.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* const wb = this.excel.buildWorkbook(wb => {
|
|
60
|
+
* const sheet = wb.addWorksheet('Sales');
|
|
61
|
+
* sheet.getCell('A1').setValue('Total');
|
|
62
|
+
* sheet.getCell('B1').setValue(12345);
|
|
63
|
+
* });
|
|
64
|
+
*/
|
|
65
|
+
buildWorkbook(configure) {
|
|
66
|
+
const wb = Workbook.create();
|
|
67
|
+
configure(wb);
|
|
68
|
+
return wb;
|
|
69
|
+
}
|
|
70
|
+
// ── Export ──────────────────────────────────────────────────────────────────
|
|
71
|
+
/**
|
|
72
|
+
* Serialises a workbook to a Uint8Array buffer.
|
|
73
|
+
* Use this when you want to upload the file via HTTP.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* const buffer = this.excel.toBuffer(workbook);
|
|
77
|
+
* await this.http.post('/api/upload', buffer, {
|
|
78
|
+
* headers: { 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }
|
|
79
|
+
* }).toPromise();
|
|
80
|
+
*/
|
|
81
|
+
toBuffer(workbook) {
|
|
82
|
+
return workbook.saveAsBuffer();
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Triggers a browser download of the workbook.
|
|
86
|
+
* Works in any modern browser via the Blob + anchor trick.
|
|
87
|
+
*
|
|
88
|
+
* @param workbook The workbook to download
|
|
89
|
+
* @param fileName Download filename (default: "export.xlsx")
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* this.excel.download(workbook, 'monthly-report.xlsx');
|
|
93
|
+
*/
|
|
94
|
+
download(workbook, fileName = "export.xlsx") {
|
|
95
|
+
const buffer = workbook.saveAsBuffer();
|
|
96
|
+
this.downloadBuffer(buffer, fileName);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Triggers a browser download from a raw Uint8Array buffer.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* const buffer = someExternalSource.getXlsxBuffer();
|
|
103
|
+
* this.excel.downloadBuffer(buffer, 'data.xlsx');
|
|
104
|
+
*/
|
|
105
|
+
downloadBuffer(buffer, fileName = "export.xlsx") {
|
|
106
|
+
const blob = new Blob([buffer], {
|
|
107
|
+
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
108
|
+
});
|
|
109
|
+
const url = URL.createObjectURL(blob);
|
|
110
|
+
const anchor = document.createElement("a");
|
|
111
|
+
anchor.href = url;
|
|
112
|
+
anchor.download = fileName;
|
|
113
|
+
anchor.style.display = "none";
|
|
114
|
+
document.body.appendChild(anchor);
|
|
115
|
+
anchor.click();
|
|
116
|
+
setTimeout(() => {
|
|
117
|
+
URL.revokeObjectURL(url);
|
|
118
|
+
document.body.removeChild(anchor);
|
|
119
|
+
}, 100);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Returns a Blob from a workbook (useful for FormData uploads).
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* const blob = this.excel.toBlob(workbook);
|
|
126
|
+
* const formData = new FormData();
|
|
127
|
+
* formData.append('file', blob, 'report.xlsx');
|
|
128
|
+
* await this.http.post('/api/upload', formData).toPromise();
|
|
129
|
+
*/
|
|
130
|
+
toBlob(workbook, fileName = "export.xlsx") {
|
|
131
|
+
const buffer = workbook.saveAsBuffer();
|
|
132
|
+
return new Blob([buffer], {
|
|
133
|
+
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// ── Convenience builders ────────────────────────────────────────────────────
|
|
137
|
+
/**
|
|
138
|
+
* Creates a simple single-sheet workbook from a 2D data array with optional headers.
|
|
139
|
+
* Suitable for quick table exports.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* const data = [
|
|
143
|
+
* ['Alice', 30, 'Engineer'],
|
|
144
|
+
* ['Bob', 25, 'Designer'],
|
|
145
|
+
* ];
|
|
146
|
+
* const headers = ['Name', 'Age', 'Role'];
|
|
147
|
+
* this.excel.download(
|
|
148
|
+
* this.excel.fromTable(data, { headers, sheetName: 'Staff' }),
|
|
149
|
+
* 'staff.xlsx',
|
|
150
|
+
* );
|
|
151
|
+
*/
|
|
152
|
+
fromTable(rows, options) {
|
|
153
|
+
const wb = Workbook.create();
|
|
154
|
+
const sheet = wb.addWorksheet(options?.sheetName ?? "Sheet1");
|
|
155
|
+
let dataStartRow = 1;
|
|
156
|
+
if (options?.headers && options.headers.length > 0) {
|
|
157
|
+
options.headers.forEach((h, i) => sheet.getCell(1, i + 1).setValue(h));
|
|
158
|
+
if (options.headerStyle) {
|
|
159
|
+
const range = sheet.getRange(`A1:${colLetter(options.headers.length)}1`);
|
|
160
|
+
range.applyStyle(options.headerStyle);
|
|
161
|
+
}
|
|
162
|
+
dataStartRow = 2;
|
|
163
|
+
}
|
|
164
|
+
rows.forEach((row, rowIdx) => {
|
|
165
|
+
row.forEach((val, colIdx) => {
|
|
166
|
+
const cell = sheet.getCell(dataStartRow + rowIdx, colIdx + 1);
|
|
167
|
+
if (val === null || val === void 0) return;
|
|
168
|
+
if (typeof val === "string") cell.setValue(val);
|
|
169
|
+
else if (typeof val === "number") cell.setValue(val);
|
|
170
|
+
else if (typeof val === "boolean") cell.setValue(val);
|
|
171
|
+
else if (val instanceof Date) cell.setValue(val);
|
|
172
|
+
else cell.setValue(String(val));
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
return wb;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
ExcelService = __decorateClass([
|
|
179
|
+
Injectable({ providedIn: "root" })
|
|
180
|
+
], ExcelService);
|
|
181
|
+
function colLetter(col) {
|
|
182
|
+
let result = "";
|
|
183
|
+
while (col > 0) {
|
|
184
|
+
const rem = (col - 1) % 26;
|
|
185
|
+
result = String.fromCharCode(65 + rem) + result;
|
|
186
|
+
col = Math.floor((col - rem) / 26);
|
|
187
|
+
}
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export { ExcelService };
|
|
192
|
+
//# sourceMappingURL=index.js.map
|
|
193
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/excel.service.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Angular service for working with Excel files.\n * Wraps @devmm/puredocs-excel with Angular-idiomatic patterns:\n * - Injectable for DI\n * - Returns Observable where appropriate\n * - Handles browser download\n * - Signal-compatible (returns plain values, no Subjects needed)\n *\n * Port concept from TVE.PureDocs.Excel — adapts C# service pattern to Angular.\n */\nimport { Injectable } from '@angular/core';\nimport { Workbook, Worksheet, CellStyle } from '@devmm/puredocs-excel';\n\nexport interface ExcelReadOptions {\n /** If true, reads formula cached values. Default: true. */\n readCachedValues?: boolean;\n}\n\nexport interface ExcelWriteOptions {\n /** File name for download (browser only). Defaults to 'export.xlsx'. */\n fileName?: string;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class ExcelService {\n\n // ── Read ────────────────────────────────────────────────────────────────────\n\n /**\n * Reads an Excel file from a browser File object.\n *\n * @example\n * // In a component\n * async onFileSelected(event: Event) {\n * const file = (event.target as HTMLInputElement).files![0];\n * const wb = await this.excel.readFile(file);\n * const sheet = wb.worksheets[0];\n * console.log(sheet.getCell('A1').getText());\n * }\n */\n async readFile(file: File): Promise<Workbook> {\n const buffer = await file.arrayBuffer();\n return Workbook.fromBuffer(buffer);\n }\n\n /**\n * Reads an Excel file from an ArrayBuffer or Uint8Array.\n * Useful when data comes from an HTTP response.\n *\n * @example\n * const response = await fetch('/api/report.xlsx');\n * const buffer = await response.arrayBuffer();\n * const wb = await this.excel.readBuffer(buffer);\n */\n readBuffer(buffer: ArrayBuffer | Uint8Array): Workbook {\n return Workbook.fromBuffer(buffer);\n }\n\n // ── Create ──────────────────────────────────────────────────────────────────\n\n /**\n * Creates a new empty workbook.\n *\n * @example\n * const wb = this.excel.createWorkbook();\n * const sheet = wb.addWorksheet('Report');\n * sheet.getCell('A1').setValue('Hello');\n */\n createWorkbook(): Workbook {\n return Workbook.create();\n }\n\n /**\n * Creates a workbook, applies a configuration callback, and returns it.\n * Convenience method for building workbooks inline.\n *\n * @example\n * const wb = this.excel.buildWorkbook(wb => {\n * const sheet = wb.addWorksheet('Sales');\n * sheet.getCell('A1').setValue('Total');\n * sheet.getCell('B1').setValue(12345);\n * });\n */\n buildWorkbook(configure: (workbook: Workbook) => void): Workbook {\n const wb = Workbook.create();\n configure(wb);\n return wb;\n }\n\n // ── Export ──────────────────────────────────────────────────────────────────\n\n /**\n * Serialises a workbook to a Uint8Array buffer.\n * Use this when you want to upload the file via HTTP.\n *\n * @example\n * const buffer = this.excel.toBuffer(workbook);\n * await this.http.post('/api/upload', buffer, {\n * headers: { 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }\n * }).toPromise();\n */\n toBuffer(workbook: Workbook): Uint8Array {\n return workbook.saveAsBuffer();\n }\n\n /**\n * Triggers a browser download of the workbook.\n * Works in any modern browser via the Blob + anchor trick.\n *\n * @param workbook The workbook to download\n * @param fileName Download filename (default: \"export.xlsx\")\n *\n * @example\n * this.excel.download(workbook, 'monthly-report.xlsx');\n */\n download(workbook: Workbook, fileName = 'export.xlsx'): void {\n const buffer = workbook.saveAsBuffer();\n this.downloadBuffer(buffer, fileName);\n }\n\n /**\n * Triggers a browser download from a raw Uint8Array buffer.\n *\n * @example\n * const buffer = someExternalSource.getXlsxBuffer();\n * this.excel.downloadBuffer(buffer, 'data.xlsx');\n */\n downloadBuffer(buffer: Uint8Array, fileName = 'export.xlsx'): void {\n const blob = new Blob([buffer as BlobPart], {\n type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement('a');\n anchor.href = url;\n anchor.download = fileName;\n anchor.style.display = 'none';\n document.body.appendChild(anchor);\n anchor.click();\n\n // Cleanup after a short delay to allow the download to start\n setTimeout(() => {\n URL.revokeObjectURL(url);\n document.body.removeChild(anchor);\n }, 100);\n }\n\n /**\n * Returns a Blob from a workbook (useful for FormData uploads).\n *\n * @example\n * const blob = this.excel.toBlob(workbook);\n * const formData = new FormData();\n * formData.append('file', blob, 'report.xlsx');\n * await this.http.post('/api/upload', formData).toPromise();\n */\n toBlob(workbook: Workbook, fileName = 'export.xlsx'): Blob {\n const buffer = workbook.saveAsBuffer();\n return new Blob([buffer as BlobPart], {\n type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n });\n }\n\n // ── Convenience builders ────────────────────────────────────────────────────\n\n /**\n * Creates a simple single-sheet workbook from a 2D data array with optional headers.\n * Suitable for quick table exports.\n *\n * @example\n * const data = [\n * ['Alice', 30, 'Engineer'],\n * ['Bob', 25, 'Designer'],\n * ];\n * const headers = ['Name', 'Age', 'Role'];\n * this.excel.download(\n * this.excel.fromTable(data, { headers, sheetName: 'Staff' }),\n * 'staff.xlsx',\n * );\n */\n fromTable(\n rows: unknown[][],\n options?: {\n headers?: string[];\n sheetName?: string;\n headerStyle?: (style: CellStyle) => void;\n },\n ): Workbook {\n const wb = Workbook.create();\n const sheet = wb.addWorksheet(options?.sheetName ?? 'Sheet1');\n\n let dataStartRow = 1;\n\n if (options?.headers && options.headers.length > 0) {\n options.headers.forEach((h, i) => sheet.getCell(1, i + 1).setValue(h));\n\n // Apply header style if provided\n if (options.headerStyle) {\n const range = sheet.getRange(`A1:${colLetter(options.headers.length)}1`);\n range.applyStyle(options.headerStyle);\n }\n\n dataStartRow = 2;\n }\n\n rows.forEach((row, rowIdx) => {\n row.forEach((val, colIdx) => {\n const cell = sheet.getCell(dataStartRow + rowIdx, colIdx + 1);\n if (val === null || val === undefined) return;\n if (typeof val === 'string') cell.setValue(val);\n else if (typeof val === 'number') cell.setValue(val);\n else if (typeof val === 'boolean') cell.setValue(val);\n else if (val instanceof Date) cell.setValue(val);\n else cell.setValue(String(val));\n });\n });\n\n return wb;\n }\n}\n\n// ── Helpers ────────────────────────────────────────────────────────────────────\n\n/** Converts a 1-based column index to a letter (A, B, … Z, AA …). */\nfunction colLetter(col: number): string {\n let result = '';\n while (col > 0) {\n const rem = (col - 1) % 26;\n result = String.fromCharCode(65 + rem) + result;\n col = Math.floor((col - rem) / 26);\n }\n return result;\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@devmm/puredocs-excel-angular",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Angular service wrapper for @devmm/puredocs-excel",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"require": "./dist/index.cjs"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"@angular/common": ">=17.0.0",
|
|
23
|
+
"@angular/core": ">=17.0.0",
|
|
24
|
+
"@devmm/puredocs-excel": "1.0.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"typescript": "^5.4.0",
|
|
28
|
+
"tsup": "^8.0.0",
|
|
29
|
+
"@devmm/puredocs-excel": "1.0.0"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/quangtrungsoft/puredocs-excel.git",
|
|
34
|
+
"directory": "packages/angular"
|
|
35
|
+
},
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/quangtrungsoft/puredocs-excel/issues"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://github.com/quangtrungsoft/puredocs-excel/tree/main/packages/angular#readme",
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsup",
|
|
42
|
+
"typecheck": "tsc --noEmit",
|
|
43
|
+
"clean": "rm -rf dist"
|
|
44
|
+
}
|
|
45
|
+
}
|