@canvas-components/utils 0.2.3 → 0.2.5
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/dist/export/index.cjs +47 -16
- package/dist/export/index.cjs.map +1 -1
- package/dist/export/index.d.cts +10 -0
- package/dist/export/index.d.ts +10 -0
- package/dist/export/index.js +47 -16
- package/dist/export/index.js.map +1 -1
- package/dist/index.cjs +77 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +95 -0
- package/dist/index.d.ts +95 -0
- package/dist/index.js +76 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/export/index.cjs
CHANGED
|
@@ -33,7 +33,10 @@ var __export = (target, all) => {
|
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
// src/export/xlsx-runtime.ts
|
|
36
|
-
function createXlsxWriter(xlsx, header, sheetName, maxRows = 1048576) {
|
|
36
|
+
function createXlsxWriter(xlsx, header, sheetName, maxRows = 1048576, merges = []) {
|
|
37
|
+
const headerRows = Array.isArray(header[0]) ? header : [header];
|
|
38
|
+
if (headerRows.length >= maxRows)
|
|
39
|
+
throw new Error("XLSX \u8868\u5934\u884C\u6570\u8D85\u8FC7\u5DE5\u4F5C\u8868\u5BB9\u91CF");
|
|
37
40
|
const workbook = xlsx.utils.book_new();
|
|
38
41
|
let worksheet;
|
|
39
42
|
let rowCount = 0;
|
|
@@ -41,7 +44,7 @@ function createXlsxWriter(xlsx, header, sheetName, maxRows = 1048576) {
|
|
|
41
44
|
const baseName = sheetName.replace(/[\\/?*[\]:]/g, "_").replace(/^'+|'+$/g, "") || "Sheet1";
|
|
42
45
|
const addSheet = () => {
|
|
43
46
|
const suffix = sheetIndex === 0 ? "" : `_${sheetIndex + 1}`;
|
|
44
|
-
worksheet = xlsx.utils.aoa_to_sheet(
|
|
47
|
+
worksheet = xlsx.utils.aoa_to_sheet(headerRows, {
|
|
45
48
|
dense: true
|
|
46
49
|
});
|
|
47
50
|
xlsx.utils.book_append_sheet(
|
|
@@ -49,7 +52,8 @@ function createXlsxWriter(xlsx, header, sheetName, maxRows = 1048576) {
|
|
|
49
52
|
worksheet,
|
|
50
53
|
baseName.slice(0, 31 - suffix.length) + suffix
|
|
51
54
|
);
|
|
52
|
-
|
|
55
|
+
if (merges.length && sheetIndex === 0) worksheet["!merges"] = merges;
|
|
56
|
+
rowCount = headerRows.length;
|
|
53
57
|
sheetIndex += 1;
|
|
54
58
|
};
|
|
55
59
|
addSheet();
|
|
@@ -125,7 +129,7 @@ let writer;
|
|
|
125
129
|
self.onmessage = function(event) {
|
|
126
130
|
try {
|
|
127
131
|
const message = event.data;
|
|
128
|
-
if (message.type === 'init') writer = createWriter(XLSX, message.header, message.sheetName);
|
|
132
|
+
if (message.type === 'init') writer = createWriter(XLSX, message.header, message.sheetName, undefined, message.merges);
|
|
129
133
|
else if (message.type === 'append') writer.append(message.rows);
|
|
130
134
|
else if (message.type === 'finish') {
|
|
131
135
|
const buffer = writer.finish();
|
|
@@ -173,8 +177,22 @@ async function buildXlsxPart(params, rangeStart, rangeEnd) {
|
|
|
173
177
|
throw new Error(
|
|
174
178
|
"\u5355\u4EFD XLSX \u6570\u636E\u8D85\u8FC7\u5B89\u5168\u9650\u5236\uFF0C\u8BF7\u4F7F\u7528 exportTableToXlsx \u81EA\u52A8\u5206\u6587\u4EF6\u5BFC\u51FA"
|
|
175
179
|
);
|
|
176
|
-
const header = columns.map((column) => column.title);
|
|
177
|
-
|
|
180
|
+
const header = params.headerRows?.length ? params.headerRows : [columns.map((column) => column.title)];
|
|
181
|
+
const headerRowCount = header.length;
|
|
182
|
+
const merges = (params.merges ?? []).flatMap((merge) => {
|
|
183
|
+
if (merge.e.r < headerRowCount) return [merge];
|
|
184
|
+
const start = Math.max(merge.s.r, headerRowCount + rangeStart);
|
|
185
|
+
const end = Math.min(merge.e.r, headerRowCount + rangeEnd - 1);
|
|
186
|
+
return end < start || end === start && merge.s.c === merge.e.c ? [] : [
|
|
187
|
+
{
|
|
188
|
+
s: { r: start - rangeStart, c: merge.s.c },
|
|
189
|
+
e: { r: end - rangeStart, c: merge.e.c }
|
|
190
|
+
}
|
|
191
|
+
];
|
|
192
|
+
});
|
|
193
|
+
if (header.some((row) => row.length > columns.length))
|
|
194
|
+
throw new Error("XLSX \u8868\u5934\u5355\u5143\u683C\u6570\u4E0D\u80FD\u8D85\u8FC7\u5BFC\u51FA\u5217\u6570");
|
|
195
|
+
let textSize = header.flat().reduce((size, title) => size + title.length, 0);
|
|
178
196
|
const normalizeExportCell = (value) => {
|
|
179
197
|
const cell = normalizeCell(value);
|
|
180
198
|
if (typeof cell === "string") {
|
|
@@ -188,7 +206,7 @@ async function buildXlsxPart(params, rangeStart, rangeEnd) {
|
|
|
188
206
|
}
|
|
189
207
|
return cell;
|
|
190
208
|
};
|
|
191
|
-
header.forEach((title) => {
|
|
209
|
+
header.flat().forEach((title) => {
|
|
192
210
|
if (title.length > 32767) throw new Error("XLSX \u8868\u5934\u8D85\u8FC7 32767 \u5B57\u7B26");
|
|
193
211
|
});
|
|
194
212
|
if (textSize > XLSX_MAX_TEXT_CHARS_PER_FILE)
|
|
@@ -240,7 +258,7 @@ async function buildXlsxPart(params, rangeStart, rangeEnd) {
|
|
|
240
258
|
() => fail(new Error("XLSX Worker \u542F\u52A8\u8D85\u65F6")),
|
|
241
259
|
1e4
|
|
242
260
|
);
|
|
243
|
-
await request({ type: "init", header, sheetName });
|
|
261
|
+
await request({ type: "init", header, sheetName, merges });
|
|
244
262
|
} catch {
|
|
245
263
|
worker?.terminate();
|
|
246
264
|
worker = void 0;
|
|
@@ -250,7 +268,7 @@ async function buildXlsxPart(params, rangeStart, rangeEnd) {
|
|
|
250
268
|
}
|
|
251
269
|
}
|
|
252
270
|
checkAbort();
|
|
253
|
-
const writer = worker ? void 0 : createXlsxWriter(XLSX__namespace, header, sheetName);
|
|
271
|
+
const writer = worker ? void 0 : createXlsxWriter(XLSX__namespace, header, sheetName, void 0, merges);
|
|
254
272
|
const totalRows = rangeEnd - rangeStart;
|
|
255
273
|
const report = (phase, completedRows) => params.onProgress?.({
|
|
256
274
|
phase,
|
|
@@ -381,7 +399,7 @@ function getXlsxRowsPerFile(params) {
|
|
|
381
399
|
throw new Error("XLSX \u5206\u6587\u4EF6\u4E0A\u9650\u5FC5\u987B\u4E3A\u6B63\u6574\u6570");
|
|
382
400
|
const byCells = Math.floor(
|
|
383
401
|
Math.min(cellLimit, XLSX_MAX_CELLS_PER_FILE) / Math.max(1, params.columns.length)
|
|
384
|
-
) - 1;
|
|
402
|
+
) - (params.headerRows?.length || 1);
|
|
385
403
|
if (byCells < 1) throw new Error("XLSX \u5355\u5143\u683C\u9884\u7B97\u4E0D\u8DB3\u4EE5\u5BB9\u7EB3\u8868\u5934\u548C\u4E00\u884C\u6570\u636E");
|
|
386
404
|
return Math.min(rowLimit, XLSX_MAX_ROWS_PER_FILE, byCells);
|
|
387
405
|
}
|
|
@@ -403,7 +421,8 @@ function buildCsvContent(params) {
|
|
|
403
421
|
columns.map((column) => column.title),
|
|
404
422
|
...rows.map(
|
|
405
423
|
(row, rowIndex) => columns.map((column) => column.value(row, rowIndex))
|
|
406
|
-
)
|
|
424
|
+
),
|
|
425
|
+
...params.footerRows ?? []
|
|
407
426
|
]);
|
|
408
427
|
}
|
|
409
428
|
function serializeCsvRows(rows, lineBreak = "\n") {
|
|
@@ -415,7 +434,13 @@ function buildTxtContent(params) {
|
|
|
415
434
|
const body = rows.map(
|
|
416
435
|
(row, rowIndex) => columns.map((column) => normalizeTextCell(column.value(row, rowIndex))).join(" ")
|
|
417
436
|
);
|
|
418
|
-
return [
|
|
437
|
+
return [
|
|
438
|
+
header,
|
|
439
|
+
...body,
|
|
440
|
+
...(params.footerRows ?? []).map(
|
|
441
|
+
(row) => row.map(normalizeTextCell).join(" ")
|
|
442
|
+
)
|
|
443
|
+
].join("\n");
|
|
419
444
|
}
|
|
420
445
|
async function downloadJsonFile(params) {
|
|
421
446
|
const { data, fileName, space = 2 } = params;
|
|
@@ -427,8 +452,8 @@ async function downloadJsonFile(params) {
|
|
|
427
452
|
});
|
|
428
453
|
}
|
|
429
454
|
async function exportTableToCsv(params) {
|
|
430
|
-
const { fileName, rows, columns } = params;
|
|
431
|
-
const content = await buildCsvContentAsync({ rows, columns });
|
|
455
|
+
const { fileName, rows, columns, footerRows } = params;
|
|
456
|
+
const content = await buildCsvContentAsync({ rows, columns, footerRows });
|
|
432
457
|
downloadTextFile({
|
|
433
458
|
fileName: ensureExtension(fileName, "csv"),
|
|
434
459
|
content,
|
|
@@ -436,8 +461,8 @@ async function exportTableToCsv(params) {
|
|
|
436
461
|
});
|
|
437
462
|
}
|
|
438
463
|
async function exportTableToTxt(params) {
|
|
439
|
-
const { fileName, rows, columns } = params;
|
|
440
|
-
const content = await buildTxtContentAsync({ rows, columns });
|
|
464
|
+
const { fileName, rows, columns, footerRows } = params;
|
|
465
|
+
const content = await buildTxtContentAsync({ rows, columns, footerRows });
|
|
441
466
|
downloadTextFile({
|
|
442
467
|
fileName: ensureExtension(fileName, "txt"),
|
|
443
468
|
content,
|
|
@@ -481,6 +506,9 @@ async function buildCsvContentAsync(params) {
|
|
|
481
506
|
}
|
|
482
507
|
await yieldToMainThread();
|
|
483
508
|
}
|
|
509
|
+
for (const footer of params.footerRows ?? []) {
|
|
510
|
+
parts.push("\n", footer.map(escapeCsvCell).join(","));
|
|
511
|
+
}
|
|
484
512
|
return parts.join("");
|
|
485
513
|
}
|
|
486
514
|
async function buildTxtContentAsync(params) {
|
|
@@ -496,6 +524,9 @@ async function buildTxtContentAsync(params) {
|
|
|
496
524
|
}
|
|
497
525
|
await yieldToMainThread();
|
|
498
526
|
}
|
|
527
|
+
for (const footer of params.footerRows ?? []) {
|
|
528
|
+
parts.push("\n", footer.map(normalizeTextCell).join(" "));
|
|
529
|
+
}
|
|
499
530
|
return parts.join("");
|
|
500
531
|
}
|
|
501
532
|
function escapeCsvCell(value) {
|