@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.d.cts
CHANGED
|
@@ -4,19 +4,75 @@ export { ValueDataIndex, getValueByDataIndex, isSameDataIndex, stringifyDataInde
|
|
|
4
4
|
export { formatDateTimeValue, isDateTimeFormatPattern, resolveDateValue } from './date/index.cjs';
|
|
5
5
|
export { clamp, isPointInRect } from './geometry/index.cjs';
|
|
6
6
|
export { ChineseNumberStyle, NumberFormatOptions, PreciseNumberInput, PreciseRoundingMode, addPreciseNumbers, comparePreciseNumbers, dividePreciseNumber, formatChineseNumber, formatCustomNumberPattern, formatNumberValue, formatPercentValue, formatPreciseNumber, formatScientificValue, normalizeDecimalPlaces, parseChineseNumber, parseNumberValue, roundPreciseNumber, sumPreciseNumbers } from './number/index.cjs';
|
|
7
|
+
import 'xlsx';
|
|
8
|
+
|
|
9
|
+
/** 表格导出支持的汇总方式,title 保留来源汇总标题。 */
|
|
10
|
+
type TableExportSummaryType = "none" | "title" | "sum" | "avg" | "count" | "unionCount" | "rowCount" | "mergedRowCount" | "min" | "max" | "original";
|
|
11
|
+
/** 列表与透视表共用的导出汇总展示配置。 */
|
|
12
|
+
interface TableExportSummarySettings {
|
|
13
|
+
type: TableExportSummaryType;
|
|
14
|
+
showTypePrefix: boolean;
|
|
15
|
+
precision?: number;
|
|
16
|
+
roundingMode: "round" | "floor" | "ceil" | "truncate";
|
|
17
|
+
preserveTrailingZeros: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** 仅作用于本次导出,不修改来源表格。 */
|
|
20
|
+
interface TableExportSettings {
|
|
21
|
+
columnKeys: string[];
|
|
22
|
+
sortState: Array<{
|
|
23
|
+
key: string;
|
|
24
|
+
order: "ascend" | "descend";
|
|
25
|
+
priority?: number;
|
|
26
|
+
}>;
|
|
27
|
+
summaries: Record<string, TableExportSummarySettings>;
|
|
28
|
+
includeSummary: boolean;
|
|
29
|
+
}
|
|
30
|
+
/** 导出配置表的一行,隐藏列默认不勾选。 */
|
|
31
|
+
interface TableExportColumnChoice {
|
|
32
|
+
key: string;
|
|
33
|
+
title: string;
|
|
34
|
+
selected?: boolean;
|
|
35
|
+
sortOrder: "default" | "ascend" | "descend";
|
|
36
|
+
sortIndex?: number;
|
|
37
|
+
sortPriority?: number;
|
|
38
|
+
summary: TableExportSummarySettings;
|
|
39
|
+
summaryTitle?: string;
|
|
40
|
+
}
|
|
41
|
+
/** 框架无关的导出弹窗请求。 */
|
|
42
|
+
interface TableExportNameRequest {
|
|
43
|
+
fileName: string;
|
|
44
|
+
columns?: TableExportColumnChoice[];
|
|
45
|
+
includeSummary?: boolean;
|
|
46
|
+
onConfirm: (fileName: string, settings?: TableExportSettings) => void;
|
|
47
|
+
onCancel: () => void;
|
|
48
|
+
}
|
|
7
49
|
|
|
8
50
|
/** 单轴 Canvas 滚动条样式。尺寸单位均为 CSS 像素。 */
|
|
9
51
|
interface CanvasScrollbarAxisOptions {
|
|
52
|
+
/** scrollbar 为现有滑块模式;button 为两个各占半轴的画布按钮。 */
|
|
53
|
+
mode?: "scrollbar" | "button";
|
|
10
54
|
/** 是否显示;隐藏不禁用滚轮或程序滚动。 */
|
|
11
55
|
visible?: boolean;
|
|
12
56
|
/** 横向高度 / 纵向宽度,默认 10,最小 6。 */
|
|
13
57
|
thickness?: number;
|
|
58
|
+
/** 纵向按钮栏宽度,优先于 thickness。 */
|
|
59
|
+
width?: number;
|
|
60
|
+
/** 横向按钮栏高度,优先于 thickness。 */
|
|
61
|
+
height?: number;
|
|
62
|
+
/** 按钮长按时的最大滚动速度,单位 CSS 像素/秒,默认 1800。 */
|
|
63
|
+
maxScrollSpeed?: number;
|
|
14
64
|
/** 滑块填充颜色。 */
|
|
15
65
|
thumbColor?: string;
|
|
16
66
|
/** 滚动槽背景颜色,不传时保持表格背景。 */
|
|
17
67
|
trackColor?: string;
|
|
18
68
|
/** 两端箭头颜色。 */
|
|
19
69
|
buttonColor?: string;
|
|
70
|
+
/** 两端按钮常态背景;不传时沿用滚动槽背景。 */
|
|
71
|
+
buttonBackgroundColor?: string;
|
|
72
|
+
/** 鼠标悬停按钮时的背景颜色。 */
|
|
73
|
+
buttonHoverBackgroundColor?: string;
|
|
74
|
+
/** 按下按钮时的背景颜色。 */
|
|
75
|
+
buttonPressedBackgroundColor?: string;
|
|
20
76
|
/** 滑块圆角;不传时保持胶囊形状。 */
|
|
21
77
|
thumbRadius?: number;
|
|
22
78
|
}
|
|
@@ -27,12 +83,19 @@ interface CanvasScrollbarOptions extends CanvasScrollbarAxisOptions {
|
|
|
27
83
|
}
|
|
28
84
|
/** 合并通用与单轴配置,并归一化无效尺寸。 */
|
|
29
85
|
declare function resolveCanvasScrollbarAxis(options: CanvasScrollbarOptions | undefined, axis: "horizontal" | "vertical"): {
|
|
86
|
+
mode: string;
|
|
30
87
|
visible: boolean;
|
|
31
88
|
thickness: number;
|
|
89
|
+
maxScrollSpeed: number;
|
|
32
90
|
thumbColor: string;
|
|
33
91
|
trackColor: string | undefined;
|
|
34
92
|
buttonColor: string;
|
|
93
|
+
buttonBackgroundColor: string | undefined;
|
|
94
|
+
buttonHoverBackgroundColor: string;
|
|
95
|
+
buttonPressedBackgroundColor: string;
|
|
35
96
|
thumbRadius: number | undefined;
|
|
36
97
|
};
|
|
98
|
+
/** 长按按钮时逐渐加速,2.5 秒达到配置上限。 */
|
|
99
|
+
declare function resolveCanvasScrollbarHoldSpeed(elapsedMs: number, maxScrollSpeed: number): number;
|
|
37
100
|
|
|
38
|
-
export { type CanvasScrollbarAxisOptions, type CanvasScrollbarOptions, resolveCanvasScrollbarAxis };
|
|
101
|
+
export { type CanvasScrollbarAxisOptions, type CanvasScrollbarOptions, type TableExportColumnChoice, type TableExportNameRequest, type TableExportSettings, type TableExportSummarySettings, type TableExportSummaryType, resolveCanvasScrollbarAxis, resolveCanvasScrollbarHoldSpeed };
|
package/dist/index.d.ts
CHANGED
|
@@ -4,19 +4,75 @@ export { ValueDataIndex, getValueByDataIndex, isSameDataIndex, stringifyDataInde
|
|
|
4
4
|
export { formatDateTimeValue, isDateTimeFormatPattern, resolveDateValue } from './date/index.js';
|
|
5
5
|
export { clamp, isPointInRect } from './geometry/index.js';
|
|
6
6
|
export { ChineseNumberStyle, NumberFormatOptions, PreciseNumberInput, PreciseRoundingMode, addPreciseNumbers, comparePreciseNumbers, dividePreciseNumber, formatChineseNumber, formatCustomNumberPattern, formatNumberValue, formatPercentValue, formatPreciseNumber, formatScientificValue, normalizeDecimalPlaces, parseChineseNumber, parseNumberValue, roundPreciseNumber, sumPreciseNumbers } from './number/index.js';
|
|
7
|
+
import 'xlsx';
|
|
8
|
+
|
|
9
|
+
/** 表格导出支持的汇总方式,title 保留来源汇总标题。 */
|
|
10
|
+
type TableExportSummaryType = "none" | "title" | "sum" | "avg" | "count" | "unionCount" | "rowCount" | "mergedRowCount" | "min" | "max" | "original";
|
|
11
|
+
/** 列表与透视表共用的导出汇总展示配置。 */
|
|
12
|
+
interface TableExportSummarySettings {
|
|
13
|
+
type: TableExportSummaryType;
|
|
14
|
+
showTypePrefix: boolean;
|
|
15
|
+
precision?: number;
|
|
16
|
+
roundingMode: "round" | "floor" | "ceil" | "truncate";
|
|
17
|
+
preserveTrailingZeros: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** 仅作用于本次导出,不修改来源表格。 */
|
|
20
|
+
interface TableExportSettings {
|
|
21
|
+
columnKeys: string[];
|
|
22
|
+
sortState: Array<{
|
|
23
|
+
key: string;
|
|
24
|
+
order: "ascend" | "descend";
|
|
25
|
+
priority?: number;
|
|
26
|
+
}>;
|
|
27
|
+
summaries: Record<string, TableExportSummarySettings>;
|
|
28
|
+
includeSummary: boolean;
|
|
29
|
+
}
|
|
30
|
+
/** 导出配置表的一行,隐藏列默认不勾选。 */
|
|
31
|
+
interface TableExportColumnChoice {
|
|
32
|
+
key: string;
|
|
33
|
+
title: string;
|
|
34
|
+
selected?: boolean;
|
|
35
|
+
sortOrder: "default" | "ascend" | "descend";
|
|
36
|
+
sortIndex?: number;
|
|
37
|
+
sortPriority?: number;
|
|
38
|
+
summary: TableExportSummarySettings;
|
|
39
|
+
summaryTitle?: string;
|
|
40
|
+
}
|
|
41
|
+
/** 框架无关的导出弹窗请求。 */
|
|
42
|
+
interface TableExportNameRequest {
|
|
43
|
+
fileName: string;
|
|
44
|
+
columns?: TableExportColumnChoice[];
|
|
45
|
+
includeSummary?: boolean;
|
|
46
|
+
onConfirm: (fileName: string, settings?: TableExportSettings) => void;
|
|
47
|
+
onCancel: () => void;
|
|
48
|
+
}
|
|
7
49
|
|
|
8
50
|
/** 单轴 Canvas 滚动条样式。尺寸单位均为 CSS 像素。 */
|
|
9
51
|
interface CanvasScrollbarAxisOptions {
|
|
52
|
+
/** scrollbar 为现有滑块模式;button 为两个各占半轴的画布按钮。 */
|
|
53
|
+
mode?: "scrollbar" | "button";
|
|
10
54
|
/** 是否显示;隐藏不禁用滚轮或程序滚动。 */
|
|
11
55
|
visible?: boolean;
|
|
12
56
|
/** 横向高度 / 纵向宽度,默认 10,最小 6。 */
|
|
13
57
|
thickness?: number;
|
|
58
|
+
/** 纵向按钮栏宽度,优先于 thickness。 */
|
|
59
|
+
width?: number;
|
|
60
|
+
/** 横向按钮栏高度,优先于 thickness。 */
|
|
61
|
+
height?: number;
|
|
62
|
+
/** 按钮长按时的最大滚动速度,单位 CSS 像素/秒,默认 1800。 */
|
|
63
|
+
maxScrollSpeed?: number;
|
|
14
64
|
/** 滑块填充颜色。 */
|
|
15
65
|
thumbColor?: string;
|
|
16
66
|
/** 滚动槽背景颜色,不传时保持表格背景。 */
|
|
17
67
|
trackColor?: string;
|
|
18
68
|
/** 两端箭头颜色。 */
|
|
19
69
|
buttonColor?: string;
|
|
70
|
+
/** 两端按钮常态背景;不传时沿用滚动槽背景。 */
|
|
71
|
+
buttonBackgroundColor?: string;
|
|
72
|
+
/** 鼠标悬停按钮时的背景颜色。 */
|
|
73
|
+
buttonHoverBackgroundColor?: string;
|
|
74
|
+
/** 按下按钮时的背景颜色。 */
|
|
75
|
+
buttonPressedBackgroundColor?: string;
|
|
20
76
|
/** 滑块圆角;不传时保持胶囊形状。 */
|
|
21
77
|
thumbRadius?: number;
|
|
22
78
|
}
|
|
@@ -27,12 +83,19 @@ interface CanvasScrollbarOptions extends CanvasScrollbarAxisOptions {
|
|
|
27
83
|
}
|
|
28
84
|
/** 合并通用与单轴配置,并归一化无效尺寸。 */
|
|
29
85
|
declare function resolveCanvasScrollbarAxis(options: CanvasScrollbarOptions | undefined, axis: "horizontal" | "vertical"): {
|
|
86
|
+
mode: string;
|
|
30
87
|
visible: boolean;
|
|
31
88
|
thickness: number;
|
|
89
|
+
maxScrollSpeed: number;
|
|
32
90
|
thumbColor: string;
|
|
33
91
|
trackColor: string | undefined;
|
|
34
92
|
buttonColor: string;
|
|
93
|
+
buttonBackgroundColor: string | undefined;
|
|
94
|
+
buttonHoverBackgroundColor: string;
|
|
95
|
+
buttonPressedBackgroundColor: string;
|
|
35
96
|
thumbRadius: number | undefined;
|
|
36
97
|
};
|
|
98
|
+
/** 长按按钮时逐渐加速,2.5 秒达到配置上限。 */
|
|
99
|
+
declare function resolveCanvasScrollbarHoldSpeed(elapsedMs: number, maxScrollSpeed: number): number;
|
|
37
100
|
|
|
38
|
-
export { type CanvasScrollbarAxisOptions, type CanvasScrollbarOptions, resolveCanvasScrollbarAxis };
|
|
101
|
+
export { type CanvasScrollbarAxisOptions, type CanvasScrollbarOptions, type TableExportColumnChoice, type TableExportNameRequest, type TableExportSettings, type TableExportSummarySettings, type TableExportSummaryType, resolveCanvasScrollbarAxis, resolveCanvasScrollbarHoldSpeed };
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,10 @@ var __export = (target, all) => {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
// src/export/xlsx-runtime.ts
|
|
14
|
-
function createXlsxWriter(xlsx, header, sheetName, maxRows = 1048576) {
|
|
14
|
+
function createXlsxWriter(xlsx, header, sheetName, maxRows = 1048576, merges = []) {
|
|
15
|
+
const headerRows = Array.isArray(header[0]) ? header : [header];
|
|
16
|
+
if (headerRows.length >= maxRows)
|
|
17
|
+
throw new Error("XLSX \u8868\u5934\u884C\u6570\u8D85\u8FC7\u5DE5\u4F5C\u8868\u5BB9\u91CF");
|
|
15
18
|
const workbook = xlsx.utils.book_new();
|
|
16
19
|
let worksheet;
|
|
17
20
|
let rowCount = 0;
|
|
@@ -19,7 +22,7 @@ function createXlsxWriter(xlsx, header, sheetName, maxRows = 1048576) {
|
|
|
19
22
|
const baseName = sheetName.replace(/[\\/?*[\]:]/g, "_").replace(/^'+|'+$/g, "") || "Sheet1";
|
|
20
23
|
const addSheet = () => {
|
|
21
24
|
const suffix = sheetIndex === 0 ? "" : `_${sheetIndex + 1}`;
|
|
22
|
-
worksheet = xlsx.utils.aoa_to_sheet(
|
|
25
|
+
worksheet = xlsx.utils.aoa_to_sheet(headerRows, {
|
|
23
26
|
dense: true
|
|
24
27
|
});
|
|
25
28
|
xlsx.utils.book_append_sheet(
|
|
@@ -27,7 +30,8 @@ function createXlsxWriter(xlsx, header, sheetName, maxRows = 1048576) {
|
|
|
27
30
|
worksheet,
|
|
28
31
|
baseName.slice(0, 31 - suffix.length) + suffix
|
|
29
32
|
);
|
|
30
|
-
|
|
33
|
+
if (merges.length && sheetIndex === 0) worksheet["!merges"] = merges;
|
|
34
|
+
rowCount = headerRows.length;
|
|
31
35
|
sheetIndex += 1;
|
|
32
36
|
};
|
|
33
37
|
addSheet();
|
|
@@ -103,7 +107,7 @@ let writer;
|
|
|
103
107
|
self.onmessage = function(event) {
|
|
104
108
|
try {
|
|
105
109
|
const message = event.data;
|
|
106
|
-
if (message.type === 'init') writer = createWriter(XLSX, message.header, message.sheetName);
|
|
110
|
+
if (message.type === 'init') writer = createWriter(XLSX, message.header, message.sheetName, undefined, message.merges);
|
|
107
111
|
else if (message.type === 'append') writer.append(message.rows);
|
|
108
112
|
else if (message.type === 'finish') {
|
|
109
113
|
const buffer = writer.finish();
|
|
@@ -206,8 +210,22 @@ async function buildXlsxPart(params, rangeStart, rangeEnd) {
|
|
|
206
210
|
throw new Error(
|
|
207
211
|
"\u5355\u4EFD XLSX \u6570\u636E\u8D85\u8FC7\u5B89\u5168\u9650\u5236\uFF0C\u8BF7\u4F7F\u7528 exportTableToXlsx \u81EA\u52A8\u5206\u6587\u4EF6\u5BFC\u51FA"
|
|
208
212
|
);
|
|
209
|
-
const header = columns.map((column) => column.title);
|
|
210
|
-
|
|
213
|
+
const header = params.headerRows?.length ? params.headerRows : [columns.map((column) => column.title)];
|
|
214
|
+
const headerRowCount = header.length;
|
|
215
|
+
const merges = (params.merges ?? []).flatMap((merge) => {
|
|
216
|
+
if (merge.e.r < headerRowCount) return [merge];
|
|
217
|
+
const start = Math.max(merge.s.r, headerRowCount + rangeStart);
|
|
218
|
+
const end = Math.min(merge.e.r, headerRowCount + rangeEnd - 1);
|
|
219
|
+
return end < start || end === start && merge.s.c === merge.e.c ? [] : [
|
|
220
|
+
{
|
|
221
|
+
s: { r: start - rangeStart, c: merge.s.c },
|
|
222
|
+
e: { r: end - rangeStart, c: merge.e.c }
|
|
223
|
+
}
|
|
224
|
+
];
|
|
225
|
+
});
|
|
226
|
+
if (header.some((row) => row.length > columns.length))
|
|
227
|
+
throw new Error("XLSX \u8868\u5934\u5355\u5143\u683C\u6570\u4E0D\u80FD\u8D85\u8FC7\u5BFC\u51FA\u5217\u6570");
|
|
228
|
+
let textSize = header.flat().reduce((size, title) => size + title.length, 0);
|
|
211
229
|
const normalizeExportCell = (value) => {
|
|
212
230
|
const cell = normalizeCell(value);
|
|
213
231
|
if (typeof cell === "string") {
|
|
@@ -221,7 +239,7 @@ async function buildXlsxPart(params, rangeStart, rangeEnd) {
|
|
|
221
239
|
}
|
|
222
240
|
return cell;
|
|
223
241
|
};
|
|
224
|
-
header.forEach((title) => {
|
|
242
|
+
header.flat().forEach((title) => {
|
|
225
243
|
if (title.length > 32767) throw new Error("XLSX \u8868\u5934\u8D85\u8FC7 32767 \u5B57\u7B26");
|
|
226
244
|
});
|
|
227
245
|
if (textSize > XLSX_MAX_TEXT_CHARS_PER_FILE)
|
|
@@ -273,7 +291,7 @@ async function buildXlsxPart(params, rangeStart, rangeEnd) {
|
|
|
273
291
|
() => fail(new Error("XLSX Worker \u542F\u52A8\u8D85\u65F6")),
|
|
274
292
|
1e4
|
|
275
293
|
);
|
|
276
|
-
await request({ type: "init", header, sheetName });
|
|
294
|
+
await request({ type: "init", header, sheetName, merges });
|
|
277
295
|
} catch {
|
|
278
296
|
worker?.terminate();
|
|
279
297
|
worker = void 0;
|
|
@@ -283,7 +301,7 @@ async function buildXlsxPart(params, rangeStart, rangeEnd) {
|
|
|
283
301
|
}
|
|
284
302
|
}
|
|
285
303
|
checkAbort();
|
|
286
|
-
const writer = worker ? void 0 : createXlsxWriter(XLSX, header, sheetName);
|
|
304
|
+
const writer = worker ? void 0 : createXlsxWriter(XLSX, header, sheetName, void 0, merges);
|
|
287
305
|
const totalRows = rangeEnd - rangeStart;
|
|
288
306
|
const report = (phase, completedRows) => params.onProgress?.({
|
|
289
307
|
phase,
|
|
@@ -414,7 +432,7 @@ function getXlsxRowsPerFile(params) {
|
|
|
414
432
|
throw new Error("XLSX \u5206\u6587\u4EF6\u4E0A\u9650\u5FC5\u987B\u4E3A\u6B63\u6574\u6570");
|
|
415
433
|
const byCells = Math.floor(
|
|
416
434
|
Math.min(cellLimit, XLSX_MAX_CELLS_PER_FILE) / Math.max(1, params.columns.length)
|
|
417
|
-
) - 1;
|
|
435
|
+
) - (params.headerRows?.length || 1);
|
|
418
436
|
if (byCells < 1) throw new Error("XLSX \u5355\u5143\u683C\u9884\u7B97\u4E0D\u8DB3\u4EE5\u5BB9\u7EB3\u8868\u5934\u548C\u4E00\u884C\u6570\u636E");
|
|
419
437
|
return Math.min(rowLimit, XLSX_MAX_ROWS_PER_FILE, byCells);
|
|
420
438
|
}
|
|
@@ -436,7 +454,8 @@ function buildCsvContent(params) {
|
|
|
436
454
|
columns.map((column) => column.title),
|
|
437
455
|
...rows.map(
|
|
438
456
|
(row, rowIndex) => columns.map((column) => column.value(row, rowIndex))
|
|
439
|
-
)
|
|
457
|
+
),
|
|
458
|
+
...params.footerRows ?? []
|
|
440
459
|
]);
|
|
441
460
|
}
|
|
442
461
|
function serializeCsvRows(rows, lineBreak = "\n") {
|
|
@@ -448,7 +467,13 @@ function buildTxtContent(params) {
|
|
|
448
467
|
const body = rows.map(
|
|
449
468
|
(row, rowIndex) => columns.map((column) => normalizeTextCell(column.value(row, rowIndex))).join(" ")
|
|
450
469
|
);
|
|
451
|
-
return [
|
|
470
|
+
return [
|
|
471
|
+
header,
|
|
472
|
+
...body,
|
|
473
|
+
...(params.footerRows ?? []).map(
|
|
474
|
+
(row) => row.map(normalizeTextCell).join(" ")
|
|
475
|
+
)
|
|
476
|
+
].join("\n");
|
|
452
477
|
}
|
|
453
478
|
async function downloadJsonFile(params) {
|
|
454
479
|
const { data, fileName, space = 2 } = params;
|
|
@@ -460,8 +485,8 @@ async function downloadJsonFile(params) {
|
|
|
460
485
|
});
|
|
461
486
|
}
|
|
462
487
|
async function exportTableToCsv(params) {
|
|
463
|
-
const { fileName, rows, columns } = params;
|
|
464
|
-
const content = await buildCsvContentAsync({ rows, columns });
|
|
488
|
+
const { fileName, rows, columns, footerRows } = params;
|
|
489
|
+
const content = await buildCsvContentAsync({ rows, columns, footerRows });
|
|
465
490
|
downloadTextFile({
|
|
466
491
|
fileName: ensureExtension(fileName, "csv"),
|
|
467
492
|
content,
|
|
@@ -469,8 +494,8 @@ async function exportTableToCsv(params) {
|
|
|
469
494
|
});
|
|
470
495
|
}
|
|
471
496
|
async function exportTableToTxt(params) {
|
|
472
|
-
const { fileName, rows, columns } = params;
|
|
473
|
-
const content = await buildTxtContentAsync({ rows, columns });
|
|
497
|
+
const { fileName, rows, columns, footerRows } = params;
|
|
498
|
+
const content = await buildTxtContentAsync({ rows, columns, footerRows });
|
|
474
499
|
downloadTextFile({
|
|
475
500
|
fileName: ensureExtension(fileName, "txt"),
|
|
476
501
|
content,
|
|
@@ -514,6 +539,9 @@ async function buildCsvContentAsync(params) {
|
|
|
514
539
|
}
|
|
515
540
|
await yieldToMainThread();
|
|
516
541
|
}
|
|
542
|
+
for (const footer of params.footerRows ?? []) {
|
|
543
|
+
parts.push("\n", footer.map(escapeCsvCell).join(","));
|
|
544
|
+
}
|
|
517
545
|
return parts.join("");
|
|
518
546
|
}
|
|
519
547
|
async function buildTxtContentAsync(params) {
|
|
@@ -529,6 +557,9 @@ async function buildTxtContentAsync(params) {
|
|
|
529
557
|
}
|
|
530
558
|
await yieldToMainThread();
|
|
531
559
|
}
|
|
560
|
+
for (const footer of params.footerRows ?? []) {
|
|
561
|
+
parts.push("\n", footer.map(normalizeTextCell).join(" "));
|
|
562
|
+
}
|
|
532
563
|
return parts.join("");
|
|
533
564
|
}
|
|
534
565
|
function escapeCsvCell(value) {
|
|
@@ -757,16 +788,29 @@ function isPointInRect(x, y, rect) {
|
|
|
757
788
|
function resolveCanvasScrollbarAxis(options, axis) {
|
|
758
789
|
const override = options?.[axis];
|
|
759
790
|
const merged = { ...options, ...override };
|
|
760
|
-
const
|
|
791
|
+
const axisSize = axis === "vertical" ? merged.width : merged.height;
|
|
792
|
+
const requestedThickness = axisSize ?? merged.thickness;
|
|
793
|
+
const thickness = Number.isFinite(requestedThickness) ? Math.max(requestedThickness, 6) : 10;
|
|
761
794
|
return {
|
|
795
|
+
mode: merged.mode === "button" ? "button" : "scrollbar",
|
|
762
796
|
visible: options?.visible !== false && override !== false && merged.visible !== false,
|
|
763
797
|
thickness,
|
|
798
|
+
maxScrollSpeed: Number.isFinite(merged.maxScrollSpeed) && merged.maxScrollSpeed > 0 ? merged.maxScrollSpeed : 1800,
|
|
764
799
|
thumbColor: merged.thumbColor ?? "rgba(100, 116, 139, 0.8)",
|
|
765
800
|
trackColor: merged.trackColor,
|
|
766
801
|
buttonColor: merged.buttonColor ?? "rgba(71, 85, 105, 0.88)",
|
|
802
|
+
buttonBackgroundColor: merged.buttonBackgroundColor,
|
|
803
|
+
buttonHoverBackgroundColor: merged.buttonHoverBackgroundColor ?? "rgba(71, 85, 105, 0.09)",
|
|
804
|
+
buttonPressedBackgroundColor: merged.buttonPressedBackgroundColor ?? "rgba(37, 99, 235, 0.18)",
|
|
767
805
|
thumbRadius: Number.isFinite(merged.thumbRadius) ? Math.max(merged.thumbRadius, 0) : void 0
|
|
768
806
|
};
|
|
769
807
|
}
|
|
808
|
+
function resolveCanvasScrollbarHoldSpeed(elapsedMs, maxScrollSpeed) {
|
|
809
|
+
const maximum = Math.max(maxScrollSpeed, 1);
|
|
810
|
+
const initial = Math.min(240, maximum);
|
|
811
|
+
const progress = Math.min(Math.max(elapsedMs, 0) / 2500, 1);
|
|
812
|
+
return initial + (maximum - initial) * progress * progress;
|
|
813
|
+
}
|
|
770
814
|
|
|
771
815
|
// src/number/precise.ts
|
|
772
816
|
function addPreciseNumbers(left, right) {
|
|
@@ -1149,6 +1193,6 @@ function resolveThousandsSeparator(separator) {
|
|
|
1149
1193
|
return ",";
|
|
1150
1194
|
}
|
|
1151
1195
|
|
|
1152
|
-
export { addPreciseNumbers, buildCsvContent, buildTxtContent, clamp, comparePreciseNumbers, copyJson, copyRows, copyText, copyTextSync, dividePreciseNumber, downloadJsonFile, exportTableToCsv, exportTableToTxt, exportTableToXlsx, formatChineseNumber, formatCustomNumberPattern, formatDateTimeValue, formatNumberValue, formatPercentValue, formatPreciseNumber, formatRowsForClipboard, formatScientificValue, getValueByDataIndex, isDateTimeFormatPattern, isPointInRect, isSameDataIndex, mapRowsToExportRecords, normalizeDecimalPlaces, parseChineseNumber, parseNumberValue, resolveCanvasScrollbarAxis, resolveDateValue, roundPreciseNumber, serializeCsvRows, stringifyDataIndex, sumPreciseNumbers };
|
|
1196
|
+
export { addPreciseNumbers, buildCsvContent, buildTxtContent, clamp, comparePreciseNumbers, copyJson, copyRows, copyText, copyTextSync, dividePreciseNumber, downloadJsonFile, exportTableToCsv, exportTableToTxt, exportTableToXlsx, formatChineseNumber, formatCustomNumberPattern, formatDateTimeValue, formatNumberValue, formatPercentValue, formatPreciseNumber, formatRowsForClipboard, formatScientificValue, getValueByDataIndex, isDateTimeFormatPattern, isPointInRect, isSameDataIndex, mapRowsToExportRecords, normalizeDecimalPlaces, parseChineseNumber, parseNumberValue, resolveCanvasScrollbarAxis, resolveCanvasScrollbarHoldSpeed, resolveDateValue, roundPreciseNumber, serializeCsvRows, stringifyDataIndex, sumPreciseNumbers };
|
|
1153
1197
|
//# sourceMappingURL=index.js.map
|
|
1154
1198
|
//# sourceMappingURL=index.js.map
|