@canvas-components/utils 0.2.4 → 0.2.6
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 +62 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +64 -1
- package/dist/index.d.ts +64 -1
- package/dist/index.js +62 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/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();
|
|
@@ -228,8 +232,22 @@ async function buildXlsxPart(params, rangeStart, rangeEnd) {
|
|
|
228
232
|
throw new Error(
|
|
229
233
|
"\u5355\u4EFD XLSX \u6570\u636E\u8D85\u8FC7\u5B89\u5168\u9650\u5236\uFF0C\u8BF7\u4F7F\u7528 exportTableToXlsx \u81EA\u52A8\u5206\u6587\u4EF6\u5BFC\u51FA"
|
|
230
234
|
);
|
|
231
|
-
const header = columns.map((column) => column.title);
|
|
232
|
-
|
|
235
|
+
const header = params.headerRows?.length ? params.headerRows : [columns.map((column) => column.title)];
|
|
236
|
+
const headerRowCount = header.length;
|
|
237
|
+
const merges = (params.merges ?? []).flatMap((merge) => {
|
|
238
|
+
if (merge.e.r < headerRowCount) return [merge];
|
|
239
|
+
const start = Math.max(merge.s.r, headerRowCount + rangeStart);
|
|
240
|
+
const end = Math.min(merge.e.r, headerRowCount + rangeEnd - 1);
|
|
241
|
+
return end < start || end === start && merge.s.c === merge.e.c ? [] : [
|
|
242
|
+
{
|
|
243
|
+
s: { r: start - rangeStart, c: merge.s.c },
|
|
244
|
+
e: { r: end - rangeStart, c: merge.e.c }
|
|
245
|
+
}
|
|
246
|
+
];
|
|
247
|
+
});
|
|
248
|
+
if (header.some((row) => row.length > columns.length))
|
|
249
|
+
throw new Error("XLSX \u8868\u5934\u5355\u5143\u683C\u6570\u4E0D\u80FD\u8D85\u8FC7\u5BFC\u51FA\u5217\u6570");
|
|
250
|
+
let textSize = header.flat().reduce((size, title) => size + title.length, 0);
|
|
233
251
|
const normalizeExportCell = (value) => {
|
|
234
252
|
const cell = normalizeCell(value);
|
|
235
253
|
if (typeof cell === "string") {
|
|
@@ -243,7 +261,7 @@ async function buildXlsxPart(params, rangeStart, rangeEnd) {
|
|
|
243
261
|
}
|
|
244
262
|
return cell;
|
|
245
263
|
};
|
|
246
|
-
header.forEach((title) => {
|
|
264
|
+
header.flat().forEach((title) => {
|
|
247
265
|
if (title.length > 32767) throw new Error("XLSX \u8868\u5934\u8D85\u8FC7 32767 \u5B57\u7B26");
|
|
248
266
|
});
|
|
249
267
|
if (textSize > XLSX_MAX_TEXT_CHARS_PER_FILE)
|
|
@@ -295,7 +313,7 @@ async function buildXlsxPart(params, rangeStart, rangeEnd) {
|
|
|
295
313
|
() => fail(new Error("XLSX Worker \u542F\u52A8\u8D85\u65F6")),
|
|
296
314
|
1e4
|
|
297
315
|
);
|
|
298
|
-
await request({ type: "init", header, sheetName });
|
|
316
|
+
await request({ type: "init", header, sheetName, merges });
|
|
299
317
|
} catch {
|
|
300
318
|
worker?.terminate();
|
|
301
319
|
worker = void 0;
|
|
@@ -305,7 +323,7 @@ async function buildXlsxPart(params, rangeStart, rangeEnd) {
|
|
|
305
323
|
}
|
|
306
324
|
}
|
|
307
325
|
checkAbort();
|
|
308
|
-
const writer = worker ? void 0 : createXlsxWriter(XLSX__namespace, header, sheetName);
|
|
326
|
+
const writer = worker ? void 0 : createXlsxWriter(XLSX__namespace, header, sheetName, void 0, merges);
|
|
309
327
|
const totalRows = rangeEnd - rangeStart;
|
|
310
328
|
const report = (phase, completedRows) => params.onProgress?.({
|
|
311
329
|
phase,
|
|
@@ -436,7 +454,7 @@ function getXlsxRowsPerFile(params) {
|
|
|
436
454
|
throw new Error("XLSX \u5206\u6587\u4EF6\u4E0A\u9650\u5FC5\u987B\u4E3A\u6B63\u6574\u6570");
|
|
437
455
|
const byCells = Math.floor(
|
|
438
456
|
Math.min(cellLimit, XLSX_MAX_CELLS_PER_FILE) / Math.max(1, params.columns.length)
|
|
439
|
-
) - 1;
|
|
457
|
+
) - (params.headerRows?.length || 1);
|
|
440
458
|
if (byCells < 1) throw new Error("XLSX \u5355\u5143\u683C\u9884\u7B97\u4E0D\u8DB3\u4EE5\u5BB9\u7EB3\u8868\u5934\u548C\u4E00\u884C\u6570\u636E");
|
|
441
459
|
return Math.min(rowLimit, XLSX_MAX_ROWS_PER_FILE, byCells);
|
|
442
460
|
}
|
|
@@ -458,7 +476,8 @@ function buildCsvContent(params) {
|
|
|
458
476
|
columns.map((column) => column.title),
|
|
459
477
|
...rows.map(
|
|
460
478
|
(row, rowIndex) => columns.map((column) => column.value(row, rowIndex))
|
|
461
|
-
)
|
|
479
|
+
),
|
|
480
|
+
...params.footerRows ?? []
|
|
462
481
|
]);
|
|
463
482
|
}
|
|
464
483
|
function serializeCsvRows(rows, lineBreak = "\n") {
|
|
@@ -470,7 +489,13 @@ function buildTxtContent(params) {
|
|
|
470
489
|
const body = rows.map(
|
|
471
490
|
(row, rowIndex) => columns.map((column) => normalizeTextCell(column.value(row, rowIndex))).join(" ")
|
|
472
491
|
);
|
|
473
|
-
return [
|
|
492
|
+
return [
|
|
493
|
+
header,
|
|
494
|
+
...body,
|
|
495
|
+
...(params.footerRows ?? []).map(
|
|
496
|
+
(row) => row.map(normalizeTextCell).join(" ")
|
|
497
|
+
)
|
|
498
|
+
].join("\n");
|
|
474
499
|
}
|
|
475
500
|
async function downloadJsonFile(params) {
|
|
476
501
|
const { data, fileName, space = 2 } = params;
|
|
@@ -482,8 +507,8 @@ async function downloadJsonFile(params) {
|
|
|
482
507
|
});
|
|
483
508
|
}
|
|
484
509
|
async function exportTableToCsv(params) {
|
|
485
|
-
const { fileName, rows, columns } = params;
|
|
486
|
-
const content = await buildCsvContentAsync({ rows, columns });
|
|
510
|
+
const { fileName, rows, columns, footerRows } = params;
|
|
511
|
+
const content = await buildCsvContentAsync({ rows, columns, footerRows });
|
|
487
512
|
downloadTextFile({
|
|
488
513
|
fileName: ensureExtension(fileName, "csv"),
|
|
489
514
|
content,
|
|
@@ -491,8 +516,8 @@ async function exportTableToCsv(params) {
|
|
|
491
516
|
});
|
|
492
517
|
}
|
|
493
518
|
async function exportTableToTxt(params) {
|
|
494
|
-
const { fileName, rows, columns } = params;
|
|
495
|
-
const content = await buildTxtContentAsync({ rows, columns });
|
|
519
|
+
const { fileName, rows, columns, footerRows } = params;
|
|
520
|
+
const content = await buildTxtContentAsync({ rows, columns, footerRows });
|
|
496
521
|
downloadTextFile({
|
|
497
522
|
fileName: ensureExtension(fileName, "txt"),
|
|
498
523
|
content,
|
|
@@ -536,6 +561,9 @@ async function buildCsvContentAsync(params) {
|
|
|
536
561
|
}
|
|
537
562
|
await yieldToMainThread();
|
|
538
563
|
}
|
|
564
|
+
for (const footer of params.footerRows ?? []) {
|
|
565
|
+
parts.push("\n", footer.map(escapeCsvCell).join(","));
|
|
566
|
+
}
|
|
539
567
|
return parts.join("");
|
|
540
568
|
}
|
|
541
569
|
async function buildTxtContentAsync(params) {
|
|
@@ -551,6 +579,9 @@ async function buildTxtContentAsync(params) {
|
|
|
551
579
|
}
|
|
552
580
|
await yieldToMainThread();
|
|
553
581
|
}
|
|
582
|
+
for (const footer of params.footerRows ?? []) {
|
|
583
|
+
parts.push("\n", footer.map(normalizeTextCell).join(" "));
|
|
584
|
+
}
|
|
554
585
|
return parts.join("");
|
|
555
586
|
}
|
|
556
587
|
function escapeCsvCell(value) {
|
|
@@ -779,16 +810,29 @@ function isPointInRect(x, y, rect) {
|
|
|
779
810
|
function resolveCanvasScrollbarAxis(options, axis) {
|
|
780
811
|
const override = options?.[axis];
|
|
781
812
|
const merged = { ...options, ...override };
|
|
782
|
-
const
|
|
813
|
+
const axisSize = axis === "vertical" ? merged.width : merged.height;
|
|
814
|
+
const requestedThickness = axisSize ?? merged.thickness;
|
|
815
|
+
const thickness = Number.isFinite(requestedThickness) ? Math.max(requestedThickness, 6) : 10;
|
|
783
816
|
return {
|
|
817
|
+
mode: merged.mode === "button" ? "button" : "scrollbar",
|
|
784
818
|
visible: options?.visible !== false && override !== false && merged.visible !== false,
|
|
785
819
|
thickness,
|
|
820
|
+
maxScrollSpeed: Number.isFinite(merged.maxScrollSpeed) && merged.maxScrollSpeed > 0 ? merged.maxScrollSpeed : 1800,
|
|
786
821
|
thumbColor: merged.thumbColor ?? "rgba(100, 116, 139, 0.8)",
|
|
787
822
|
trackColor: merged.trackColor,
|
|
788
823
|
buttonColor: merged.buttonColor ?? "rgba(71, 85, 105, 0.88)",
|
|
824
|
+
buttonBackgroundColor: merged.buttonBackgroundColor,
|
|
825
|
+
buttonHoverBackgroundColor: merged.buttonHoverBackgroundColor ?? "rgba(71, 85, 105, 0.09)",
|
|
826
|
+
buttonPressedBackgroundColor: merged.buttonPressedBackgroundColor ?? "rgba(37, 99, 235, 0.18)",
|
|
789
827
|
thumbRadius: Number.isFinite(merged.thumbRadius) ? Math.max(merged.thumbRadius, 0) : void 0
|
|
790
828
|
};
|
|
791
829
|
}
|
|
830
|
+
function resolveCanvasScrollbarHoldSpeed(elapsedMs, maxScrollSpeed) {
|
|
831
|
+
const maximum = Math.max(maxScrollSpeed, 1);
|
|
832
|
+
const initial = Math.min(240, maximum);
|
|
833
|
+
const progress = Math.min(Math.max(elapsedMs, 0) / 2500, 1);
|
|
834
|
+
return initial + (maximum - initial) * progress * progress;
|
|
835
|
+
}
|
|
792
836
|
|
|
793
837
|
// src/number/precise.ts
|
|
794
838
|
function addPreciseNumbers(left, right) {
|
|
@@ -1202,6 +1246,7 @@ exports.normalizeDecimalPlaces = normalizeDecimalPlaces;
|
|
|
1202
1246
|
exports.parseChineseNumber = parseChineseNumber;
|
|
1203
1247
|
exports.parseNumberValue = parseNumberValue;
|
|
1204
1248
|
exports.resolveCanvasScrollbarAxis = resolveCanvasScrollbarAxis;
|
|
1249
|
+
exports.resolveCanvasScrollbarHoldSpeed = resolveCanvasScrollbarHoldSpeed;
|
|
1205
1250
|
exports.resolveDateValue = resolveDateValue;
|
|
1206
1251
|
exports.roundPreciseNumber = roundPreciseNumber;
|
|
1207
1252
|
exports.serializeCsvRows = serializeCsvRows;
|