@canvas-components/utils 0.2.0 → 0.2.2
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 +141 -96
- package/dist/clipboard/index.cjs +8 -5
- package/dist/clipboard/index.cjs.map +1 -1
- package/dist/clipboard/index.d.cts +1 -1
- package/dist/clipboard/index.d.ts +1 -1
- package/dist/clipboard/index.js +8 -5
- package/dist/clipboard/index.js.map +1 -1
- package/dist/data/index.cjs +31 -0
- package/dist/data/index.cjs.map +1 -0
- package/dist/data/index.d.cts +22 -0
- package/dist/data/index.d.ts +22 -0
- package/dist/data/index.js +27 -0
- package/dist/data/index.js.map +1 -0
- package/dist/date/index.cjs +162 -0
- package/dist/date/index.cjs.map +1 -0
- package/dist/date/index.d.cts +13 -0
- package/dist/date/index.d.ts +13 -0
- package/dist/date/index.js +158 -0
- package/dist/date/index.js.map +1 -0
- package/dist/export/index.cjs +14 -12
- package/dist/export/index.cjs.map +1 -1
- package/dist/export/index.d.cts +5 -1
- package/dist/export/index.d.ts +5 -1
- package/dist/export/index.js +14 -13
- package/dist/export/index.js.map +1 -1
- package/dist/geometry/index.cjs +14 -0
- package/dist/geometry/index.cjs.map +1 -0
- package/dist/geometry/index.d.cts +15 -0
- package/dist/geometry/index.d.ts +15 -0
- package/dist/geometry/index.js +11 -0
- package/dist/geometry/index.js.map +1 -0
- package/dist/index.cjs +612 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +590 -18
- package/dist/index.js.map +1 -1
- package/dist/number/index.cjs +399 -0
- package/dist/number/index.cjs.map +1 -0
- package/dist/number/index.d.cts +44 -0
- package/dist/number/index.d.ts +44 -0
- package/dist/number/index.js +384 -0
- package/dist/number/index.js.map +1 -0
- package/package.json +21 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/date/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/** Day.js 风格日期时间格式中支持识别的 token。 */\nconst DATE_TIME_FORMAT_TOKEN =\n /Y{2,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|m{1,2}|s{1,2}|S{1,3}|A|a/;\n\nconst FORMAT_TOKEN =\n /\\[[^\\]]*\\]|YYYY|MMMM|MMM|dddd|ddd|SSS|YY|MM|DD|dd|HH|hh|mm|ss|SS|M|D|d|H|h|m|s|S|A|a/g;\n\nconst ZH_WEEKDAYS = [\n \"星期日\",\n \"星期一\",\n \"星期二\",\n \"星期三\",\n \"星期四\",\n \"星期五\",\n \"星期六\",\n];\nconst ZH_WEEKDAYS_SHORT = [\n \"周日\",\n \"周一\",\n \"周二\",\n \"周三\",\n \"周四\",\n \"周五\",\n \"周六\",\n];\nconst EN_WEEKDAYS = [\n \"Sunday\",\n \"Monday\",\n \"Tuesday\",\n \"Wednesday\",\n \"Thursday\",\n \"Friday\",\n \"Saturday\",\n];\nconst EN_MONTHS = [\n \"January\",\n \"February\",\n \"March\",\n \"April\",\n \"May\",\n \"June\",\n \"July\",\n \"August\",\n \"September\",\n \"October\",\n \"November\",\n \"December\",\n];\n\n/** 将未知值解析为有效日期。 */\nexport function resolveDateValue(value: unknown): Date | null {\n if (value instanceof Date) {\n return Number.isNaN(value.getTime()) ? null : value;\n }\n if (typeof value !== \"string\" && typeof value !== \"number\") {\n return null;\n }\n if (typeof value === \"string\") {\n const localDate = resolveLocalDateString(value);\n if (localDate) {\n return localDate;\n }\n }\n const resolved = new Date(value);\n return Number.isNaN(resolved.getTime()) ? null : resolved;\n}\n\n/** 判断字符串中是否包含 Day.js 风格的日期时间格式 token。 */\nexport function isDateTimeFormatPattern(pattern: string) {\n return DATE_TIME_FORMAT_TOKEN.test(pattern.replace(/\\[[^\\]]*\\]/g, \"\"));\n}\n\n/**\n * 使用 Day.js 风格的常用 token 格式化日期时间,不依赖 Day.js 运行时。\n *\n * 支持年、月、日、星期、24/12 小时、分、秒、毫秒和上下午标记;\n * 默认使用中文区域设置,值或 pattern 无效时返回 `null`。\n */\nexport function formatDateTimeValue(\n value: unknown,\n pattern: string,\n locale = \"zh-cn\",\n): string | null {\n const date = resolveDateValue(value);\n const normalizedPattern = pattern.trim();\n if (!date || !normalizedPattern) {\n return null;\n }\n const year = date.getFullYear();\n const monthIndex = date.getMonth();\n const month = monthIndex + 1;\n const day = date.getDate();\n const weekdayIndex = date.getDay();\n const hour = date.getHours();\n const hour12 = hour % 12 || 12;\n const minute = date.getMinutes();\n const second = date.getSeconds();\n const millisecond = date.getMilliseconds();\n const chinese = locale.toLowerCase().startsWith(\"zh\");\n const marker =\n hour >= 12 ? (chinese ? \"下午\" : \"PM\") : chinese ? \"上午\" : \"AM\";\n const weekday = chinese\n ? (ZH_WEEKDAYS[weekdayIndex] ?? \"\")\n : (EN_WEEKDAYS[weekdayIndex] ?? \"\");\n const weekdayShort = chinese\n ? (ZH_WEEKDAYS_SHORT[weekdayIndex] ?? \"\")\n : weekday.slice(0, 3);\n const monthName = chinese ? `${month}月` : (EN_MONTHS[monthIndex] ?? \"\");\n const values: Record<string, string> = {\n YYYY: String(year).padStart(4, \"0\"),\n YY: String(year).slice(-2),\n M: String(month),\n MM: padNumber(month),\n MMM: chinese ? monthName : monthName.slice(0, 3),\n MMMM: monthName,\n D: String(day),\n DD: padNumber(day),\n d: String(weekdayIndex),\n dd: chinese ? weekdayShort.slice(-1) : weekday.slice(0, 2),\n ddd: weekdayShort,\n dddd: weekday,\n H: String(hour),\n HH: padNumber(hour),\n h: String(hour12),\n hh: padNumber(hour12),\n m: String(minute),\n mm: padNumber(minute),\n s: String(second),\n ss: padNumber(second),\n S: String(Math.floor(millisecond / 100)),\n SS: String(Math.floor(millisecond / 10)).padStart(2, \"0\"),\n SSS: String(millisecond).padStart(3, \"0\"),\n A: marker,\n a: marker.toLowerCase(),\n };\n\n return normalizedPattern.replace(FORMAT_TOKEN, (token) =>\n token.startsWith(\"[\") && token.endsWith(\"]\")\n ? token.slice(1, -1)\n : (values[token] ?? token),\n );\n}\n\nfunction padNumber(value: number) {\n return String(value).padStart(2, \"0\");\n}\n\nfunction resolveLocalDateString(value: string) {\n const match = value\n .trim()\n .match(\n /^(\\d{4})[-/](\\d{1,2})[-/](\\d{1,2})(?:[ T](\\d{1,2}):?(\\d{2})?(?::?(\\d{2}))?(?:\\.(\\d{1,3}))?)?$/,\n );\n if (!match) {\n return null;\n }\n const [\n ,\n yearText,\n monthText,\n dayText,\n hourText,\n minuteText,\n secondText,\n millisecondText,\n ] = match;\n const year = Number(yearText);\n const monthIndex = Number(monthText) - 1;\n const day = Number(dayText);\n const hour = Number(hourText ?? 0);\n const minute = Number(minuteText ?? 0);\n const second = Number(secondText ?? 0);\n const millisecond = Number((millisecondText ?? \"0\").padEnd(3, \"0\"));\n const resolved = new Date(\n year,\n monthIndex,\n day,\n hour,\n minute,\n second,\n millisecond,\n );\n return resolved.getFullYear() === year &&\n resolved.getMonth() === monthIndex &&\n resolved.getDate() === day &&\n resolved.getHours() === hour &&\n resolved.getMinutes() === minute &&\n resolved.getSeconds() === second\n ? resolved\n : null;\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** 将未知值解析为有效日期。 */
|
|
2
|
+
declare function resolveDateValue(value: unknown): Date | null;
|
|
3
|
+
/** 判断字符串中是否包含 Day.js 风格的日期时间格式 token。 */
|
|
4
|
+
declare function isDateTimeFormatPattern(pattern: string): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* 使用 Day.js 风格的常用 token 格式化日期时间,不依赖 Day.js 运行时。
|
|
7
|
+
*
|
|
8
|
+
* 支持年、月、日、星期、24/12 小时、分、秒、毫秒和上下午标记;
|
|
9
|
+
* 默认使用中文区域设置,值或 pattern 无效时返回 `null`。
|
|
10
|
+
*/
|
|
11
|
+
declare function formatDateTimeValue(value: unknown, pattern: string, locale?: string): string | null;
|
|
12
|
+
|
|
13
|
+
export { formatDateTimeValue, isDateTimeFormatPattern, resolveDateValue };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** 将未知值解析为有效日期。 */
|
|
2
|
+
declare function resolveDateValue(value: unknown): Date | null;
|
|
3
|
+
/** 判断字符串中是否包含 Day.js 风格的日期时间格式 token。 */
|
|
4
|
+
declare function isDateTimeFormatPattern(pattern: string): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* 使用 Day.js 风格的常用 token 格式化日期时间,不依赖 Day.js 运行时。
|
|
7
|
+
*
|
|
8
|
+
* 支持年、月、日、星期、24/12 小时、分、秒、毫秒和上下午标记;
|
|
9
|
+
* 默认使用中文区域设置,值或 pattern 无效时返回 `null`。
|
|
10
|
+
*/
|
|
11
|
+
declare function formatDateTimeValue(value: unknown, pattern: string, locale?: string): string | null;
|
|
12
|
+
|
|
13
|
+
export { formatDateTimeValue, isDateTimeFormatPattern, resolveDateValue };
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// src/date/index.ts
|
|
2
|
+
var DATE_TIME_FORMAT_TOKEN = /Y{2,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|m{1,2}|s{1,2}|S{1,3}|A|a/;
|
|
3
|
+
var FORMAT_TOKEN = /\[[^\]]*\]|YYYY|MMMM|MMM|dddd|ddd|SSS|YY|MM|DD|dd|HH|hh|mm|ss|SS|M|D|d|H|h|m|s|S|A|a/g;
|
|
4
|
+
var ZH_WEEKDAYS = [
|
|
5
|
+
"\u661F\u671F\u65E5",
|
|
6
|
+
"\u661F\u671F\u4E00",
|
|
7
|
+
"\u661F\u671F\u4E8C",
|
|
8
|
+
"\u661F\u671F\u4E09",
|
|
9
|
+
"\u661F\u671F\u56DB",
|
|
10
|
+
"\u661F\u671F\u4E94",
|
|
11
|
+
"\u661F\u671F\u516D"
|
|
12
|
+
];
|
|
13
|
+
var ZH_WEEKDAYS_SHORT = [
|
|
14
|
+
"\u5468\u65E5",
|
|
15
|
+
"\u5468\u4E00",
|
|
16
|
+
"\u5468\u4E8C",
|
|
17
|
+
"\u5468\u4E09",
|
|
18
|
+
"\u5468\u56DB",
|
|
19
|
+
"\u5468\u4E94",
|
|
20
|
+
"\u5468\u516D"
|
|
21
|
+
];
|
|
22
|
+
var EN_WEEKDAYS = [
|
|
23
|
+
"Sunday",
|
|
24
|
+
"Monday",
|
|
25
|
+
"Tuesday",
|
|
26
|
+
"Wednesday",
|
|
27
|
+
"Thursday",
|
|
28
|
+
"Friday",
|
|
29
|
+
"Saturday"
|
|
30
|
+
];
|
|
31
|
+
var EN_MONTHS = [
|
|
32
|
+
"January",
|
|
33
|
+
"February",
|
|
34
|
+
"March",
|
|
35
|
+
"April",
|
|
36
|
+
"May",
|
|
37
|
+
"June",
|
|
38
|
+
"July",
|
|
39
|
+
"August",
|
|
40
|
+
"September",
|
|
41
|
+
"October",
|
|
42
|
+
"November",
|
|
43
|
+
"December"
|
|
44
|
+
];
|
|
45
|
+
function resolveDateValue(value) {
|
|
46
|
+
if (value instanceof Date) {
|
|
47
|
+
return Number.isNaN(value.getTime()) ? null : value;
|
|
48
|
+
}
|
|
49
|
+
if (typeof value !== "string" && typeof value !== "number") {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
if (typeof value === "string") {
|
|
53
|
+
const localDate = resolveLocalDateString(value);
|
|
54
|
+
if (localDate) {
|
|
55
|
+
return localDate;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const resolved = new Date(value);
|
|
59
|
+
return Number.isNaN(resolved.getTime()) ? null : resolved;
|
|
60
|
+
}
|
|
61
|
+
function isDateTimeFormatPattern(pattern) {
|
|
62
|
+
return DATE_TIME_FORMAT_TOKEN.test(pattern.replace(/\[[^\]]*\]/g, ""));
|
|
63
|
+
}
|
|
64
|
+
function formatDateTimeValue(value, pattern, locale = "zh-cn") {
|
|
65
|
+
const date = resolveDateValue(value);
|
|
66
|
+
const normalizedPattern = pattern.trim();
|
|
67
|
+
if (!date || !normalizedPattern) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const year = date.getFullYear();
|
|
71
|
+
const monthIndex = date.getMonth();
|
|
72
|
+
const month = monthIndex + 1;
|
|
73
|
+
const day = date.getDate();
|
|
74
|
+
const weekdayIndex = date.getDay();
|
|
75
|
+
const hour = date.getHours();
|
|
76
|
+
const hour12 = hour % 12 || 12;
|
|
77
|
+
const minute = date.getMinutes();
|
|
78
|
+
const second = date.getSeconds();
|
|
79
|
+
const millisecond = date.getMilliseconds();
|
|
80
|
+
const chinese = locale.toLowerCase().startsWith("zh");
|
|
81
|
+
const marker = hour >= 12 ? chinese ? "\u4E0B\u5348" : "PM" : chinese ? "\u4E0A\u5348" : "AM";
|
|
82
|
+
const weekday = chinese ? ZH_WEEKDAYS[weekdayIndex] ?? "" : EN_WEEKDAYS[weekdayIndex] ?? "";
|
|
83
|
+
const weekdayShort = chinese ? ZH_WEEKDAYS_SHORT[weekdayIndex] ?? "" : weekday.slice(0, 3);
|
|
84
|
+
const monthName = chinese ? `${month}\u6708` : EN_MONTHS[monthIndex] ?? "";
|
|
85
|
+
const values = {
|
|
86
|
+
YYYY: String(year).padStart(4, "0"),
|
|
87
|
+
YY: String(year).slice(-2),
|
|
88
|
+
M: String(month),
|
|
89
|
+
MM: padNumber(month),
|
|
90
|
+
MMM: chinese ? monthName : monthName.slice(0, 3),
|
|
91
|
+
MMMM: monthName,
|
|
92
|
+
D: String(day),
|
|
93
|
+
DD: padNumber(day),
|
|
94
|
+
d: String(weekdayIndex),
|
|
95
|
+
dd: chinese ? weekdayShort.slice(-1) : weekday.slice(0, 2),
|
|
96
|
+
ddd: weekdayShort,
|
|
97
|
+
dddd: weekday,
|
|
98
|
+
H: String(hour),
|
|
99
|
+
HH: padNumber(hour),
|
|
100
|
+
h: String(hour12),
|
|
101
|
+
hh: padNumber(hour12),
|
|
102
|
+
m: String(minute),
|
|
103
|
+
mm: padNumber(minute),
|
|
104
|
+
s: String(second),
|
|
105
|
+
ss: padNumber(second),
|
|
106
|
+
S: String(Math.floor(millisecond / 100)),
|
|
107
|
+
SS: String(Math.floor(millisecond / 10)).padStart(2, "0"),
|
|
108
|
+
SSS: String(millisecond).padStart(3, "0"),
|
|
109
|
+
A: marker,
|
|
110
|
+
a: marker.toLowerCase()
|
|
111
|
+
};
|
|
112
|
+
return normalizedPattern.replace(
|
|
113
|
+
FORMAT_TOKEN,
|
|
114
|
+
(token) => token.startsWith("[") && token.endsWith("]") ? token.slice(1, -1) : values[token] ?? token
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
function padNumber(value) {
|
|
118
|
+
return String(value).padStart(2, "0");
|
|
119
|
+
}
|
|
120
|
+
function resolveLocalDateString(value) {
|
|
121
|
+
const match = value.trim().match(
|
|
122
|
+
/^(\d{4})[-/](\d{1,2})[-/](\d{1,2})(?:[ T](\d{1,2}):?(\d{2})?(?::?(\d{2}))?(?:\.(\d{1,3}))?)?$/
|
|
123
|
+
);
|
|
124
|
+
if (!match) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
const [
|
|
128
|
+
,
|
|
129
|
+
yearText,
|
|
130
|
+
monthText,
|
|
131
|
+
dayText,
|
|
132
|
+
hourText,
|
|
133
|
+
minuteText,
|
|
134
|
+
secondText,
|
|
135
|
+
millisecondText
|
|
136
|
+
] = match;
|
|
137
|
+
const year = Number(yearText);
|
|
138
|
+
const monthIndex = Number(monthText) - 1;
|
|
139
|
+
const day = Number(dayText);
|
|
140
|
+
const hour = Number(hourText ?? 0);
|
|
141
|
+
const minute = Number(minuteText ?? 0);
|
|
142
|
+
const second = Number(secondText ?? 0);
|
|
143
|
+
const millisecond = Number((millisecondText ?? "0").padEnd(3, "0"));
|
|
144
|
+
const resolved = new Date(
|
|
145
|
+
year,
|
|
146
|
+
monthIndex,
|
|
147
|
+
day,
|
|
148
|
+
hour,
|
|
149
|
+
minute,
|
|
150
|
+
second,
|
|
151
|
+
millisecond
|
|
152
|
+
);
|
|
153
|
+
return resolved.getFullYear() === year && resolved.getMonth() === monthIndex && resolved.getDate() === day && resolved.getHours() === hour && resolved.getMinutes() === minute && resolved.getSeconds() === second ? resolved : null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export { formatDateTimeValue, isDateTimeFormatPattern, resolveDateValue };
|
|
157
|
+
//# sourceMappingURL=index.js.map
|
|
158
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/date/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/** Day.js 风格日期时间格式中支持识别的 token。 */\nconst DATE_TIME_FORMAT_TOKEN =\n /Y{2,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|m{1,2}|s{1,2}|S{1,3}|A|a/;\n\nconst FORMAT_TOKEN =\n /\\[[^\\]]*\\]|YYYY|MMMM|MMM|dddd|ddd|SSS|YY|MM|DD|dd|HH|hh|mm|ss|SS|M|D|d|H|h|m|s|S|A|a/g;\n\nconst ZH_WEEKDAYS = [\n \"星期日\",\n \"星期一\",\n \"星期二\",\n \"星期三\",\n \"星期四\",\n \"星期五\",\n \"星期六\",\n];\nconst ZH_WEEKDAYS_SHORT = [\n \"周日\",\n \"周一\",\n \"周二\",\n \"周三\",\n \"周四\",\n \"周五\",\n \"周六\",\n];\nconst EN_WEEKDAYS = [\n \"Sunday\",\n \"Monday\",\n \"Tuesday\",\n \"Wednesday\",\n \"Thursday\",\n \"Friday\",\n \"Saturday\",\n];\nconst EN_MONTHS = [\n \"January\",\n \"February\",\n \"March\",\n \"April\",\n \"May\",\n \"June\",\n \"July\",\n \"August\",\n \"September\",\n \"October\",\n \"November\",\n \"December\",\n];\n\n/** 将未知值解析为有效日期。 */\nexport function resolveDateValue(value: unknown): Date | null {\n if (value instanceof Date) {\n return Number.isNaN(value.getTime()) ? null : value;\n }\n if (typeof value !== \"string\" && typeof value !== \"number\") {\n return null;\n }\n if (typeof value === \"string\") {\n const localDate = resolveLocalDateString(value);\n if (localDate) {\n return localDate;\n }\n }\n const resolved = new Date(value);\n return Number.isNaN(resolved.getTime()) ? null : resolved;\n}\n\n/** 判断字符串中是否包含 Day.js 风格的日期时间格式 token。 */\nexport function isDateTimeFormatPattern(pattern: string) {\n return DATE_TIME_FORMAT_TOKEN.test(pattern.replace(/\\[[^\\]]*\\]/g, \"\"));\n}\n\n/**\n * 使用 Day.js 风格的常用 token 格式化日期时间,不依赖 Day.js 运行时。\n *\n * 支持年、月、日、星期、24/12 小时、分、秒、毫秒和上下午标记;\n * 默认使用中文区域设置,值或 pattern 无效时返回 `null`。\n */\nexport function formatDateTimeValue(\n value: unknown,\n pattern: string,\n locale = \"zh-cn\",\n): string | null {\n const date = resolveDateValue(value);\n const normalizedPattern = pattern.trim();\n if (!date || !normalizedPattern) {\n return null;\n }\n const year = date.getFullYear();\n const monthIndex = date.getMonth();\n const month = monthIndex + 1;\n const day = date.getDate();\n const weekdayIndex = date.getDay();\n const hour = date.getHours();\n const hour12 = hour % 12 || 12;\n const minute = date.getMinutes();\n const second = date.getSeconds();\n const millisecond = date.getMilliseconds();\n const chinese = locale.toLowerCase().startsWith(\"zh\");\n const marker =\n hour >= 12 ? (chinese ? \"下午\" : \"PM\") : chinese ? \"上午\" : \"AM\";\n const weekday = chinese\n ? (ZH_WEEKDAYS[weekdayIndex] ?? \"\")\n : (EN_WEEKDAYS[weekdayIndex] ?? \"\");\n const weekdayShort = chinese\n ? (ZH_WEEKDAYS_SHORT[weekdayIndex] ?? \"\")\n : weekday.slice(0, 3);\n const monthName = chinese ? `${month}月` : (EN_MONTHS[monthIndex] ?? \"\");\n const values: Record<string, string> = {\n YYYY: String(year).padStart(4, \"0\"),\n YY: String(year).slice(-2),\n M: String(month),\n MM: padNumber(month),\n MMM: chinese ? monthName : monthName.slice(0, 3),\n MMMM: monthName,\n D: String(day),\n DD: padNumber(day),\n d: String(weekdayIndex),\n dd: chinese ? weekdayShort.slice(-1) : weekday.slice(0, 2),\n ddd: weekdayShort,\n dddd: weekday,\n H: String(hour),\n HH: padNumber(hour),\n h: String(hour12),\n hh: padNumber(hour12),\n m: String(minute),\n mm: padNumber(minute),\n s: String(second),\n ss: padNumber(second),\n S: String(Math.floor(millisecond / 100)),\n SS: String(Math.floor(millisecond / 10)).padStart(2, \"0\"),\n SSS: String(millisecond).padStart(3, \"0\"),\n A: marker,\n a: marker.toLowerCase(),\n };\n\n return normalizedPattern.replace(FORMAT_TOKEN, (token) =>\n token.startsWith(\"[\") && token.endsWith(\"]\")\n ? token.slice(1, -1)\n : (values[token] ?? token),\n );\n}\n\nfunction padNumber(value: number) {\n return String(value).padStart(2, \"0\");\n}\n\nfunction resolveLocalDateString(value: string) {\n const match = value\n .trim()\n .match(\n /^(\\d{4})[-/](\\d{1,2})[-/](\\d{1,2})(?:[ T](\\d{1,2}):?(\\d{2})?(?::?(\\d{2}))?(?:\\.(\\d{1,3}))?)?$/,\n );\n if (!match) {\n return null;\n }\n const [\n ,\n yearText,\n monthText,\n dayText,\n hourText,\n minuteText,\n secondText,\n millisecondText,\n ] = match;\n const year = Number(yearText);\n const monthIndex = Number(monthText) - 1;\n const day = Number(dayText);\n const hour = Number(hourText ?? 0);\n const minute = Number(minuteText ?? 0);\n const second = Number(secondText ?? 0);\n const millisecond = Number((millisecondText ?? \"0\").padEnd(3, \"0\"));\n const resolved = new Date(\n year,\n monthIndex,\n day,\n hour,\n minute,\n second,\n millisecond,\n );\n return resolved.getFullYear() === year &&\n resolved.getMonth() === monthIndex &&\n resolved.getDate() === day &&\n resolved.getHours() === hour &&\n resolved.getMinutes() === minute &&\n resolved.getSeconds() === second\n ? resolved\n : null;\n}\n"]}
|
package/dist/export/index.cjs
CHANGED
|
@@ -35,11 +35,15 @@ function mapRowsToExportRecords(params) {
|
|
|
35
35
|
}
|
|
36
36
|
function buildCsvContent(params) {
|
|
37
37
|
const { rows, columns } = params;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
return serializeCsvRows([
|
|
39
|
+
columns.map((column) => column.title),
|
|
40
|
+
...rows.map(
|
|
41
|
+
(row, rowIndex) => columns.map((column) => column.value(row, rowIndex))
|
|
42
|
+
)
|
|
43
|
+
]);
|
|
44
|
+
}
|
|
45
|
+
function serializeCsvRows(rows, lineBreak = "\n") {
|
|
46
|
+
return rows.map((row) => row.map((value) => escapeCsvCell(value)).join(",")).join(lineBreak);
|
|
43
47
|
}
|
|
44
48
|
function buildTxtContent(params) {
|
|
45
49
|
const { rows, columns } = params;
|
|
@@ -77,12 +81,7 @@ async function exportTableToTxt(params) {
|
|
|
77
81
|
});
|
|
78
82
|
}
|
|
79
83
|
async function exportTableToXlsx(params) {
|
|
80
|
-
const {
|
|
81
|
-
fileName,
|
|
82
|
-
rows,
|
|
83
|
-
columns,
|
|
84
|
-
sheetName = "Sheet1"
|
|
85
|
-
} = params;
|
|
84
|
+
const { fileName, rows, columns, sheetName = "Sheet1" } = params;
|
|
86
85
|
const worksheet = await buildXlsxWorksheet({ rows, columns });
|
|
87
86
|
const workbook = XLSX__namespace.utils.book_new();
|
|
88
87
|
XLSX__namespace.utils.book_append_sheet(workbook, worksheet, sheetName);
|
|
@@ -101,7 +100,9 @@ async function buildXlsxWorksheet(params) {
|
|
|
101
100
|
const chunkSize = EXPORT_CHUNK_SIZE;
|
|
102
101
|
for (let start = 0; start < rows.length; start += chunkSize) {
|
|
103
102
|
const chunk = rows.slice(start, start + chunkSize).map(
|
|
104
|
-
(row, rowIndex) => columns.map(
|
|
103
|
+
(row, rowIndex) => columns.map(
|
|
104
|
+
(column) => normalizeXlsxCell(column.value(row, start + rowIndex))
|
|
105
|
+
)
|
|
105
106
|
);
|
|
106
107
|
XLSX__namespace.utils.sheet_add_aoa(worksheet, chunk, appendOptions);
|
|
107
108
|
await yieldToMainThread();
|
|
@@ -216,5 +217,6 @@ exports.exportTableToCsv = exportTableToCsv;
|
|
|
216
217
|
exports.exportTableToTxt = exportTableToTxt;
|
|
217
218
|
exports.exportTableToXlsx = exportTableToXlsx;
|
|
218
219
|
exports.mapRowsToExportRecords = mapRowsToExportRecords;
|
|
220
|
+
exports.serializeCsvRows = serializeCsvRows;
|
|
219
221
|
//# sourceMappingURL=index.cjs.map
|
|
220
222
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/export/index.ts"],"names":["XLSX"],"mappings":"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","file":"index.cjs","sourcesContent":["import * as XLSX from \"xlsx\";\r\n\r\nconst EXPORT_CHUNK_SIZE = 2_000;\r\n\r\nexport interface ExportTableColumn<Row> {\r\n key: string;\r\n title: string;\r\n value: (row: Row, index: number) => unknown;\r\n}\r\n\r\n/**\r\n * 将表格行映射为适合导出的对象数组。\r\n */\r\nexport function mapRowsToExportRecords<Row>(params: {\r\n rows: Row[];\r\n columns: ExportTableColumn<Row>[];\r\n}) {\r\n const { rows, columns } = params;\r\n return rows.map((row, rowIndex) =>\r\n columns.reduce<Record<string, unknown>>((record, column) => {\r\n record[column.title] = column.value(row, rowIndex);\r\n return record;\r\n }, {}),\r\n );\r\n}\r\n\r\n/**\r\n * 生成 CSV 文本内容。\r\n */\r\nexport function buildCsvContent<Row>(params: {\r\n rows: Row[];\r\n columns: ExportTableColumn<Row>[];\r\n}) {\r\n const { rows, columns } = params;\r\n const header = columns.map((column) => escapeCsvCell(column.title)).join(\",\");\r\n const body = rows.map((row, rowIndex) =>\r\n columns\r\n .map((column) => escapeCsvCell(column.value(row, rowIndex)))\r\n .join(\",\"),\r\n );\r\n\r\n return [header, ...body].join(\"\\n\");\r\n}\r\n\r\n/**\r\n * 生成 TXT 文本内容。\r\n */\r\nexport function buildTxtContent<Row>(params: {\r\n rows: Row[];\r\n columns: ExportTableColumn<Row>[];\r\n}) {\r\n const { rows, columns } = params;\r\n const header = columns.map((column) => normalizeTextCell(column.title)).join(\"\\t\");\r\n const body = rows.map((row, rowIndex) =>\r\n columns\r\n .map((column) => normalizeTextCell(column.value(row, rowIndex)))\r\n .join(\"\\t\"),\r\n );\r\n\r\n return [header, ...body].join(\"\\n\");\r\n}\r\n\r\n/**\r\n * 下载 JSON 文件。\r\n */\r\nexport async function downloadJsonFile(params: {\r\n fileName: string;\r\n data: unknown;\r\n space?: number;\r\n}) {\r\n const { data, fileName, space = 2 } = params;\r\n const content = await buildJsonContentAsync({ data, space });\r\n downloadTextFile({\r\n fileName: ensureExtension(fileName, \"json\"),\r\n content,\r\n type: \"application/json;charset=utf-8\",\r\n });\r\n}\r\n\r\n/**\r\n * 导出表格 CSV 文件。\r\n */\r\nexport async function exportTableToCsv<Row>(params: {\r\n fileName: string;\r\n rows: Row[];\r\n columns: ExportTableColumn<Row>[];\r\n}) {\r\n const { fileName, rows, columns } = params;\r\n const content = await buildCsvContentAsync({ rows, columns });\r\n downloadTextFile({\r\n fileName: ensureExtension(fileName, \"csv\"),\r\n content,\r\n type: \"text/csv;charset=utf-8\",\r\n });\r\n}\r\n\r\n/**\r\n * 导出表格 TXT 文件。\r\n */\r\nexport async function exportTableToTxt<Row>(params: {\r\n fileName: string;\r\n rows: Row[];\r\n columns: ExportTableColumn<Row>[];\r\n}) {\r\n const { fileName, rows, columns } = params;\r\n const content = await buildTxtContentAsync({ rows, columns });\r\n downloadTextFile({\r\n fileName: ensureExtension(fileName, \"txt\"),\r\n content,\r\n type: \"text/plain;charset=utf-8\",\r\n });\r\n}\r\n\r\n/**\r\n * 导出表格 XLSX 文件。\r\n */\r\nexport async function exportTableToXlsx<Row>(params: {\r\n fileName: string;\r\n rows: Row[];\r\n columns: ExportTableColumn<Row>[];\r\n sheetName?: string;\r\n}) {\r\n const {\r\n fileName,\r\n rows,\r\n columns,\r\n sheetName = \"Sheet1\",\r\n } = params;\r\n const worksheet = await buildXlsxWorksheet({ rows, columns });\r\n const workbook = XLSX.utils.book_new();\r\n XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);\r\n await yieldToMainThread();\r\n XLSX.writeFile(workbook, ensureExtension(fileName, \"xlsx\"));\r\n}\r\n\r\n/**\r\n * 构建适合大数据量导出的 XLSX 工作表。\r\n */\r\nasync function buildXlsxWorksheet<Row>(params: {\r\n rows: Row[];\r\n columns: ExportTableColumn<Row>[];\r\n}) {\r\n const { rows, columns } = params;\r\n const header = columns.map((column) => column.title);\r\n const denseOptions = { dense: true } as unknown as XLSX.AOA2SheetOpts;\r\n const appendOptions = {\r\n origin: -1,\r\n dense: true,\r\n } as unknown as XLSX.SheetAOAOpts;\r\n const worksheet = XLSX.utils.aoa_to_sheet([header], denseOptions);\r\n const chunkSize = EXPORT_CHUNK_SIZE;\r\n\r\n for (let start = 0; start < rows.length; start += chunkSize) {\r\n const chunk = rows.slice(start, start + chunkSize).map((row, rowIndex) =>\r\n columns.map((column) => normalizeXlsxCell(column.value(row, start + rowIndex))),\r\n );\r\n\r\n XLSX.utils.sheet_add_aoa(worksheet, chunk, appendOptions);\r\n\r\n await yieldToMainThread();\r\n }\r\n\r\n return worksheet;\r\n}\r\n\r\nasync function buildJsonContentAsync(params: {\r\n data: unknown;\r\n space: number;\r\n}) {\r\n const { data, space } = params;\r\n if (!Array.isArray(data)) {\r\n return JSON.stringify(data, null, space) ?? \"\";\r\n }\r\n\r\n if (data.length === 0) {\r\n return \"[]\";\r\n }\r\n\r\n const lineBreak = space > 0 ? \"\\n\" : \"\";\r\n const indent = space > 0 ? \" \".repeat(space) : \"\";\r\n const parts = [\"[\", lineBreak];\r\n\r\n for (let start = 0; start < data.length; start += EXPORT_CHUNK_SIZE) {\r\n const chunk = data.slice(start, start + EXPORT_CHUNK_SIZE);\r\n for (let index = 0; index < chunk.length; index += 1) {\r\n const itemIndex = start + index;\r\n const prefix = itemIndex === 0 ? \"\" : `,${lineBreak}`;\r\n const content = JSON.stringify(chunk[index], null, space) ?? \"null\";\r\n parts.push(prefix, indent, content);\r\n }\r\n\r\n await yieldToMainThread();\r\n }\r\n\r\n parts.push(lineBreak, \"]\");\r\n return parts.join(\"\");\r\n}\r\n\r\nasync function buildCsvContentAsync<Row>(params: {\r\n rows: Row[];\r\n columns: ExportTableColumn<Row>[];\r\n}) {\r\n const { rows, columns } = params;\r\n const header = columns.map((column) => escapeCsvCell(column.title)).join(\",\");\r\n const parts = [header];\r\n\r\n for (let start = 0; start < rows.length; start += EXPORT_CHUNK_SIZE) {\r\n const chunk = rows.slice(start, start + EXPORT_CHUNK_SIZE);\r\n for (let rowIndex = 0; rowIndex < chunk.length; rowIndex += 1) {\r\n const row = chunk[rowIndex];\r\n const line = columns\r\n .map((column) => escapeCsvCell(column.value(row, start + rowIndex)))\r\n .join(\",\");\r\n parts.push(\"\\n\", line);\r\n }\r\n\r\n await yieldToMainThread();\r\n }\r\n\r\n return parts.join(\"\");\r\n}\r\n\r\nasync function buildTxtContentAsync<Row>(params: {\r\n rows: Row[];\r\n columns: ExportTableColumn<Row>[];\r\n}) {\r\n const { rows, columns } = params;\r\n const header = columns.map((column) => normalizeTextCell(column.title)).join(\"\\t\");\r\n const parts = [header];\r\n\r\n for (let start = 0; start < rows.length; start += EXPORT_CHUNK_SIZE) {\r\n const chunk = rows.slice(start, start + EXPORT_CHUNK_SIZE);\r\n for (let rowIndex = 0; rowIndex < chunk.length; rowIndex += 1) {\r\n const row = chunk[rowIndex];\r\n const line = columns\r\n .map((column) => normalizeTextCell(column.value(row, start + rowIndex)))\r\n .join(\"\\t\");\r\n parts.push(\"\\n\", line);\r\n }\r\n\r\n await yieldToMainThread();\r\n }\r\n\r\n return parts.join(\"\");\r\n}\r\n\r\nfunction escapeCsvCell(value: unknown) {\r\n const normalized = value == null ? \"\" : String(value);\r\n if (\r\n normalized.includes(\",\") ||\r\n normalized.includes(\"\\\"\") ||\r\n normalized.includes(\"\\n\")\r\n ) {\r\n return `\"${normalized.split(\"\\\"\").join(\"\\\"\\\"\")}\"`;\r\n }\r\n return normalized;\r\n}\r\n\r\nfunction normalizeTextCell(value: unknown) {\r\n return value == null ? \"\" : String(value);\r\n}\r\n\r\nfunction normalizeXlsxCell(value: unknown) {\r\n if (value == null) {\r\n return \"\";\r\n }\r\n\r\n if (\r\n typeof value === \"string\" ||\r\n typeof value === \"number\" ||\r\n typeof value === \"boolean\"\r\n ) {\r\n return value;\r\n }\r\n\r\n if (value instanceof Date) {\r\n return value;\r\n }\r\n\r\n return String(value);\r\n}\r\n\r\nfunction ensureExtension(fileName: string, extension: string) {\r\n return fileName.toLowerCase().endsWith(`.${extension}`)\r\n ? fileName\r\n : `${fileName}.${extension}`;\r\n}\r\n\r\nfunction yieldToMainThread() {\r\n return new Promise<void>((resolve) => {\r\n if (typeof window !== \"undefined\" && typeof window.requestAnimationFrame === \"function\") {\r\n window.requestAnimationFrame(() => {\r\n resolve();\r\n });\r\n return;\r\n }\r\n\r\n setTimeout(resolve, 0);\r\n });\r\n}\r\n\r\nfunction downloadTextFile(params: {\r\n fileName: string;\r\n content: string;\r\n type: string;\r\n}) {\r\n const { fileName, content, type } = params;\r\n const blob = new Blob([content], { type });\r\n const url = URL.createObjectURL(blob);\r\n const anchor = document.createElement(\"a\");\r\n anchor.href = url;\r\n anchor.download = fileName;\r\n anchor.click();\r\n URL.revokeObjectURL(url);\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/export/index.ts"],"names":["XLSX"],"mappings":"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","file":"index.cjs","sourcesContent":["import * as XLSX from \"xlsx\";\n\nconst EXPORT_CHUNK_SIZE = 2_000;\n\nexport interface ExportTableColumn<Row> {\n key: string;\n title: string;\n value: (row: Row, index: number) => unknown;\n}\n\n/**\n * 将表格行映射为适合导出的对象数组。\n */\nexport function mapRowsToExportRecords<Row>(params: {\n rows: Row[];\n columns: ExportTableColumn<Row>[];\n}) {\n const { rows, columns } = params;\n return rows.map((row, rowIndex) =>\n columns.reduce<Record<string, unknown>>((record, column) => {\n record[column.title] = column.value(row, rowIndex);\n return record;\n }, {}),\n );\n}\n\n/**\n * 生成 CSV 文本内容。\n */\nexport function buildCsvContent<Row>(params: {\n rows: Row[];\n columns: ExportTableColumn<Row>[];\n}) {\n const { rows, columns } = params;\n return serializeCsvRows([\n columns.map((column) => column.title),\n ...rows.map((row, rowIndex) =>\n columns.map((column) => column.value(row, rowIndex)),\n ),\n ]);\n}\n\n/**\n * 将二维数据序列化为 CSV 文本。\n */\nexport function serializeCsvRows(\n rows: readonly (readonly unknown[])[],\n lineBreak = \"\\n\",\n) {\n return rows\n .map((row) => row.map((value) => escapeCsvCell(value)).join(\",\"))\n .join(lineBreak);\n}\n\n/**\n * 生成 TXT 文本内容。\n */\nexport function buildTxtContent<Row>(params: {\n rows: Row[];\n columns: ExportTableColumn<Row>[];\n}) {\n const { rows, columns } = params;\n const header = columns\n .map((column) => normalizeTextCell(column.title))\n .join(\"\\t\");\n const body = rows.map((row, rowIndex) =>\n columns\n .map((column) => normalizeTextCell(column.value(row, rowIndex)))\n .join(\"\\t\"),\n );\n\n return [header, ...body].join(\"\\n\");\n}\n\n/**\n * 下载 JSON 文件。\n */\nexport async function downloadJsonFile(params: {\n fileName: string;\n data: unknown;\n space?: number;\n}) {\n const { data, fileName, space = 2 } = params;\n const content = await buildJsonContentAsync({ data, space });\n downloadTextFile({\n fileName: ensureExtension(fileName, \"json\"),\n content,\n type: \"application/json;charset=utf-8\",\n });\n}\n\n/**\n * 导出表格 CSV 文件。\n */\nexport async function exportTableToCsv<Row>(params: {\n fileName: string;\n rows: Row[];\n columns: ExportTableColumn<Row>[];\n}) {\n const { fileName, rows, columns } = params;\n const content = await buildCsvContentAsync({ rows, columns });\n downloadTextFile({\n fileName: ensureExtension(fileName, \"csv\"),\n content,\n type: \"text/csv;charset=utf-8\",\n });\n}\n\n/**\n * 导出表格 TXT 文件。\n */\nexport async function exportTableToTxt<Row>(params: {\n fileName: string;\n rows: Row[];\n columns: ExportTableColumn<Row>[];\n}) {\n const { fileName, rows, columns } = params;\n const content = await buildTxtContentAsync({ rows, columns });\n downloadTextFile({\n fileName: ensureExtension(fileName, \"txt\"),\n content,\n type: \"text/plain;charset=utf-8\",\n });\n}\n\n/**\n * 导出表格 XLSX 文件。\n */\nexport async function exportTableToXlsx<Row>(params: {\n fileName: string;\n rows: Row[];\n columns: ExportTableColumn<Row>[];\n sheetName?: string;\n}) {\n const { fileName, rows, columns, sheetName = \"Sheet1\" } = params;\n const worksheet = await buildXlsxWorksheet({ rows, columns });\n const workbook = XLSX.utils.book_new();\n XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);\n await yieldToMainThread();\n XLSX.writeFile(workbook, ensureExtension(fileName, \"xlsx\"));\n}\n\n/**\n * 构建适合大数据量导出的 XLSX 工作表。\n */\nasync function buildXlsxWorksheet<Row>(params: {\n rows: Row[];\n columns: ExportTableColumn<Row>[];\n}) {\n const { rows, columns } = params;\n const header = columns.map((column) => column.title);\n const denseOptions = { dense: true } as unknown as XLSX.AOA2SheetOpts;\n const appendOptions = {\n origin: -1,\n dense: true,\n } as unknown as XLSX.SheetAOAOpts;\n const worksheet = XLSX.utils.aoa_to_sheet([header], denseOptions);\n const chunkSize = EXPORT_CHUNK_SIZE;\n\n for (let start = 0; start < rows.length; start += chunkSize) {\n const chunk = rows\n .slice(start, start + chunkSize)\n .map((row, rowIndex) =>\n columns.map((column) =>\n normalizeXlsxCell(column.value(row, start + rowIndex)),\n ),\n );\n\n XLSX.utils.sheet_add_aoa(worksheet, chunk, appendOptions);\n\n await yieldToMainThread();\n }\n\n return worksheet;\n}\n\nasync function buildJsonContentAsync(params: { data: unknown; space: number }) {\n const { data, space } = params;\n if (!Array.isArray(data)) {\n return JSON.stringify(data, null, space) ?? \"\";\n }\n\n if (data.length === 0) {\n return \"[]\";\n }\n\n const lineBreak = space > 0 ? \"\\n\" : \"\";\n const indent = space > 0 ? \" \".repeat(space) : \"\";\n const parts = [\"[\", lineBreak];\n\n for (let start = 0; start < data.length; start += EXPORT_CHUNK_SIZE) {\n const chunk = data.slice(start, start + EXPORT_CHUNK_SIZE);\n for (let index = 0; index < chunk.length; index += 1) {\n const itemIndex = start + index;\n const prefix = itemIndex === 0 ? \"\" : `,${lineBreak}`;\n const content = JSON.stringify(chunk[index], null, space) ?? \"null\";\n parts.push(prefix, indent, content);\n }\n\n await yieldToMainThread();\n }\n\n parts.push(lineBreak, \"]\");\n return parts.join(\"\");\n}\n\nasync function buildCsvContentAsync<Row>(params: {\n rows: Row[];\n columns: ExportTableColumn<Row>[];\n}) {\n const { rows, columns } = params;\n const header = columns.map((column) => escapeCsvCell(column.title)).join(\",\");\n const parts = [header];\n\n for (let start = 0; start < rows.length; start += EXPORT_CHUNK_SIZE) {\n const chunk = rows.slice(start, start + EXPORT_CHUNK_SIZE);\n for (let rowIndex = 0; rowIndex < chunk.length; rowIndex += 1) {\n const row = chunk[rowIndex];\n const line = columns\n .map((column) => escapeCsvCell(column.value(row, start + rowIndex)))\n .join(\",\");\n parts.push(\"\\n\", line);\n }\n\n await yieldToMainThread();\n }\n\n return parts.join(\"\");\n}\n\nasync function buildTxtContentAsync<Row>(params: {\n rows: Row[];\n columns: ExportTableColumn<Row>[];\n}) {\n const { rows, columns } = params;\n const header = columns\n .map((column) => normalizeTextCell(column.title))\n .join(\"\\t\");\n const parts = [header];\n\n for (let start = 0; start < rows.length; start += EXPORT_CHUNK_SIZE) {\n const chunk = rows.slice(start, start + EXPORT_CHUNK_SIZE);\n for (let rowIndex = 0; rowIndex < chunk.length; rowIndex += 1) {\n const row = chunk[rowIndex];\n const line = columns\n .map((column) => normalizeTextCell(column.value(row, start + rowIndex)))\n .join(\"\\t\");\n parts.push(\"\\n\", line);\n }\n\n await yieldToMainThread();\n }\n\n return parts.join(\"\");\n}\n\nfunction escapeCsvCell(value: unknown) {\n const normalized = value == null ? \"\" : String(value);\n if (\n normalized.includes(\",\") ||\n normalized.includes('\"') ||\n normalized.includes(\"\\n\")\n ) {\n return `\"${normalized.split('\"').join('\"\"')}\"`;\n }\n return normalized;\n}\n\nfunction normalizeTextCell(value: unknown) {\n return value == null ? \"\" : String(value);\n}\n\nfunction normalizeXlsxCell(value: unknown) {\n if (value == null) {\n return \"\";\n }\n\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n return value;\n }\n\n if (value instanceof Date) {\n return value;\n }\n\n return String(value);\n}\n\nfunction ensureExtension(fileName: string, extension: string) {\n return fileName.toLowerCase().endsWith(`.${extension}`)\n ? fileName\n : `${fileName}.${extension}`;\n}\n\nfunction yieldToMainThread() {\n return new Promise<void>((resolve) => {\n if (\n typeof window !== \"undefined\" &&\n typeof window.requestAnimationFrame === \"function\"\n ) {\n window.requestAnimationFrame(() => {\n resolve();\n });\n return;\n }\n\n setTimeout(resolve, 0);\n });\n}\n\nfunction downloadTextFile(params: {\n fileName: string;\n content: string;\n type: string;\n}) {\n const { fileName, content, type } = params;\n const blob = new Blob([content], { type });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = fileName;\n anchor.click();\n URL.revokeObjectURL(url);\n}\n"]}
|
package/dist/export/index.d.cts
CHANGED
|
@@ -17,6 +17,10 @@ declare function buildCsvContent<Row>(params: {
|
|
|
17
17
|
rows: Row[];
|
|
18
18
|
columns: ExportTableColumn<Row>[];
|
|
19
19
|
}): string;
|
|
20
|
+
/**
|
|
21
|
+
* 将二维数据序列化为 CSV 文本。
|
|
22
|
+
*/
|
|
23
|
+
declare function serializeCsvRows(rows: readonly (readonly unknown[])[], lineBreak?: string): string;
|
|
20
24
|
/**
|
|
21
25
|
* 生成 TXT 文本内容。
|
|
22
26
|
*/
|
|
@@ -58,4 +62,4 @@ declare function exportTableToXlsx<Row>(params: {
|
|
|
58
62
|
sheetName?: string;
|
|
59
63
|
}): Promise<void>;
|
|
60
64
|
|
|
61
|
-
export { type ExportTableColumn, buildCsvContent, buildTxtContent, downloadJsonFile, exportTableToCsv, exportTableToTxt, exportTableToXlsx, mapRowsToExportRecords };
|
|
65
|
+
export { type ExportTableColumn, buildCsvContent, buildTxtContent, downloadJsonFile, exportTableToCsv, exportTableToTxt, exportTableToXlsx, mapRowsToExportRecords, serializeCsvRows };
|
package/dist/export/index.d.ts
CHANGED
|
@@ -17,6 +17,10 @@ declare function buildCsvContent<Row>(params: {
|
|
|
17
17
|
rows: Row[];
|
|
18
18
|
columns: ExportTableColumn<Row>[];
|
|
19
19
|
}): string;
|
|
20
|
+
/**
|
|
21
|
+
* 将二维数据序列化为 CSV 文本。
|
|
22
|
+
*/
|
|
23
|
+
declare function serializeCsvRows(rows: readonly (readonly unknown[])[], lineBreak?: string): string;
|
|
20
24
|
/**
|
|
21
25
|
* 生成 TXT 文本内容。
|
|
22
26
|
*/
|
|
@@ -58,4 +62,4 @@ declare function exportTableToXlsx<Row>(params: {
|
|
|
58
62
|
sheetName?: string;
|
|
59
63
|
}): Promise<void>;
|
|
60
64
|
|
|
61
|
-
export { type ExportTableColumn, buildCsvContent, buildTxtContent, downloadJsonFile, exportTableToCsv, exportTableToTxt, exportTableToXlsx, mapRowsToExportRecords };
|
|
65
|
+
export { type ExportTableColumn, buildCsvContent, buildTxtContent, downloadJsonFile, exportTableToCsv, exportTableToTxt, exportTableToXlsx, mapRowsToExportRecords, serializeCsvRows };
|
package/dist/export/index.js
CHANGED
|
@@ -13,11 +13,15 @@ function mapRowsToExportRecords(params) {
|
|
|
13
13
|
}
|
|
14
14
|
function buildCsvContent(params) {
|
|
15
15
|
const { rows, columns } = params;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
return serializeCsvRows([
|
|
17
|
+
columns.map((column) => column.title),
|
|
18
|
+
...rows.map(
|
|
19
|
+
(row, rowIndex) => columns.map((column) => column.value(row, rowIndex))
|
|
20
|
+
)
|
|
21
|
+
]);
|
|
22
|
+
}
|
|
23
|
+
function serializeCsvRows(rows, lineBreak = "\n") {
|
|
24
|
+
return rows.map((row) => row.map((value) => escapeCsvCell(value)).join(",")).join(lineBreak);
|
|
21
25
|
}
|
|
22
26
|
function buildTxtContent(params) {
|
|
23
27
|
const { rows, columns } = params;
|
|
@@ -55,12 +59,7 @@ async function exportTableToTxt(params) {
|
|
|
55
59
|
});
|
|
56
60
|
}
|
|
57
61
|
async function exportTableToXlsx(params) {
|
|
58
|
-
const {
|
|
59
|
-
fileName,
|
|
60
|
-
rows,
|
|
61
|
-
columns,
|
|
62
|
-
sheetName = "Sheet1"
|
|
63
|
-
} = params;
|
|
62
|
+
const { fileName, rows, columns, sheetName = "Sheet1" } = params;
|
|
64
63
|
const worksheet = await buildXlsxWorksheet({ rows, columns });
|
|
65
64
|
const workbook = XLSX.utils.book_new();
|
|
66
65
|
XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
|
|
@@ -79,7 +78,9 @@ async function buildXlsxWorksheet(params) {
|
|
|
79
78
|
const chunkSize = EXPORT_CHUNK_SIZE;
|
|
80
79
|
for (let start = 0; start < rows.length; start += chunkSize) {
|
|
81
80
|
const chunk = rows.slice(start, start + chunkSize).map(
|
|
82
|
-
(row, rowIndex) => columns.map(
|
|
81
|
+
(row, rowIndex) => columns.map(
|
|
82
|
+
(column) => normalizeXlsxCell(column.value(row, start + rowIndex))
|
|
83
|
+
)
|
|
83
84
|
);
|
|
84
85
|
XLSX.utils.sheet_add_aoa(worksheet, chunk, appendOptions);
|
|
85
86
|
await yieldToMainThread();
|
|
@@ -187,6 +188,6 @@ function downloadTextFile(params) {
|
|
|
187
188
|
URL.revokeObjectURL(url);
|
|
188
189
|
}
|
|
189
190
|
|
|
190
|
-
export { buildCsvContent, buildTxtContent, downloadJsonFile, exportTableToCsv, exportTableToTxt, exportTableToXlsx, mapRowsToExportRecords };
|
|
191
|
+
export { buildCsvContent, buildTxtContent, downloadJsonFile, exportTableToCsv, exportTableToTxt, exportTableToXlsx, mapRowsToExportRecords, serializeCsvRows };
|
|
191
192
|
//# sourceMappingURL=index.js.map
|
|
192
193
|
//# sourceMappingURL=index.js.map
|
package/dist/export/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/export/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import * as XLSX from \"xlsx\";\r\n\r\nconst EXPORT_CHUNK_SIZE = 2_000;\r\n\r\nexport interface ExportTableColumn<Row> {\r\n key: string;\r\n title: string;\r\n value: (row: Row, index: number) => unknown;\r\n}\r\n\r\n/**\r\n * 将表格行映射为适合导出的对象数组。\r\n */\r\nexport function mapRowsToExportRecords<Row>(params: {\r\n rows: Row[];\r\n columns: ExportTableColumn<Row>[];\r\n}) {\r\n const { rows, columns } = params;\r\n return rows.map((row, rowIndex) =>\r\n columns.reduce<Record<string, unknown>>((record, column) => {\r\n record[column.title] = column.value(row, rowIndex);\r\n return record;\r\n }, {}),\r\n );\r\n}\r\n\r\n/**\r\n * 生成 CSV 文本内容。\r\n */\r\nexport function buildCsvContent<Row>(params: {\r\n rows: Row[];\r\n columns: ExportTableColumn<Row>[];\r\n}) {\r\n const { rows, columns } = params;\r\n const header = columns.map((column) => escapeCsvCell(column.title)).join(\",\");\r\n const body = rows.map((row, rowIndex) =>\r\n columns\r\n .map((column) => escapeCsvCell(column.value(row, rowIndex)))\r\n .join(\",\"),\r\n );\r\n\r\n return [header, ...body].join(\"\\n\");\r\n}\r\n\r\n/**\r\n * 生成 TXT 文本内容。\r\n */\r\nexport function buildTxtContent<Row>(params: {\r\n rows: Row[];\r\n columns: ExportTableColumn<Row>[];\r\n}) {\r\n const { rows, columns } = params;\r\n const header = columns.map((column) => normalizeTextCell(column.title)).join(\"\\t\");\r\n const body = rows.map((row, rowIndex) =>\r\n columns\r\n .map((column) => normalizeTextCell(column.value(row, rowIndex)))\r\n .join(\"\\t\"),\r\n );\r\n\r\n return [header, ...body].join(\"\\n\");\r\n}\r\n\r\n/**\r\n * 下载 JSON 文件。\r\n */\r\nexport async function downloadJsonFile(params: {\r\n fileName: string;\r\n data: unknown;\r\n space?: number;\r\n}) {\r\n const { data, fileName, space = 2 } = params;\r\n const content = await buildJsonContentAsync({ data, space });\r\n downloadTextFile({\r\n fileName: ensureExtension(fileName, \"json\"),\r\n content,\r\n type: \"application/json;charset=utf-8\",\r\n });\r\n}\r\n\r\n/**\r\n * 导出表格 CSV 文件。\r\n */\r\nexport async function exportTableToCsv<Row>(params: {\r\n fileName: string;\r\n rows: Row[];\r\n columns: ExportTableColumn<Row>[];\r\n}) {\r\n const { fileName, rows, columns } = params;\r\n const content = await buildCsvContentAsync({ rows, columns });\r\n downloadTextFile({\r\n fileName: ensureExtension(fileName, \"csv\"),\r\n content,\r\n type: \"text/csv;charset=utf-8\",\r\n });\r\n}\r\n\r\n/**\r\n * 导出表格 TXT 文件。\r\n */\r\nexport async function exportTableToTxt<Row>(params: {\r\n fileName: string;\r\n rows: Row[];\r\n columns: ExportTableColumn<Row>[];\r\n}) {\r\n const { fileName, rows, columns } = params;\r\n const content = await buildTxtContentAsync({ rows, columns });\r\n downloadTextFile({\r\n fileName: ensureExtension(fileName, \"txt\"),\r\n content,\r\n type: \"text/plain;charset=utf-8\",\r\n });\r\n}\r\n\r\n/**\r\n * 导出表格 XLSX 文件。\r\n */\r\nexport async function exportTableToXlsx<Row>(params: {\r\n fileName: string;\r\n rows: Row[];\r\n columns: ExportTableColumn<Row>[];\r\n sheetName?: string;\r\n}) {\r\n const {\r\n fileName,\r\n rows,\r\n columns,\r\n sheetName = \"Sheet1\",\r\n } = params;\r\n const worksheet = await buildXlsxWorksheet({ rows, columns });\r\n const workbook = XLSX.utils.book_new();\r\n XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);\r\n await yieldToMainThread();\r\n XLSX.writeFile(workbook, ensureExtension(fileName, \"xlsx\"));\r\n}\r\n\r\n/**\r\n * 构建适合大数据量导出的 XLSX 工作表。\r\n */\r\nasync function buildXlsxWorksheet<Row>(params: {\r\n rows: Row[];\r\n columns: ExportTableColumn<Row>[];\r\n}) {\r\n const { rows, columns } = params;\r\n const header = columns.map((column) => column.title);\r\n const denseOptions = { dense: true } as unknown as XLSX.AOA2SheetOpts;\r\n const appendOptions = {\r\n origin: -1,\r\n dense: true,\r\n } as unknown as XLSX.SheetAOAOpts;\r\n const worksheet = XLSX.utils.aoa_to_sheet([header], denseOptions);\r\n const chunkSize = EXPORT_CHUNK_SIZE;\r\n\r\n for (let start = 0; start < rows.length; start += chunkSize) {\r\n const chunk = rows.slice(start, start + chunkSize).map((row, rowIndex) =>\r\n columns.map((column) => normalizeXlsxCell(column.value(row, start + rowIndex))),\r\n );\r\n\r\n XLSX.utils.sheet_add_aoa(worksheet, chunk, appendOptions);\r\n\r\n await yieldToMainThread();\r\n }\r\n\r\n return worksheet;\r\n}\r\n\r\nasync function buildJsonContentAsync(params: {\r\n data: unknown;\r\n space: number;\r\n}) {\r\n const { data, space } = params;\r\n if (!Array.isArray(data)) {\r\n return JSON.stringify(data, null, space) ?? \"\";\r\n }\r\n\r\n if (data.length === 0) {\r\n return \"[]\";\r\n }\r\n\r\n const lineBreak = space > 0 ? \"\\n\" : \"\";\r\n const indent = space > 0 ? \" \".repeat(space) : \"\";\r\n const parts = [\"[\", lineBreak];\r\n\r\n for (let start = 0; start < data.length; start += EXPORT_CHUNK_SIZE) {\r\n const chunk = data.slice(start, start + EXPORT_CHUNK_SIZE);\r\n for (let index = 0; index < chunk.length; index += 1) {\r\n const itemIndex = start + index;\r\n const prefix = itemIndex === 0 ? \"\" : `,${lineBreak}`;\r\n const content = JSON.stringify(chunk[index], null, space) ?? \"null\";\r\n parts.push(prefix, indent, content);\r\n }\r\n\r\n await yieldToMainThread();\r\n }\r\n\r\n parts.push(lineBreak, \"]\");\r\n return parts.join(\"\");\r\n}\r\n\r\nasync function buildCsvContentAsync<Row>(params: {\r\n rows: Row[];\r\n columns: ExportTableColumn<Row>[];\r\n}) {\r\n const { rows, columns } = params;\r\n const header = columns.map((column) => escapeCsvCell(column.title)).join(\",\");\r\n const parts = [header];\r\n\r\n for (let start = 0; start < rows.length; start += EXPORT_CHUNK_SIZE) {\r\n const chunk = rows.slice(start, start + EXPORT_CHUNK_SIZE);\r\n for (let rowIndex = 0; rowIndex < chunk.length; rowIndex += 1) {\r\n const row = chunk[rowIndex];\r\n const line = columns\r\n .map((column) => escapeCsvCell(column.value(row, start + rowIndex)))\r\n .join(\",\");\r\n parts.push(\"\\n\", line);\r\n }\r\n\r\n await yieldToMainThread();\r\n }\r\n\r\n return parts.join(\"\");\r\n}\r\n\r\nasync function buildTxtContentAsync<Row>(params: {\r\n rows: Row[];\r\n columns: ExportTableColumn<Row>[];\r\n}) {\r\n const { rows, columns } = params;\r\n const header = columns.map((column) => normalizeTextCell(column.title)).join(\"\\t\");\r\n const parts = [header];\r\n\r\n for (let start = 0; start < rows.length; start += EXPORT_CHUNK_SIZE) {\r\n const chunk = rows.slice(start, start + EXPORT_CHUNK_SIZE);\r\n for (let rowIndex = 0; rowIndex < chunk.length; rowIndex += 1) {\r\n const row = chunk[rowIndex];\r\n const line = columns\r\n .map((column) => normalizeTextCell(column.value(row, start + rowIndex)))\r\n .join(\"\\t\");\r\n parts.push(\"\\n\", line);\r\n }\r\n\r\n await yieldToMainThread();\r\n }\r\n\r\n return parts.join(\"\");\r\n}\r\n\r\nfunction escapeCsvCell(value: unknown) {\r\n const normalized = value == null ? \"\" : String(value);\r\n if (\r\n normalized.includes(\",\") ||\r\n normalized.includes(\"\\\"\") ||\r\n normalized.includes(\"\\n\")\r\n ) {\r\n return `\"${normalized.split(\"\\\"\").join(\"\\\"\\\"\")}\"`;\r\n }\r\n return normalized;\r\n}\r\n\r\nfunction normalizeTextCell(value: unknown) {\r\n return value == null ? \"\" : String(value);\r\n}\r\n\r\nfunction normalizeXlsxCell(value: unknown) {\r\n if (value == null) {\r\n return \"\";\r\n }\r\n\r\n if (\r\n typeof value === \"string\" ||\r\n typeof value === \"number\" ||\r\n typeof value === \"boolean\"\r\n ) {\r\n return value;\r\n }\r\n\r\n if (value instanceof Date) {\r\n return value;\r\n }\r\n\r\n return String(value);\r\n}\r\n\r\nfunction ensureExtension(fileName: string, extension: string) {\r\n return fileName.toLowerCase().endsWith(`.${extension}`)\r\n ? fileName\r\n : `${fileName}.${extension}`;\r\n}\r\n\r\nfunction yieldToMainThread() {\r\n return new Promise<void>((resolve) => {\r\n if (typeof window !== \"undefined\" && typeof window.requestAnimationFrame === \"function\") {\r\n window.requestAnimationFrame(() => {\r\n resolve();\r\n });\r\n return;\r\n }\r\n\r\n setTimeout(resolve, 0);\r\n });\r\n}\r\n\r\nfunction downloadTextFile(params: {\r\n fileName: string;\r\n content: string;\r\n type: string;\r\n}) {\r\n const { fileName, content, type } = params;\r\n const blob = new Blob([content], { type });\r\n const url = URL.createObjectURL(blob);\r\n const anchor = document.createElement(\"a\");\r\n anchor.href = url;\r\n anchor.download = fileName;\r\n anchor.click();\r\n URL.revokeObjectURL(url);\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/export/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import * as XLSX from \"xlsx\";\n\nconst EXPORT_CHUNK_SIZE = 2_000;\n\nexport interface ExportTableColumn<Row> {\n key: string;\n title: string;\n value: (row: Row, index: number) => unknown;\n}\n\n/**\n * 将表格行映射为适合导出的对象数组。\n */\nexport function mapRowsToExportRecords<Row>(params: {\n rows: Row[];\n columns: ExportTableColumn<Row>[];\n}) {\n const { rows, columns } = params;\n return rows.map((row, rowIndex) =>\n columns.reduce<Record<string, unknown>>((record, column) => {\n record[column.title] = column.value(row, rowIndex);\n return record;\n }, {}),\n );\n}\n\n/**\n * 生成 CSV 文本内容。\n */\nexport function buildCsvContent<Row>(params: {\n rows: Row[];\n columns: ExportTableColumn<Row>[];\n}) {\n const { rows, columns } = params;\n return serializeCsvRows([\n columns.map((column) => column.title),\n ...rows.map((row, rowIndex) =>\n columns.map((column) => column.value(row, rowIndex)),\n ),\n ]);\n}\n\n/**\n * 将二维数据序列化为 CSV 文本。\n */\nexport function serializeCsvRows(\n rows: readonly (readonly unknown[])[],\n lineBreak = \"\\n\",\n) {\n return rows\n .map((row) => row.map((value) => escapeCsvCell(value)).join(\",\"))\n .join(lineBreak);\n}\n\n/**\n * 生成 TXT 文本内容。\n */\nexport function buildTxtContent<Row>(params: {\n rows: Row[];\n columns: ExportTableColumn<Row>[];\n}) {\n const { rows, columns } = params;\n const header = columns\n .map((column) => normalizeTextCell(column.title))\n .join(\"\\t\");\n const body = rows.map((row, rowIndex) =>\n columns\n .map((column) => normalizeTextCell(column.value(row, rowIndex)))\n .join(\"\\t\"),\n );\n\n return [header, ...body].join(\"\\n\");\n}\n\n/**\n * 下载 JSON 文件。\n */\nexport async function downloadJsonFile(params: {\n fileName: string;\n data: unknown;\n space?: number;\n}) {\n const { data, fileName, space = 2 } = params;\n const content = await buildJsonContentAsync({ data, space });\n downloadTextFile({\n fileName: ensureExtension(fileName, \"json\"),\n content,\n type: \"application/json;charset=utf-8\",\n });\n}\n\n/**\n * 导出表格 CSV 文件。\n */\nexport async function exportTableToCsv<Row>(params: {\n fileName: string;\n rows: Row[];\n columns: ExportTableColumn<Row>[];\n}) {\n const { fileName, rows, columns } = params;\n const content = await buildCsvContentAsync({ rows, columns });\n downloadTextFile({\n fileName: ensureExtension(fileName, \"csv\"),\n content,\n type: \"text/csv;charset=utf-8\",\n });\n}\n\n/**\n * 导出表格 TXT 文件。\n */\nexport async function exportTableToTxt<Row>(params: {\n fileName: string;\n rows: Row[];\n columns: ExportTableColumn<Row>[];\n}) {\n const { fileName, rows, columns } = params;\n const content = await buildTxtContentAsync({ rows, columns });\n downloadTextFile({\n fileName: ensureExtension(fileName, \"txt\"),\n content,\n type: \"text/plain;charset=utf-8\",\n });\n}\n\n/**\n * 导出表格 XLSX 文件。\n */\nexport async function exportTableToXlsx<Row>(params: {\n fileName: string;\n rows: Row[];\n columns: ExportTableColumn<Row>[];\n sheetName?: string;\n}) {\n const { fileName, rows, columns, sheetName = \"Sheet1\" } = params;\n const worksheet = await buildXlsxWorksheet({ rows, columns });\n const workbook = XLSX.utils.book_new();\n XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);\n await yieldToMainThread();\n XLSX.writeFile(workbook, ensureExtension(fileName, \"xlsx\"));\n}\n\n/**\n * 构建适合大数据量导出的 XLSX 工作表。\n */\nasync function buildXlsxWorksheet<Row>(params: {\n rows: Row[];\n columns: ExportTableColumn<Row>[];\n}) {\n const { rows, columns } = params;\n const header = columns.map((column) => column.title);\n const denseOptions = { dense: true } as unknown as XLSX.AOA2SheetOpts;\n const appendOptions = {\n origin: -1,\n dense: true,\n } as unknown as XLSX.SheetAOAOpts;\n const worksheet = XLSX.utils.aoa_to_sheet([header], denseOptions);\n const chunkSize = EXPORT_CHUNK_SIZE;\n\n for (let start = 0; start < rows.length; start += chunkSize) {\n const chunk = rows\n .slice(start, start + chunkSize)\n .map((row, rowIndex) =>\n columns.map((column) =>\n normalizeXlsxCell(column.value(row, start + rowIndex)),\n ),\n );\n\n XLSX.utils.sheet_add_aoa(worksheet, chunk, appendOptions);\n\n await yieldToMainThread();\n }\n\n return worksheet;\n}\n\nasync function buildJsonContentAsync(params: { data: unknown; space: number }) {\n const { data, space } = params;\n if (!Array.isArray(data)) {\n return JSON.stringify(data, null, space) ?? \"\";\n }\n\n if (data.length === 0) {\n return \"[]\";\n }\n\n const lineBreak = space > 0 ? \"\\n\" : \"\";\n const indent = space > 0 ? \" \".repeat(space) : \"\";\n const parts = [\"[\", lineBreak];\n\n for (let start = 0; start < data.length; start += EXPORT_CHUNK_SIZE) {\n const chunk = data.slice(start, start + EXPORT_CHUNK_SIZE);\n for (let index = 0; index < chunk.length; index += 1) {\n const itemIndex = start + index;\n const prefix = itemIndex === 0 ? \"\" : `,${lineBreak}`;\n const content = JSON.stringify(chunk[index], null, space) ?? \"null\";\n parts.push(prefix, indent, content);\n }\n\n await yieldToMainThread();\n }\n\n parts.push(lineBreak, \"]\");\n return parts.join(\"\");\n}\n\nasync function buildCsvContentAsync<Row>(params: {\n rows: Row[];\n columns: ExportTableColumn<Row>[];\n}) {\n const { rows, columns } = params;\n const header = columns.map((column) => escapeCsvCell(column.title)).join(\",\");\n const parts = [header];\n\n for (let start = 0; start < rows.length; start += EXPORT_CHUNK_SIZE) {\n const chunk = rows.slice(start, start + EXPORT_CHUNK_SIZE);\n for (let rowIndex = 0; rowIndex < chunk.length; rowIndex += 1) {\n const row = chunk[rowIndex];\n const line = columns\n .map((column) => escapeCsvCell(column.value(row, start + rowIndex)))\n .join(\",\");\n parts.push(\"\\n\", line);\n }\n\n await yieldToMainThread();\n }\n\n return parts.join(\"\");\n}\n\nasync function buildTxtContentAsync<Row>(params: {\n rows: Row[];\n columns: ExportTableColumn<Row>[];\n}) {\n const { rows, columns } = params;\n const header = columns\n .map((column) => normalizeTextCell(column.title))\n .join(\"\\t\");\n const parts = [header];\n\n for (let start = 0; start < rows.length; start += EXPORT_CHUNK_SIZE) {\n const chunk = rows.slice(start, start + EXPORT_CHUNK_SIZE);\n for (let rowIndex = 0; rowIndex < chunk.length; rowIndex += 1) {\n const row = chunk[rowIndex];\n const line = columns\n .map((column) => normalizeTextCell(column.value(row, start + rowIndex)))\n .join(\"\\t\");\n parts.push(\"\\n\", line);\n }\n\n await yieldToMainThread();\n }\n\n return parts.join(\"\");\n}\n\nfunction escapeCsvCell(value: unknown) {\n const normalized = value == null ? \"\" : String(value);\n if (\n normalized.includes(\",\") ||\n normalized.includes('\"') ||\n normalized.includes(\"\\n\")\n ) {\n return `\"${normalized.split('\"').join('\"\"')}\"`;\n }\n return normalized;\n}\n\nfunction normalizeTextCell(value: unknown) {\n return value == null ? \"\" : String(value);\n}\n\nfunction normalizeXlsxCell(value: unknown) {\n if (value == null) {\n return \"\";\n }\n\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n return value;\n }\n\n if (value instanceof Date) {\n return value;\n }\n\n return String(value);\n}\n\nfunction ensureExtension(fileName: string, extension: string) {\n return fileName.toLowerCase().endsWith(`.${extension}`)\n ? fileName\n : `${fileName}.${extension}`;\n}\n\nfunction yieldToMainThread() {\n return new Promise<void>((resolve) => {\n if (\n typeof window !== \"undefined\" &&\n typeof window.requestAnimationFrame === \"function\"\n ) {\n window.requestAnimationFrame(() => {\n resolve();\n });\n return;\n }\n\n setTimeout(resolve, 0);\n });\n}\n\nfunction downloadTextFile(params: {\n fileName: string;\n content: string;\n type: string;\n}) {\n const { fileName, content, type } = params;\n const blob = new Blob([content], { type });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = fileName;\n anchor.click();\n URL.revokeObjectURL(url);\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/geometry/index.ts
|
|
4
|
+
function clamp(value, minimum, maximum) {
|
|
5
|
+
return Math.min(Math.max(value, minimum), maximum);
|
|
6
|
+
}
|
|
7
|
+
function isPointInRect(x, y, rect) {
|
|
8
|
+
return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
exports.clamp = clamp;
|
|
12
|
+
exports.isPointInRect = isPointInRect;
|
|
13
|
+
//# sourceMappingURL=index.cjs.map
|
|
14
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/geometry/index.ts"],"names":[],"mappings":";;;AAGO,SAAS,KAAA,CAAM,KAAA,EAAe,OAAA,EAAiB,OAAA,EAAiB;AACrE,EAAA,OAAO,KAAK,GAAA,CAAI,IAAA,CAAK,IAAI,KAAA,EAAO,OAAO,GAAG,OAAO,CAAA;AACnD;AAKO,SAAS,aAAA,CACd,CAAA,EACA,CAAA,EACA,IAAA,EACA;AACA,EAAA,OACE,CAAA,IAAK,IAAA,CAAK,CAAA,IACV,CAAA,IAAK,KAAK,CAAA,GAAI,IAAA,CAAK,KAAA,IACnB,CAAA,IAAK,IAAA,CAAK,CAAA,IACV,CAAA,IAAK,IAAA,CAAK,IAAI,IAAA,CAAK,MAAA;AAEvB","file":"index.cjs","sourcesContent":["/**\n * 将数值限制在指定闭区间内。\n */\nexport function clamp(value: number, minimum: number, maximum: number) {\n return Math.min(Math.max(value, minimum), maximum);\n}\n\n/**\n * 判断坐标是否位于矩形范围内,矩形边界视为命中。\n */\nexport function isPointInRect(\n x: number,\n y: number,\n rect: { x: number; y: number; width: number; height: number },\n) {\n return (\n x >= rect.x &&\n x <= rect.x + rect.width &&\n y >= rect.y &&\n y <= rect.y + rect.height\n );\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 将数值限制在指定闭区间内。
|
|
3
|
+
*/
|
|
4
|
+
declare function clamp(value: number, minimum: number, maximum: number): number;
|
|
5
|
+
/**
|
|
6
|
+
* 判断坐标是否位于矩形范围内,矩形边界视为命中。
|
|
7
|
+
*/
|
|
8
|
+
declare function isPointInRect(x: number, y: number, rect: {
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
}): boolean;
|
|
14
|
+
|
|
15
|
+
export { clamp, isPointInRect };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 将数值限制在指定闭区间内。
|
|
3
|
+
*/
|
|
4
|
+
declare function clamp(value: number, minimum: number, maximum: number): number;
|
|
5
|
+
/**
|
|
6
|
+
* 判断坐标是否位于矩形范围内,矩形边界视为命中。
|
|
7
|
+
*/
|
|
8
|
+
declare function isPointInRect(x: number, y: number, rect: {
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
}): boolean;
|
|
14
|
+
|
|
15
|
+
export { clamp, isPointInRect };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// src/geometry/index.ts
|
|
2
|
+
function clamp(value, minimum, maximum) {
|
|
3
|
+
return Math.min(Math.max(value, minimum), maximum);
|
|
4
|
+
}
|
|
5
|
+
function isPointInRect(x, y, rect) {
|
|
6
|
+
return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { clamp, isPointInRect };
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/geometry/index.ts"],"names":[],"mappings":";AAGO,SAAS,KAAA,CAAM,KAAA,EAAe,OAAA,EAAiB,OAAA,EAAiB;AACrE,EAAA,OAAO,KAAK,GAAA,CAAI,IAAA,CAAK,IAAI,KAAA,EAAO,OAAO,GAAG,OAAO,CAAA;AACnD;AAKO,SAAS,aAAA,CACd,CAAA,EACA,CAAA,EACA,IAAA,EACA;AACA,EAAA,OACE,CAAA,IAAK,IAAA,CAAK,CAAA,IACV,CAAA,IAAK,KAAK,CAAA,GAAI,IAAA,CAAK,KAAA,IACnB,CAAA,IAAK,IAAA,CAAK,CAAA,IACV,CAAA,IAAK,IAAA,CAAK,IAAI,IAAA,CAAK,MAAA;AAEvB","file":"index.js","sourcesContent":["/**\n * 将数值限制在指定闭区间内。\n */\nexport function clamp(value: number, minimum: number, maximum: number) {\n return Math.min(Math.max(value, minimum), maximum);\n}\n\n/**\n * 判断坐标是否位于矩形范围内,矩形边界视为命中。\n */\nexport function isPointInRect(\n x: number,\n y: number,\n rect: { x: number; y: number; width: number; height: number },\n) {\n return (\n x >= rect.x &&\n x <= rect.x + rect.width &&\n y >= rect.y &&\n y <= rect.y + rect.height\n );\n}\n"]}
|