@canvas-components/utils 0.2.0 → 0.2.1
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 +23 -5
- 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/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 +59 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +54 -18
- package/dist/index.js.map +1 -1
- package/package.json +11 -1
package/README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# @canvas-components/utils
|
|
2
2
|
|
|
3
|
-
`@canvas-components/utils`
|
|
3
|
+
`@canvas-components/utils` 提供表格包之间可复用的纯原生工具能力,覆盖数据读取、剪贴板写入和导出文件。
|
|
4
4
|
|
|
5
5
|
## 功能作用
|
|
6
6
|
|
|
7
|
-
- 写入文本、二维表格文本、JSON 到系统剪贴板
|
|
7
|
+
- 写入文本、二维表格文本、JSON 到系统剪贴板
|
|
8
|
+
- 通过 `dataIndex` 安全读取嵌套数据
|
|
9
|
+
- 复用数据路径比较、数值约束和矩形命中等纯函数
|
|
8
10
|
- 把行列数据导出为 `csv`、`txt`、`xlsx`
|
|
9
11
|
- 生成导出前的中间文本 / 记录结构
|
|
10
12
|
- 对大批量导出做分片让步,减少主线程长时间阻塞
|
|
@@ -76,17 +78,33 @@ type ClipboardCellValue = string | number | boolean | null | undefined;
|
|
|
76
78
|
| `copyJson` | `(value: unknown, space = 2) => Promise<void>` | 写入 JSON 文本 |
|
|
77
79
|
| `formatRowsForClipboard` | `(rows) => string` | 把二维数据转成制表符文本 |
|
|
78
80
|
|
|
79
|
-
### 导出
|
|
81
|
+
### 导出
|
|
80
82
|
|
|
81
83
|
| 方法 | 签名 | 说明 |
|
|
82
84
|
| --- | --- | --- |
|
|
83
85
|
| `mapRowsToExportRecords` | `({ rows, columns }) => Record<string, unknown>[]` | 生成导出记录数组 |
|
|
84
|
-
| `buildCsvContent` | `({ rows, columns }) => string` | 生成 CSV 文本 |
|
|
86
|
+
| `buildCsvContent` | `({ rows, columns }) => string` | 生成 CSV 文本 |
|
|
87
|
+
| `serializeCsvRows` | `(rows, lineBreak?) => string` | 将二维数据序列化为 CSV 文本 |
|
|
85
88
|
| `buildTxtContent` | `({ rows, columns }) => string` | 生成 TXT 文本 |
|
|
86
89
|
| `downloadJsonFile` | `({ fileName, data, space? }) => Promise<void>` | 下载 JSON |
|
|
87
90
|
| `exportTableToCsv` | `({ fileName, rows, columns }) => Promise<void>` | 导出 CSV |
|
|
88
91
|
| `exportTableToTxt` | `({ fileName, rows, columns }) => Promise<void>` | 导出 TXT |
|
|
89
|
-
| `exportTableToXlsx` | `({ fileName, rows, columns, sheetName? }) => Promise<void>` | 导出 XLSX |
|
|
92
|
+
| `exportTableToXlsx` | `({ fileName, rows, columns, sheetName? }) => Promise<void>` | 导出 XLSX |
|
|
93
|
+
|
|
94
|
+
### 数据读取
|
|
95
|
+
|
|
96
|
+
| 方法 | 签名 | 说明 |
|
|
97
|
+
| --- | --- | --- |
|
|
98
|
+
| `getValueByDataIndex` | `(source, dataIndex?) => unknown` | 通过字符串、数字或属性路径数组安全读取嵌套值 |
|
|
99
|
+
| `stringifyDataIndex` | `(dataIndex) => string` | 将属性路径转换为稳定字符串 |
|
|
100
|
+
| `isSameDataIndex` | `(left, right) => boolean` | 判断两个属性路径是否一致 |
|
|
101
|
+
|
|
102
|
+
### 基础几何
|
|
103
|
+
|
|
104
|
+
| 方法 | 签名 | 说明 |
|
|
105
|
+
| --- | --- | --- |
|
|
106
|
+
| `clamp` | `(value, minimum, maximum) => number` | 将数值限制在闭区间内 |
|
|
107
|
+
| `isPointInRect` | `(x, y, rect) => boolean` | 判断坐标是否位于矩形内 |
|
|
90
108
|
|
|
91
109
|
## 适用场景
|
|
92
110
|
|
package/dist/clipboard/index.cjs
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
// src/clipboard/index.ts
|
|
4
|
-
async function copyText(text) {
|
|
4
|
+
async function copyText(text, ownerDocument = document) {
|
|
5
|
+
const clipboard = ownerDocument.defaultView?.navigator.clipboard;
|
|
5
6
|
try {
|
|
6
|
-
if (
|
|
7
|
-
await
|
|
8
|
-
return;
|
|
7
|
+
if (clipboard?.writeText) {
|
|
8
|
+
await clipboard.writeText(text);
|
|
9
|
+
return true;
|
|
9
10
|
}
|
|
10
11
|
} catch {
|
|
11
12
|
}
|
|
12
|
-
copyTextSync(text);
|
|
13
|
+
return copyTextSync(text, ownerDocument);
|
|
13
14
|
}
|
|
14
15
|
function copyTextSync(text, ownerDocument = document) {
|
|
15
16
|
const activeElement = ownerDocument.activeElement;
|
|
@@ -27,6 +28,8 @@ function copyTextSync(text, ownerDocument = document) {
|
|
|
27
28
|
let copied = false;
|
|
28
29
|
try {
|
|
29
30
|
copied = ownerDocument.execCommand?.("copy") ?? false;
|
|
31
|
+
} catch {
|
|
32
|
+
copied = false;
|
|
30
33
|
} finally {
|
|
31
34
|
textarea.remove();
|
|
32
35
|
const HTMLElementConstructor = ownerDocument.defaultView?.HTMLElement;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/clipboard/index.ts"],"names":[],"mappings":";;;AAKA,eAAsB,
|
|
1
|
+
{"version":3,"sources":["../../src/clipboard/index.ts"],"names":[],"mappings":";;;AAKA,eAAsB,QAAA,CAAS,IAAA,EAAc,aAAA,GAAgB,QAAA,EAAU;AACrE,EAAA,MAAM,SAAA,GAAY,aAAA,CAAc,WAAA,EAAa,SAAA,CAAU,SAAA;AACvD,EAAA,IAAI;AACF,IAAA,IAAI,WAAW,SAAA,EAAW;AACxB,MAAA,MAAM,SAAA,CAAU,UAAU,IAAI,CAAA;AAC9B,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AAEA,EAAA,OAAO,YAAA,CAAa,MAAM,aAAa,CAAA;AACzC;AAGO,SAAS,YAAA,CAAa,IAAA,EAAc,aAAA,GAAgB,QAAA,EAAU;AACnE,EAAA,MAAM,gBAAgB,aAAA,CAAc,aAAA;AACpC,EAAA,MAAM,QAAA,GAAW,aAAA,CAAc,aAAA,CAAc,UAAU,CAAA;AACvD,EAAA,QAAA,CAAS,KAAA,GAAQ,IAAA;AACjB,EAAA,QAAA,CAAS,YAAA,CAAa,YAAY,MAAM,CAAA;AACxC,EAAA,QAAA,CAAS,MAAM,QAAA,GAAW,OAAA;AAC1B,EAAA,QAAA,CAAS,MAAM,IAAA,GAAO,SAAA;AACtB,EAAA,QAAA,CAAS,MAAM,GAAA,GAAM,GAAA;AACrB,EAAA,QAAA,CAAS,MAAM,OAAA,GAAU,GAAA;AAEzB,EAAA,aAAA,CAAc,IAAA,CAAK,YAAY,QAAQ,CAAA;AACvC,EAAA,QAAA,CAAS,KAAA,CAAM,EAAE,aAAA,EAAe,IAAA,EAAM,CAAA;AACtC,EAAA,QAAA,CAAS,MAAA,EAAO;AAChB,EAAA,QAAA,CAAS,iBAAA,CAAkB,CAAA,EAAG,QAAA,CAAS,KAAA,CAAM,MAAM,CAAA;AAEnD,EAAA,IAAI,MAAA,GAAS,KAAA;AACb,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,aAAA,CAAc,WAAA,GAAc,MAAM,CAAA,IAAK,KAAA;AAAA,EAClD,CAAA,CAAA,MAAQ;AACN,IAAA,MAAA,GAAS,KAAA;AAAA,EACX,CAAA,SAAE;AACA,IAAA,QAAA,CAAS,MAAA,EAAO;AAChB,IAAA,MAAM,sBAAA,GAAyB,cAAc,WAAA,EAAa,WAAA;AAC1D,IAAA,IACE,sBAAA,IACA,yBAAyB,sBAAA,EACzB;AACA,MAAA,aAAA,CAAc,KAAA,CAAM,EAAE,aAAA,EAAe,IAAA,EAAM,CAAA;AAAA,IAC7C;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AAKA,eAAsB,SAAS,IAAA,EAA8B;AAC3D,EAAA,MAAM,QAAA,CAAS,sBAAA,CAAuB,IAAI,CAAC,CAAA;AAC7C;AAKA,eAAsB,QAAA,CAAS,KAAA,EAAgB,KAAA,GAAQ,CAAA,EAAG;AACxD,EAAA,MAAM,SAAS,IAAA,CAAK,SAAA,CAAU,OAAO,IAAA,EAAM,KAAK,KAAK,EAAE,CAAA;AACzD;AAKO,SAAS,uBAAuB,IAAA,EAA8B;AACnE,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,KAAQ,GAAA,CAAI,GAAA,CAAI,mBAAmB,CAAA,CAAE,IAAA,CAAK,GAAI,CAAC,CAAA,CAAE,KAAK,IAAI,CAAA;AAC7E;AAEA,SAAS,oBAAoB,KAAA,EAA2B;AACtD,EAAA,IAAI,SAAS,IAAA,EAAM;AACjB,IAAA,OAAO,EAAA;AAAA,EACT;AAEA,EAAA,OAAO,OAAO,KAAK,CAAA;AACrB","file":"index.cjs","sourcesContent":["export type ClipboardCellValue = string | number | boolean | null | undefined;\n\n/**\n * 写入纯文本到系统剪贴板。\n */\nexport async function copyText(text: string, ownerDocument = document) {\n const clipboard = ownerDocument.defaultView?.navigator.clipboard;\n try {\n if (clipboard?.writeText) {\n await clipboard.writeText(text);\n return true;\n }\n } catch {\n // 非安全上下文或权限拒绝时回退到同步 DOM 复制。\n }\n\n return copyTextSync(text, ownerDocument);\n}\n\n/** 在当前用户激活事件中同步复制纯文本。 */\nexport function copyTextSync(text: string, ownerDocument = document) {\n const activeElement = ownerDocument.activeElement;\n const textarea = ownerDocument.createElement(\"textarea\");\n textarea.value = text;\n textarea.setAttribute(\"readonly\", \"true\");\n textarea.style.position = \"fixed\";\n textarea.style.left = \"-9999px\";\n textarea.style.top = \"0\";\n textarea.style.opacity = \"0\";\n\n ownerDocument.body.appendChild(textarea);\n textarea.focus({ preventScroll: true });\n textarea.select();\n textarea.setSelectionRange(0, textarea.value.length);\n\n let copied = false;\n try {\n copied = ownerDocument.execCommand?.(\"copy\") ?? false;\n } catch {\n copied = false;\n } finally {\n textarea.remove();\n const HTMLElementConstructor = ownerDocument.defaultView?.HTMLElement;\n if (\n HTMLElementConstructor &&\n activeElement instanceof HTMLElementConstructor\n ) {\n activeElement.focus({ preventScroll: true });\n }\n }\n return copied;\n}\n\n/**\n * 写入二维表格文本到系统剪贴板。\n */\nexport async function copyRows(rows: ClipboardCellValue[][]) {\n await copyText(formatRowsForClipboard(rows));\n}\n\n/**\n * 写入 JSON 文本到系统剪贴板。\n */\nexport async function copyJson(value: unknown, space = 2) {\n await copyText(JSON.stringify(value, null, space) ?? \"\");\n}\n\n/**\n * 格式化二维数据为剪贴板友好的文本。\n */\nexport function formatRowsForClipboard(rows: ClipboardCellValue[][]) {\n return rows.map((row) => row.map(formatClipboardCell).join(\"\\t\")).join(\"\\n\");\n}\n\nfunction formatClipboardCell(value: ClipboardCellValue) {\n if (value == null) {\n return \"\";\n }\n\n return String(value);\n}\n"]}
|
|
@@ -2,7 +2,7 @@ type ClipboardCellValue = string | number | boolean | null | undefined;
|
|
|
2
2
|
/**
|
|
3
3
|
* 写入纯文本到系统剪贴板。
|
|
4
4
|
*/
|
|
5
|
-
declare function copyText(text: string): Promise<
|
|
5
|
+
declare function copyText(text: string, ownerDocument?: Document): Promise<boolean>;
|
|
6
6
|
/** 在当前用户激活事件中同步复制纯文本。 */
|
|
7
7
|
declare function copyTextSync(text: string, ownerDocument?: Document): boolean;
|
|
8
8
|
/**
|
|
@@ -2,7 +2,7 @@ type ClipboardCellValue = string | number | boolean | null | undefined;
|
|
|
2
2
|
/**
|
|
3
3
|
* 写入纯文本到系统剪贴板。
|
|
4
4
|
*/
|
|
5
|
-
declare function copyText(text: string): Promise<
|
|
5
|
+
declare function copyText(text: string, ownerDocument?: Document): Promise<boolean>;
|
|
6
6
|
/** 在当前用户激活事件中同步复制纯文本。 */
|
|
7
7
|
declare function copyTextSync(text: string, ownerDocument?: Document): boolean;
|
|
8
8
|
/**
|
package/dist/clipboard/index.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
// src/clipboard/index.ts
|
|
2
|
-
async function copyText(text) {
|
|
2
|
+
async function copyText(text, ownerDocument = document) {
|
|
3
|
+
const clipboard = ownerDocument.defaultView?.navigator.clipboard;
|
|
3
4
|
try {
|
|
4
|
-
if (
|
|
5
|
-
await
|
|
6
|
-
return;
|
|
5
|
+
if (clipboard?.writeText) {
|
|
6
|
+
await clipboard.writeText(text);
|
|
7
|
+
return true;
|
|
7
8
|
}
|
|
8
9
|
} catch {
|
|
9
10
|
}
|
|
10
|
-
copyTextSync(text);
|
|
11
|
+
return copyTextSync(text, ownerDocument);
|
|
11
12
|
}
|
|
12
13
|
function copyTextSync(text, ownerDocument = document) {
|
|
13
14
|
const activeElement = ownerDocument.activeElement;
|
|
@@ -25,6 +26,8 @@ function copyTextSync(text, ownerDocument = document) {
|
|
|
25
26
|
let copied = false;
|
|
26
27
|
try {
|
|
27
28
|
copied = ownerDocument.execCommand?.("copy") ?? false;
|
|
29
|
+
} catch {
|
|
30
|
+
copied = false;
|
|
28
31
|
} finally {
|
|
29
32
|
textarea.remove();
|
|
30
33
|
const HTMLElementConstructor = ownerDocument.defaultView?.HTMLElement;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/clipboard/index.ts"],"names":[],"mappings":";AAKA,eAAsB,
|
|
1
|
+
{"version":3,"sources":["../../src/clipboard/index.ts"],"names":[],"mappings":";AAKA,eAAsB,QAAA,CAAS,IAAA,EAAc,aAAA,GAAgB,QAAA,EAAU;AACrE,EAAA,MAAM,SAAA,GAAY,aAAA,CAAc,WAAA,EAAa,SAAA,CAAU,SAAA;AACvD,EAAA,IAAI;AACF,IAAA,IAAI,WAAW,SAAA,EAAW;AACxB,MAAA,MAAM,SAAA,CAAU,UAAU,IAAI,CAAA;AAC9B,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AAEA,EAAA,OAAO,YAAA,CAAa,MAAM,aAAa,CAAA;AACzC;AAGO,SAAS,YAAA,CAAa,IAAA,EAAc,aAAA,GAAgB,QAAA,EAAU;AACnE,EAAA,MAAM,gBAAgB,aAAA,CAAc,aAAA;AACpC,EAAA,MAAM,QAAA,GAAW,aAAA,CAAc,aAAA,CAAc,UAAU,CAAA;AACvD,EAAA,QAAA,CAAS,KAAA,GAAQ,IAAA;AACjB,EAAA,QAAA,CAAS,YAAA,CAAa,YAAY,MAAM,CAAA;AACxC,EAAA,QAAA,CAAS,MAAM,QAAA,GAAW,OAAA;AAC1B,EAAA,QAAA,CAAS,MAAM,IAAA,GAAO,SAAA;AACtB,EAAA,QAAA,CAAS,MAAM,GAAA,GAAM,GAAA;AACrB,EAAA,QAAA,CAAS,MAAM,OAAA,GAAU,GAAA;AAEzB,EAAA,aAAA,CAAc,IAAA,CAAK,YAAY,QAAQ,CAAA;AACvC,EAAA,QAAA,CAAS,KAAA,CAAM,EAAE,aAAA,EAAe,IAAA,EAAM,CAAA;AACtC,EAAA,QAAA,CAAS,MAAA,EAAO;AAChB,EAAA,QAAA,CAAS,iBAAA,CAAkB,CAAA,EAAG,QAAA,CAAS,KAAA,CAAM,MAAM,CAAA;AAEnD,EAAA,IAAI,MAAA,GAAS,KAAA;AACb,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,aAAA,CAAc,WAAA,GAAc,MAAM,CAAA,IAAK,KAAA;AAAA,EAClD,CAAA,CAAA,MAAQ;AACN,IAAA,MAAA,GAAS,KAAA;AAAA,EACX,CAAA,SAAE;AACA,IAAA,QAAA,CAAS,MAAA,EAAO;AAChB,IAAA,MAAM,sBAAA,GAAyB,cAAc,WAAA,EAAa,WAAA;AAC1D,IAAA,IACE,sBAAA,IACA,yBAAyB,sBAAA,EACzB;AACA,MAAA,aAAA,CAAc,KAAA,CAAM,EAAE,aAAA,EAAe,IAAA,EAAM,CAAA;AAAA,IAC7C;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AAKA,eAAsB,SAAS,IAAA,EAA8B;AAC3D,EAAA,MAAM,QAAA,CAAS,sBAAA,CAAuB,IAAI,CAAC,CAAA;AAC7C;AAKA,eAAsB,QAAA,CAAS,KAAA,EAAgB,KAAA,GAAQ,CAAA,EAAG;AACxD,EAAA,MAAM,SAAS,IAAA,CAAK,SAAA,CAAU,OAAO,IAAA,EAAM,KAAK,KAAK,EAAE,CAAA;AACzD;AAKO,SAAS,uBAAuB,IAAA,EAA8B;AACnE,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,KAAQ,GAAA,CAAI,GAAA,CAAI,mBAAmB,CAAA,CAAE,IAAA,CAAK,GAAI,CAAC,CAAA,CAAE,KAAK,IAAI,CAAA;AAC7E;AAEA,SAAS,oBAAoB,KAAA,EAA2B;AACtD,EAAA,IAAI,SAAS,IAAA,EAAM;AACjB,IAAA,OAAO,EAAA;AAAA,EACT;AAEA,EAAA,OAAO,OAAO,KAAK,CAAA;AACrB","file":"index.js","sourcesContent":["export type ClipboardCellValue = string | number | boolean | null | undefined;\n\n/**\n * 写入纯文本到系统剪贴板。\n */\nexport async function copyText(text: string, ownerDocument = document) {\n const clipboard = ownerDocument.defaultView?.navigator.clipboard;\n try {\n if (clipboard?.writeText) {\n await clipboard.writeText(text);\n return true;\n }\n } catch {\n // 非安全上下文或权限拒绝时回退到同步 DOM 复制。\n }\n\n return copyTextSync(text, ownerDocument);\n}\n\n/** 在当前用户激活事件中同步复制纯文本。 */\nexport function copyTextSync(text: string, ownerDocument = document) {\n const activeElement = ownerDocument.activeElement;\n const textarea = ownerDocument.createElement(\"textarea\");\n textarea.value = text;\n textarea.setAttribute(\"readonly\", \"true\");\n textarea.style.position = \"fixed\";\n textarea.style.left = \"-9999px\";\n textarea.style.top = \"0\";\n textarea.style.opacity = \"0\";\n\n ownerDocument.body.appendChild(textarea);\n textarea.focus({ preventScroll: true });\n textarea.select();\n textarea.setSelectionRange(0, textarea.value.length);\n\n let copied = false;\n try {\n copied = ownerDocument.execCommand?.(\"copy\") ?? false;\n } catch {\n copied = false;\n } finally {\n textarea.remove();\n const HTMLElementConstructor = ownerDocument.defaultView?.HTMLElement;\n if (\n HTMLElementConstructor &&\n activeElement instanceof HTMLElementConstructor\n ) {\n activeElement.focus({ preventScroll: true });\n }\n }\n return copied;\n}\n\n/**\n * 写入二维表格文本到系统剪贴板。\n */\nexport async function copyRows(rows: ClipboardCellValue[][]) {\n await copyText(formatRowsForClipboard(rows));\n}\n\n/**\n * 写入 JSON 文本到系统剪贴板。\n */\nexport async function copyJson(value: unknown, space = 2) {\n await copyText(JSON.stringify(value, null, space) ?? \"\");\n}\n\n/**\n * 格式化二维数据为剪贴板友好的文本。\n */\nexport function formatRowsForClipboard(rows: ClipboardCellValue[][]) {\n return rows.map((row) => row.map(formatClipboardCell).join(\"\\t\")).join(\"\\n\");\n}\n\nfunction formatClipboardCell(value: ClipboardCellValue) {\n if (value == null) {\n return \"\";\n }\n\n return String(value);\n}\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/data/index.ts
|
|
4
|
+
function stringifyDataIndex(dataIndex) {
|
|
5
|
+
return (Array.isArray(dataIndex) ? dataIndex : [dataIndex]).map((item) => String(item)).join(".");
|
|
6
|
+
}
|
|
7
|
+
function isSameDataIndex(left, right) {
|
|
8
|
+
const leftPath = Array.isArray(left) ? left : [left];
|
|
9
|
+
const rightPath = Array.isArray(right) ? right : [right];
|
|
10
|
+
return leftPath.length === rightPath.length && leftPath.every((key, index) => key === rightPath[index]);
|
|
11
|
+
}
|
|
12
|
+
function getValueByDataIndex(source, dataIndex) {
|
|
13
|
+
if (dataIndex == null) {
|
|
14
|
+
return void 0;
|
|
15
|
+
}
|
|
16
|
+
const path = Array.isArray(dataIndex) ? dataIndex : [dataIndex];
|
|
17
|
+
let current = source;
|
|
18
|
+
for (const key of path) {
|
|
19
|
+
if (current == null || typeof current !== "object" && typeof current !== "function") {
|
|
20
|
+
return void 0;
|
|
21
|
+
}
|
|
22
|
+
current = current[key];
|
|
23
|
+
}
|
|
24
|
+
return current;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
exports.getValueByDataIndex = getValueByDataIndex;
|
|
28
|
+
exports.isSameDataIndex = isSameDataIndex;
|
|
29
|
+
exports.stringifyDataIndex = stringifyDataIndex;
|
|
30
|
+
//# sourceMappingURL=index.cjs.map
|
|
31
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/data/index.ts"],"names":[],"mappings":";;;AAQO,SAAS,mBAAmB,SAAA,EAA2B;AAC5D,EAAA,OAAA,CAAQ,MAAM,OAAA,CAAQ,SAAS,CAAA,GAAI,SAAA,GAAY,CAAC,SAAS,CAAA,EACtD,GAAA,CAAI,CAAC,SAAS,MAAA,CAAO,IAAI,CAAC,CAAA,CAC1B,KAAK,GAAG,CAAA;AACb;AAKO,SAAS,eAAA,CAAgB,MAAsB,KAAA,EAAuB;AAC3E,EAAA,MAAM,WAAW,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,GAAI,IAAA,GAAO,CAAC,IAAI,CAAA;AACnD,EAAA,MAAM,YAAY,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,GAAI,KAAA,GAAQ,CAAC,KAAK,CAAA;AACvD,EAAA,OACE,QAAA,CAAS,MAAA,KAAW,SAAA,CAAU,MAAA,IAC9B,QAAA,CAAS,KAAA,CAAM,CAAC,GAAA,EAAK,KAAA,KAAU,GAAA,KAAQ,SAAA,CAAU,KAAK,CAAC,CAAA;AAE3D;AASO,SAAS,mBAAA,CACd,QACA,SAAA,EACA;AACA,EAAA,IAAI,aAAa,IAAA,EAAM;AACrB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAO,KAAA,CAAM,OAAA,CAAQ,SAAS,CAAA,GAAI,SAAA,GAAY,CAAC,SAAS,CAAA;AAC9D,EAAA,IAAI,OAAA,GAAmB,MAAA;AAEvB,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,IACE,WAAW,IAAA,IACV,OAAO,YAAY,QAAA,IAAY,OAAO,YAAY,UAAA,EACnD;AACA,MAAA,OAAO,MAAA;AAAA,IACT;AACA,IAAA,OAAA,GAAW,QAA6C,GAAG,CAAA;AAAA,EAC7D;AAEA,EAAA,OAAO,OAAA;AACT","file":"index.cjs","sourcesContent":["/**\n * 支持对象属性路径的数据索引。\n */\nexport type ValueDataIndex = string | number | Array<string | number>;\n\n/**\n * 将 dataIndex 转换为稳定字符串。\n */\nexport function stringifyDataIndex(dataIndex: ValueDataIndex) {\n return (Array.isArray(dataIndex) ? dataIndex : [dataIndex])\n .map((item) => String(item))\n .join(\".\");\n}\n\n/**\n * 判断两个 dataIndex 是否指向相同属性路径。\n */\nexport function isSameDataIndex(left: ValueDataIndex, right: ValueDataIndex) {\n const leftPath = Array.isArray(left) ? left : [left];\n const rightPath = Array.isArray(right) ? right : [right];\n return (\n leftPath.length === rightPath.length &&\n leftPath.every((key, index) => key === rightPath[index])\n );\n}\n\n/**\n * 通过 dataIndex 安全读取值。\n *\n * @param source 数据记录。\n * @param dataIndex 属性路径。\n * @returns 读取结果。\n */\nexport function getValueByDataIndex(\n source: unknown,\n dataIndex?: ValueDataIndex,\n) {\n if (dataIndex == null) {\n return undefined;\n }\n\n const path = Array.isArray(dataIndex) ? dataIndex : [dataIndex];\n let current: unknown = source;\n\n for (const key of path) {\n if (\n current == null ||\n (typeof current !== \"object\" && typeof current !== \"function\")\n ) {\n return undefined;\n }\n current = (current as Record<string | number, unknown>)[key];\n }\n\n return current;\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 支持对象属性路径的数据索引。
|
|
3
|
+
*/
|
|
4
|
+
type ValueDataIndex = string | number | Array<string | number>;
|
|
5
|
+
/**
|
|
6
|
+
* 将 dataIndex 转换为稳定字符串。
|
|
7
|
+
*/
|
|
8
|
+
declare function stringifyDataIndex(dataIndex: ValueDataIndex): string;
|
|
9
|
+
/**
|
|
10
|
+
* 判断两个 dataIndex 是否指向相同属性路径。
|
|
11
|
+
*/
|
|
12
|
+
declare function isSameDataIndex(left: ValueDataIndex, right: ValueDataIndex): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* 通过 dataIndex 安全读取值。
|
|
15
|
+
*
|
|
16
|
+
* @param source 数据记录。
|
|
17
|
+
* @param dataIndex 属性路径。
|
|
18
|
+
* @returns 读取结果。
|
|
19
|
+
*/
|
|
20
|
+
declare function getValueByDataIndex(source: unknown, dataIndex?: ValueDataIndex): unknown;
|
|
21
|
+
|
|
22
|
+
export { type ValueDataIndex, getValueByDataIndex, isSameDataIndex, stringifyDataIndex };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 支持对象属性路径的数据索引。
|
|
3
|
+
*/
|
|
4
|
+
type ValueDataIndex = string | number | Array<string | number>;
|
|
5
|
+
/**
|
|
6
|
+
* 将 dataIndex 转换为稳定字符串。
|
|
7
|
+
*/
|
|
8
|
+
declare function stringifyDataIndex(dataIndex: ValueDataIndex): string;
|
|
9
|
+
/**
|
|
10
|
+
* 判断两个 dataIndex 是否指向相同属性路径。
|
|
11
|
+
*/
|
|
12
|
+
declare function isSameDataIndex(left: ValueDataIndex, right: ValueDataIndex): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* 通过 dataIndex 安全读取值。
|
|
15
|
+
*
|
|
16
|
+
* @param source 数据记录。
|
|
17
|
+
* @param dataIndex 属性路径。
|
|
18
|
+
* @returns 读取结果。
|
|
19
|
+
*/
|
|
20
|
+
declare function getValueByDataIndex(source: unknown, dataIndex?: ValueDataIndex): unknown;
|
|
21
|
+
|
|
22
|
+
export { type ValueDataIndex, getValueByDataIndex, isSameDataIndex, stringifyDataIndex };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// src/data/index.ts
|
|
2
|
+
function stringifyDataIndex(dataIndex) {
|
|
3
|
+
return (Array.isArray(dataIndex) ? dataIndex : [dataIndex]).map((item) => String(item)).join(".");
|
|
4
|
+
}
|
|
5
|
+
function isSameDataIndex(left, right) {
|
|
6
|
+
const leftPath = Array.isArray(left) ? left : [left];
|
|
7
|
+
const rightPath = Array.isArray(right) ? right : [right];
|
|
8
|
+
return leftPath.length === rightPath.length && leftPath.every((key, index) => key === rightPath[index]);
|
|
9
|
+
}
|
|
10
|
+
function getValueByDataIndex(source, dataIndex) {
|
|
11
|
+
if (dataIndex == null) {
|
|
12
|
+
return void 0;
|
|
13
|
+
}
|
|
14
|
+
const path = Array.isArray(dataIndex) ? dataIndex : [dataIndex];
|
|
15
|
+
let current = source;
|
|
16
|
+
for (const key of path) {
|
|
17
|
+
if (current == null || typeof current !== "object" && typeof current !== "function") {
|
|
18
|
+
return void 0;
|
|
19
|
+
}
|
|
20
|
+
current = current[key];
|
|
21
|
+
}
|
|
22
|
+
return current;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { getValueByDataIndex, isSameDataIndex, stringifyDataIndex };
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/data/index.ts"],"names":[],"mappings":";AAQO,SAAS,mBAAmB,SAAA,EAA2B;AAC5D,EAAA,OAAA,CAAQ,MAAM,OAAA,CAAQ,SAAS,CAAA,GAAI,SAAA,GAAY,CAAC,SAAS,CAAA,EACtD,GAAA,CAAI,CAAC,SAAS,MAAA,CAAO,IAAI,CAAC,CAAA,CAC1B,KAAK,GAAG,CAAA;AACb;AAKO,SAAS,eAAA,CAAgB,MAAsB,KAAA,EAAuB;AAC3E,EAAA,MAAM,WAAW,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,GAAI,IAAA,GAAO,CAAC,IAAI,CAAA;AACnD,EAAA,MAAM,YAAY,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,GAAI,KAAA,GAAQ,CAAC,KAAK,CAAA;AACvD,EAAA,OACE,QAAA,CAAS,MAAA,KAAW,SAAA,CAAU,MAAA,IAC9B,QAAA,CAAS,KAAA,CAAM,CAAC,GAAA,EAAK,KAAA,KAAU,GAAA,KAAQ,SAAA,CAAU,KAAK,CAAC,CAAA;AAE3D;AASO,SAAS,mBAAA,CACd,QACA,SAAA,EACA;AACA,EAAA,IAAI,aAAa,IAAA,EAAM;AACrB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAO,KAAA,CAAM,OAAA,CAAQ,SAAS,CAAA,GAAI,SAAA,GAAY,CAAC,SAAS,CAAA;AAC9D,EAAA,IAAI,OAAA,GAAmB,MAAA;AAEvB,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,IACE,WAAW,IAAA,IACV,OAAO,YAAY,QAAA,IAAY,OAAO,YAAY,UAAA,EACnD;AACA,MAAA,OAAO,MAAA;AAAA,IACT;AACA,IAAA,OAAA,GAAW,QAA6C,GAAG,CAAA;AAAA,EAC7D;AAEA,EAAA,OAAO,OAAA;AACT","file":"index.js","sourcesContent":["/**\n * 支持对象属性路径的数据索引。\n */\nexport type ValueDataIndex = string | number | Array<string | number>;\n\n/**\n * 将 dataIndex 转换为稳定字符串。\n */\nexport function stringifyDataIndex(dataIndex: ValueDataIndex) {\n return (Array.isArray(dataIndex) ? dataIndex : [dataIndex])\n .map((item) => String(item))\n .join(\".\");\n}\n\n/**\n * 判断两个 dataIndex 是否指向相同属性路径。\n */\nexport function isSameDataIndex(left: ValueDataIndex, right: ValueDataIndex) {\n const leftPath = Array.isArray(left) ? left : [left];\n const rightPath = Array.isArray(right) ? right : [right];\n return (\n leftPath.length === rightPath.length &&\n leftPath.every((key, index) => key === rightPath[index])\n );\n}\n\n/**\n * 通过 dataIndex 安全读取值。\n *\n * @param source 数据记录。\n * @param dataIndex 属性路径。\n * @returns 读取结果。\n */\nexport function getValueByDataIndex(\n source: unknown,\n dataIndex?: ValueDataIndex,\n) {\n if (dataIndex == null) {\n return undefined;\n }\n\n const path = Array.isArray(dataIndex) ? dataIndex : [dataIndex];\n let current: unknown = source;\n\n for (const key of path) {\n if (\n current == null ||\n (typeof current !== \"object\" && typeof current !== \"function\")\n ) {\n return undefined;\n }\n current = (current as Record<string | number, unknown>)[key];\n }\n\n return current;\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"]}
|
package/dist/index.cjs
CHANGED
|
@@ -23,15 +23,16 @@ function _interopNamespace(e) {
|
|
|
23
23
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
24
24
|
|
|
25
25
|
// src/clipboard/index.ts
|
|
26
|
-
async function copyText(text) {
|
|
26
|
+
async function copyText(text, ownerDocument = document) {
|
|
27
|
+
const clipboard = ownerDocument.defaultView?.navigator.clipboard;
|
|
27
28
|
try {
|
|
28
|
-
if (
|
|
29
|
-
await
|
|
30
|
-
return;
|
|
29
|
+
if (clipboard?.writeText) {
|
|
30
|
+
await clipboard.writeText(text);
|
|
31
|
+
return true;
|
|
31
32
|
}
|
|
32
33
|
} catch {
|
|
33
34
|
}
|
|
34
|
-
copyTextSync(text);
|
|
35
|
+
return copyTextSync(text, ownerDocument);
|
|
35
36
|
}
|
|
36
37
|
function copyTextSync(text, ownerDocument = document) {
|
|
37
38
|
const activeElement = ownerDocument.activeElement;
|
|
@@ -49,6 +50,8 @@ function copyTextSync(text, ownerDocument = document) {
|
|
|
49
50
|
let copied = false;
|
|
50
51
|
try {
|
|
51
52
|
copied = ownerDocument.execCommand?.("copy") ?? false;
|
|
53
|
+
} catch {
|
|
54
|
+
copied = false;
|
|
52
55
|
} finally {
|
|
53
56
|
textarea.remove();
|
|
54
57
|
const HTMLElementConstructor = ownerDocument.defaultView?.HTMLElement;
|
|
@@ -85,11 +88,15 @@ function mapRowsToExportRecords(params) {
|
|
|
85
88
|
}
|
|
86
89
|
function buildCsvContent(params) {
|
|
87
90
|
const { rows, columns } = params;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
return serializeCsvRows([
|
|
92
|
+
columns.map((column) => column.title),
|
|
93
|
+
...rows.map(
|
|
94
|
+
(row, rowIndex) => columns.map((column) => column.value(row, rowIndex))
|
|
95
|
+
)
|
|
96
|
+
]);
|
|
97
|
+
}
|
|
98
|
+
function serializeCsvRows(rows, lineBreak = "\n") {
|
|
99
|
+
return rows.map((row) => row.map((value) => escapeCsvCell(value)).join(",")).join(lineBreak);
|
|
93
100
|
}
|
|
94
101
|
function buildTxtContent(params) {
|
|
95
102
|
const { rows, columns } = params;
|
|
@@ -127,12 +134,7 @@ async function exportTableToTxt(params) {
|
|
|
127
134
|
});
|
|
128
135
|
}
|
|
129
136
|
async function exportTableToXlsx(params) {
|
|
130
|
-
const {
|
|
131
|
-
fileName,
|
|
132
|
-
rows,
|
|
133
|
-
columns,
|
|
134
|
-
sheetName = "Sheet1"
|
|
135
|
-
} = params;
|
|
137
|
+
const { fileName, rows, columns, sheetName = "Sheet1" } = params;
|
|
136
138
|
const worksheet = await buildXlsxWorksheet({ rows, columns });
|
|
137
139
|
const workbook = XLSX__namespace.utils.book_new();
|
|
138
140
|
XLSX__namespace.utils.book_append_sheet(workbook, worksheet, sheetName);
|
|
@@ -151,7 +153,9 @@ async function buildXlsxWorksheet(params) {
|
|
|
151
153
|
const chunkSize = EXPORT_CHUNK_SIZE;
|
|
152
154
|
for (let start = 0; start < rows.length; start += chunkSize) {
|
|
153
155
|
const chunk = rows.slice(start, start + chunkSize).map(
|
|
154
|
-
(row, rowIndex) => columns.map(
|
|
156
|
+
(row, rowIndex) => columns.map(
|
|
157
|
+
(column) => normalizeXlsxCell(column.value(row, start + rowIndex))
|
|
158
|
+
)
|
|
155
159
|
);
|
|
156
160
|
XLSX__namespace.utils.sheet_add_aoa(worksheet, chunk, appendOptions);
|
|
157
161
|
await yieldToMainThread();
|
|
@@ -259,8 +263,41 @@ function downloadTextFile(params) {
|
|
|
259
263
|
URL.revokeObjectURL(url);
|
|
260
264
|
}
|
|
261
265
|
|
|
266
|
+
// src/data/index.ts
|
|
267
|
+
function stringifyDataIndex(dataIndex) {
|
|
268
|
+
return (Array.isArray(dataIndex) ? dataIndex : [dataIndex]).map((item) => String(item)).join(".");
|
|
269
|
+
}
|
|
270
|
+
function isSameDataIndex(left, right) {
|
|
271
|
+
const leftPath = Array.isArray(left) ? left : [left];
|
|
272
|
+
const rightPath = Array.isArray(right) ? right : [right];
|
|
273
|
+
return leftPath.length === rightPath.length && leftPath.every((key, index) => key === rightPath[index]);
|
|
274
|
+
}
|
|
275
|
+
function getValueByDataIndex(source, dataIndex) {
|
|
276
|
+
if (dataIndex == null) {
|
|
277
|
+
return void 0;
|
|
278
|
+
}
|
|
279
|
+
const path = Array.isArray(dataIndex) ? dataIndex : [dataIndex];
|
|
280
|
+
let current = source;
|
|
281
|
+
for (const key of path) {
|
|
282
|
+
if (current == null || typeof current !== "object" && typeof current !== "function") {
|
|
283
|
+
return void 0;
|
|
284
|
+
}
|
|
285
|
+
current = current[key];
|
|
286
|
+
}
|
|
287
|
+
return current;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// src/geometry/index.ts
|
|
291
|
+
function clamp(value, minimum, maximum) {
|
|
292
|
+
return Math.min(Math.max(value, minimum), maximum);
|
|
293
|
+
}
|
|
294
|
+
function isPointInRect(x, y, rect) {
|
|
295
|
+
return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height;
|
|
296
|
+
}
|
|
297
|
+
|
|
262
298
|
exports.buildCsvContent = buildCsvContent;
|
|
263
299
|
exports.buildTxtContent = buildTxtContent;
|
|
300
|
+
exports.clamp = clamp;
|
|
264
301
|
exports.copyJson = copyJson;
|
|
265
302
|
exports.copyRows = copyRows;
|
|
266
303
|
exports.copyText = copyText;
|
|
@@ -270,6 +307,11 @@ exports.exportTableToCsv = exportTableToCsv;
|
|
|
270
307
|
exports.exportTableToTxt = exportTableToTxt;
|
|
271
308
|
exports.exportTableToXlsx = exportTableToXlsx;
|
|
272
309
|
exports.formatRowsForClipboard = formatRowsForClipboard;
|
|
310
|
+
exports.getValueByDataIndex = getValueByDataIndex;
|
|
311
|
+
exports.isPointInRect = isPointInRect;
|
|
312
|
+
exports.isSameDataIndex = isSameDataIndex;
|
|
273
313
|
exports.mapRowsToExportRecords = mapRowsToExportRecords;
|
|
314
|
+
exports.serializeCsvRows = serializeCsvRows;
|
|
315
|
+
exports.stringifyDataIndex = stringifyDataIndex;
|
|
274
316
|
//# sourceMappingURL=index.cjs.map
|
|
275
317
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/clipboard/index.ts","../src/export/index.ts"],"names":["XLSX"],"mappings":"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","file":"index.cjs","sourcesContent":["export type ClipboardCellValue = string | number | boolean | null | undefined;\n\n/**\n * 写入纯文本到系统剪贴板。\n */\nexport async function copyText(text: string) {\n try {\n if (navigator.clipboard?.writeText) {\n await navigator.clipboard.writeText(text);\n return;\n }\n } catch {\n // 非安全上下文或权限拒绝时回退到同步 DOM 复制。\n }\n\n copyTextSync(text);\n}\n\n/** 在当前用户激活事件中同步复制纯文本。 */\nexport function copyTextSync(text: string, ownerDocument = document) {\n const activeElement = ownerDocument.activeElement;\n const textarea = ownerDocument.createElement(\"textarea\");\n textarea.value = text;\n textarea.setAttribute(\"readonly\", \"true\");\n textarea.style.position = \"fixed\";\n textarea.style.left = \"-9999px\";\n textarea.style.top = \"0\";\n textarea.style.opacity = \"0\";\n\n ownerDocument.body.appendChild(textarea);\n textarea.focus({ preventScroll: true });\n textarea.select();\n textarea.setSelectionRange(0, textarea.value.length);\n\n let copied = false;\n try {\n copied = ownerDocument.execCommand?.(\"copy\") ?? false;\n } finally {\n textarea.remove();\n const HTMLElementConstructor = ownerDocument.defaultView?.HTMLElement;\n if (\n HTMLElementConstructor &&\n activeElement instanceof HTMLElementConstructor\n ) {\n activeElement.focus({ preventScroll: true });\n }\n }\n return copied;\n}\n\n/**\n * 写入二维表格文本到系统剪贴板。\n */\nexport async function copyRows(rows: ClipboardCellValue[][]) {\n await copyText(formatRowsForClipboard(rows));\n}\n\n/**\n * 写入 JSON 文本到系统剪贴板。\n */\nexport async function copyJson(value: unknown, space = 2) {\n await copyText(JSON.stringify(value, null, space) ?? \"\");\n}\n\n/**\n * 格式化二维数据为剪贴板友好的文本。\n */\nexport function formatRowsForClipboard(rows: ClipboardCellValue[][]) {\n return rows.map((row) => row.map(formatClipboardCell).join(\"\\t\")).join(\"\\n\");\n}\n\nfunction formatClipboardCell(value: ClipboardCellValue) {\n if (value == null) {\n return \"\";\n }\n\n return String(value);\n}\n","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/clipboard/index.ts","../src/export/index.ts","../src/data/index.ts","../src/geometry/index.ts"],"names":["XLSX"],"mappings":"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","file":"index.cjs","sourcesContent":["export type ClipboardCellValue = string | number | boolean | null | undefined;\n\n/**\n * 写入纯文本到系统剪贴板。\n */\nexport async function copyText(text: string, ownerDocument = document) {\n const clipboard = ownerDocument.defaultView?.navigator.clipboard;\n try {\n if (clipboard?.writeText) {\n await clipboard.writeText(text);\n return true;\n }\n } catch {\n // 非安全上下文或权限拒绝时回退到同步 DOM 复制。\n }\n\n return copyTextSync(text, ownerDocument);\n}\n\n/** 在当前用户激活事件中同步复制纯文本。 */\nexport function copyTextSync(text: string, ownerDocument = document) {\n const activeElement = ownerDocument.activeElement;\n const textarea = ownerDocument.createElement(\"textarea\");\n textarea.value = text;\n textarea.setAttribute(\"readonly\", \"true\");\n textarea.style.position = \"fixed\";\n textarea.style.left = \"-9999px\";\n textarea.style.top = \"0\";\n textarea.style.opacity = \"0\";\n\n ownerDocument.body.appendChild(textarea);\n textarea.focus({ preventScroll: true });\n textarea.select();\n textarea.setSelectionRange(0, textarea.value.length);\n\n let copied = false;\n try {\n copied = ownerDocument.execCommand?.(\"copy\") ?? false;\n } catch {\n copied = false;\n } finally {\n textarea.remove();\n const HTMLElementConstructor = ownerDocument.defaultView?.HTMLElement;\n if (\n HTMLElementConstructor &&\n activeElement instanceof HTMLElementConstructor\n ) {\n activeElement.focus({ preventScroll: true });\n }\n }\n return copied;\n}\n\n/**\n * 写入二维表格文本到系统剪贴板。\n */\nexport async function copyRows(rows: ClipboardCellValue[][]) {\n await copyText(formatRowsForClipboard(rows));\n}\n\n/**\n * 写入 JSON 文本到系统剪贴板。\n */\nexport async function copyJson(value: unknown, space = 2) {\n await copyText(JSON.stringify(value, null, space) ?? \"\");\n}\n\n/**\n * 格式化二维数据为剪贴板友好的文本。\n */\nexport function formatRowsForClipboard(rows: ClipboardCellValue[][]) {\n return rows.map((row) => row.map(formatClipboardCell).join(\"\\t\")).join(\"\\n\");\n}\n\nfunction formatClipboardCell(value: ClipboardCellValue) {\n if (value == null) {\n return \"\";\n }\n\n return String(value);\n}\n","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","/**\n * 支持对象属性路径的数据索引。\n */\nexport type ValueDataIndex = string | number | Array<string | number>;\n\n/**\n * 将 dataIndex 转换为稳定字符串。\n */\nexport function stringifyDataIndex(dataIndex: ValueDataIndex) {\n return (Array.isArray(dataIndex) ? dataIndex : [dataIndex])\n .map((item) => String(item))\n .join(\".\");\n}\n\n/**\n * 判断两个 dataIndex 是否指向相同属性路径。\n */\nexport function isSameDataIndex(left: ValueDataIndex, right: ValueDataIndex) {\n const leftPath = Array.isArray(left) ? left : [left];\n const rightPath = Array.isArray(right) ? right : [right];\n return (\n leftPath.length === rightPath.length &&\n leftPath.every((key, index) => key === rightPath[index])\n );\n}\n\n/**\n * 通过 dataIndex 安全读取值。\n *\n * @param source 数据记录。\n * @param dataIndex 属性路径。\n * @returns 读取结果。\n */\nexport function getValueByDataIndex(\n source: unknown,\n dataIndex?: ValueDataIndex,\n) {\n if (dataIndex == null) {\n return undefined;\n }\n\n const path = Array.isArray(dataIndex) ? dataIndex : [dataIndex];\n let current: unknown = source;\n\n for (const key of path) {\n if (\n current == null ||\n (typeof current !== \"object\" && typeof current !== \"function\")\n ) {\n return undefined;\n }\n current = (current as Record<string | number, unknown>)[key];\n }\n\n return current;\n}\n","/**\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"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
export { ClipboardCellValue, copyJson, copyRows, copyText, copyTextSync, formatRowsForClipboard } from './clipboard/index.cjs';
|
|
2
|
-
export { ExportTableColumn, buildCsvContent, buildTxtContent, downloadJsonFile, exportTableToCsv, exportTableToTxt, exportTableToXlsx, mapRowsToExportRecords } from './export/index.cjs';
|
|
2
|
+
export { ExportTableColumn, buildCsvContent, buildTxtContent, downloadJsonFile, exportTableToCsv, exportTableToTxt, exportTableToXlsx, mapRowsToExportRecords, serializeCsvRows } from './export/index.cjs';
|
|
3
|
+
export { ValueDataIndex, getValueByDataIndex, isSameDataIndex, stringifyDataIndex } from './data/index.cjs';
|
|
4
|
+
export { clamp, isPointInRect } from './geometry/index.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
export { ClipboardCellValue, copyJson, copyRows, copyText, copyTextSync, formatRowsForClipboard } from './clipboard/index.js';
|
|
2
|
-
export { ExportTableColumn, buildCsvContent, buildTxtContent, downloadJsonFile, exportTableToCsv, exportTableToTxt, exportTableToXlsx, mapRowsToExportRecords } from './export/index.js';
|
|
2
|
+
export { ExportTableColumn, buildCsvContent, buildTxtContent, downloadJsonFile, exportTableToCsv, exportTableToTxt, exportTableToXlsx, mapRowsToExportRecords, serializeCsvRows } from './export/index.js';
|
|
3
|
+
export { ValueDataIndex, getValueByDataIndex, isSameDataIndex, stringifyDataIndex } from './data/index.js';
|
|
4
|
+
export { clamp, isPointInRect } from './geometry/index.js';
|
package/dist/index.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import * as XLSX from 'xlsx';
|
|
2
2
|
|
|
3
3
|
// src/clipboard/index.ts
|
|
4
|
-
async function copyText(text) {
|
|
4
|
+
async function copyText(text, ownerDocument = document) {
|
|
5
|
+
const clipboard = ownerDocument.defaultView?.navigator.clipboard;
|
|
5
6
|
try {
|
|
6
|
-
if (
|
|
7
|
-
await
|
|
8
|
-
return;
|
|
7
|
+
if (clipboard?.writeText) {
|
|
8
|
+
await clipboard.writeText(text);
|
|
9
|
+
return true;
|
|
9
10
|
}
|
|
10
11
|
} catch {
|
|
11
12
|
}
|
|
12
|
-
copyTextSync(text);
|
|
13
|
+
return copyTextSync(text, ownerDocument);
|
|
13
14
|
}
|
|
14
15
|
function copyTextSync(text, ownerDocument = document) {
|
|
15
16
|
const activeElement = ownerDocument.activeElement;
|
|
@@ -27,6 +28,8 @@ function copyTextSync(text, ownerDocument = document) {
|
|
|
27
28
|
let copied = false;
|
|
28
29
|
try {
|
|
29
30
|
copied = ownerDocument.execCommand?.("copy") ?? false;
|
|
31
|
+
} catch {
|
|
32
|
+
copied = false;
|
|
30
33
|
} finally {
|
|
31
34
|
textarea.remove();
|
|
32
35
|
const HTMLElementConstructor = ownerDocument.defaultView?.HTMLElement;
|
|
@@ -63,11 +66,15 @@ function mapRowsToExportRecords(params) {
|
|
|
63
66
|
}
|
|
64
67
|
function buildCsvContent(params) {
|
|
65
68
|
const { rows, columns } = params;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
return serializeCsvRows([
|
|
70
|
+
columns.map((column) => column.title),
|
|
71
|
+
...rows.map(
|
|
72
|
+
(row, rowIndex) => columns.map((column) => column.value(row, rowIndex))
|
|
73
|
+
)
|
|
74
|
+
]);
|
|
75
|
+
}
|
|
76
|
+
function serializeCsvRows(rows, lineBreak = "\n") {
|
|
77
|
+
return rows.map((row) => row.map((value) => escapeCsvCell(value)).join(",")).join(lineBreak);
|
|
71
78
|
}
|
|
72
79
|
function buildTxtContent(params) {
|
|
73
80
|
const { rows, columns } = params;
|
|
@@ -105,12 +112,7 @@ async function exportTableToTxt(params) {
|
|
|
105
112
|
});
|
|
106
113
|
}
|
|
107
114
|
async function exportTableToXlsx(params) {
|
|
108
|
-
const {
|
|
109
|
-
fileName,
|
|
110
|
-
rows,
|
|
111
|
-
columns,
|
|
112
|
-
sheetName = "Sheet1"
|
|
113
|
-
} = params;
|
|
115
|
+
const { fileName, rows, columns, sheetName = "Sheet1" } = params;
|
|
114
116
|
const worksheet = await buildXlsxWorksheet({ rows, columns });
|
|
115
117
|
const workbook = XLSX.utils.book_new();
|
|
116
118
|
XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
|
|
@@ -129,7 +131,9 @@ async function buildXlsxWorksheet(params) {
|
|
|
129
131
|
const chunkSize = EXPORT_CHUNK_SIZE;
|
|
130
132
|
for (let start = 0; start < rows.length; start += chunkSize) {
|
|
131
133
|
const chunk = rows.slice(start, start + chunkSize).map(
|
|
132
|
-
(row, rowIndex) => columns.map(
|
|
134
|
+
(row, rowIndex) => columns.map(
|
|
135
|
+
(column) => normalizeXlsxCell(column.value(row, start + rowIndex))
|
|
136
|
+
)
|
|
133
137
|
);
|
|
134
138
|
XLSX.utils.sheet_add_aoa(worksheet, chunk, appendOptions);
|
|
135
139
|
await yieldToMainThread();
|
|
@@ -237,6 +241,38 @@ function downloadTextFile(params) {
|
|
|
237
241
|
URL.revokeObjectURL(url);
|
|
238
242
|
}
|
|
239
243
|
|
|
240
|
-
|
|
244
|
+
// src/data/index.ts
|
|
245
|
+
function stringifyDataIndex(dataIndex) {
|
|
246
|
+
return (Array.isArray(dataIndex) ? dataIndex : [dataIndex]).map((item) => String(item)).join(".");
|
|
247
|
+
}
|
|
248
|
+
function isSameDataIndex(left, right) {
|
|
249
|
+
const leftPath = Array.isArray(left) ? left : [left];
|
|
250
|
+
const rightPath = Array.isArray(right) ? right : [right];
|
|
251
|
+
return leftPath.length === rightPath.length && leftPath.every((key, index) => key === rightPath[index]);
|
|
252
|
+
}
|
|
253
|
+
function getValueByDataIndex(source, dataIndex) {
|
|
254
|
+
if (dataIndex == null) {
|
|
255
|
+
return void 0;
|
|
256
|
+
}
|
|
257
|
+
const path = Array.isArray(dataIndex) ? dataIndex : [dataIndex];
|
|
258
|
+
let current = source;
|
|
259
|
+
for (const key of path) {
|
|
260
|
+
if (current == null || typeof current !== "object" && typeof current !== "function") {
|
|
261
|
+
return void 0;
|
|
262
|
+
}
|
|
263
|
+
current = current[key];
|
|
264
|
+
}
|
|
265
|
+
return current;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// src/geometry/index.ts
|
|
269
|
+
function clamp(value, minimum, maximum) {
|
|
270
|
+
return Math.min(Math.max(value, minimum), maximum);
|
|
271
|
+
}
|
|
272
|
+
function isPointInRect(x, y, rect) {
|
|
273
|
+
return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export { buildCsvContent, buildTxtContent, clamp, copyJson, copyRows, copyText, copyTextSync, downloadJsonFile, exportTableToCsv, exportTableToTxt, exportTableToXlsx, formatRowsForClipboard, getValueByDataIndex, isPointInRect, isSameDataIndex, mapRowsToExportRecords, serializeCsvRows, stringifyDataIndex };
|
|
241
277
|
//# sourceMappingURL=index.js.map
|
|
242
278
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/clipboard/index.ts","../src/export/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export type ClipboardCellValue = string | number | boolean | null | undefined;\n\n/**\n * 写入纯文本到系统剪贴板。\n */\nexport async function copyText(text: string) {\n try {\n if (navigator.clipboard?.writeText) {\n await navigator.clipboard.writeText(text);\n return;\n }\n } catch {\n // 非安全上下文或权限拒绝时回退到同步 DOM 复制。\n }\n\n copyTextSync(text);\n}\n\n/** 在当前用户激活事件中同步复制纯文本。 */\nexport function copyTextSync(text: string, ownerDocument = document) {\n const activeElement = ownerDocument.activeElement;\n const textarea = ownerDocument.createElement(\"textarea\");\n textarea.value = text;\n textarea.setAttribute(\"readonly\", \"true\");\n textarea.style.position = \"fixed\";\n textarea.style.left = \"-9999px\";\n textarea.style.top = \"0\";\n textarea.style.opacity = \"0\";\n\n ownerDocument.body.appendChild(textarea);\n textarea.focus({ preventScroll: true });\n textarea.select();\n textarea.setSelectionRange(0, textarea.value.length);\n\n let copied = false;\n try {\n copied = ownerDocument.execCommand?.(\"copy\") ?? false;\n } finally {\n textarea.remove();\n const HTMLElementConstructor = ownerDocument.defaultView?.HTMLElement;\n if (\n HTMLElementConstructor &&\n activeElement instanceof HTMLElementConstructor\n ) {\n activeElement.focus({ preventScroll: true });\n }\n }\n return copied;\n}\n\n/**\n * 写入二维表格文本到系统剪贴板。\n */\nexport async function copyRows(rows: ClipboardCellValue[][]) {\n await copyText(formatRowsForClipboard(rows));\n}\n\n/**\n * 写入 JSON 文本到系统剪贴板。\n */\nexport async function copyJson(value: unknown, space = 2) {\n await copyText(JSON.stringify(value, null, space) ?? \"\");\n}\n\n/**\n * 格式化二维数据为剪贴板友好的文本。\n */\nexport function formatRowsForClipboard(rows: ClipboardCellValue[][]) {\n return rows.map((row) => row.map(formatClipboardCell).join(\"\\t\")).join(\"\\n\");\n}\n\nfunction formatClipboardCell(value: ClipboardCellValue) {\n if (value == null) {\n return \"\";\n }\n\n return String(value);\n}\n","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/clipboard/index.ts","../src/export/index.ts","../src/data/index.ts","../src/geometry/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export type ClipboardCellValue = string | number | boolean | null | undefined;\n\n/**\n * 写入纯文本到系统剪贴板。\n */\nexport async function copyText(text: string, ownerDocument = document) {\n const clipboard = ownerDocument.defaultView?.navigator.clipboard;\n try {\n if (clipboard?.writeText) {\n await clipboard.writeText(text);\n return true;\n }\n } catch {\n // 非安全上下文或权限拒绝时回退到同步 DOM 复制。\n }\n\n return copyTextSync(text, ownerDocument);\n}\n\n/** 在当前用户激活事件中同步复制纯文本。 */\nexport function copyTextSync(text: string, ownerDocument = document) {\n const activeElement = ownerDocument.activeElement;\n const textarea = ownerDocument.createElement(\"textarea\");\n textarea.value = text;\n textarea.setAttribute(\"readonly\", \"true\");\n textarea.style.position = \"fixed\";\n textarea.style.left = \"-9999px\";\n textarea.style.top = \"0\";\n textarea.style.opacity = \"0\";\n\n ownerDocument.body.appendChild(textarea);\n textarea.focus({ preventScroll: true });\n textarea.select();\n textarea.setSelectionRange(0, textarea.value.length);\n\n let copied = false;\n try {\n copied = ownerDocument.execCommand?.(\"copy\") ?? false;\n } catch {\n copied = false;\n } finally {\n textarea.remove();\n const HTMLElementConstructor = ownerDocument.defaultView?.HTMLElement;\n if (\n HTMLElementConstructor &&\n activeElement instanceof HTMLElementConstructor\n ) {\n activeElement.focus({ preventScroll: true });\n }\n }\n return copied;\n}\n\n/**\n * 写入二维表格文本到系统剪贴板。\n */\nexport async function copyRows(rows: ClipboardCellValue[][]) {\n await copyText(formatRowsForClipboard(rows));\n}\n\n/**\n * 写入 JSON 文本到系统剪贴板。\n */\nexport async function copyJson(value: unknown, space = 2) {\n await copyText(JSON.stringify(value, null, space) ?? \"\");\n}\n\n/**\n * 格式化二维数据为剪贴板友好的文本。\n */\nexport function formatRowsForClipboard(rows: ClipboardCellValue[][]) {\n return rows.map((row) => row.map(formatClipboardCell).join(\"\\t\")).join(\"\\n\");\n}\n\nfunction formatClipboardCell(value: ClipboardCellValue) {\n if (value == null) {\n return \"\";\n }\n\n return String(value);\n}\n","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","/**\n * 支持对象属性路径的数据索引。\n */\nexport type ValueDataIndex = string | number | Array<string | number>;\n\n/**\n * 将 dataIndex 转换为稳定字符串。\n */\nexport function stringifyDataIndex(dataIndex: ValueDataIndex) {\n return (Array.isArray(dataIndex) ? dataIndex : [dataIndex])\n .map((item) => String(item))\n .join(\".\");\n}\n\n/**\n * 判断两个 dataIndex 是否指向相同属性路径。\n */\nexport function isSameDataIndex(left: ValueDataIndex, right: ValueDataIndex) {\n const leftPath = Array.isArray(left) ? left : [left];\n const rightPath = Array.isArray(right) ? right : [right];\n return (\n leftPath.length === rightPath.length &&\n leftPath.every((key, index) => key === rightPath[index])\n );\n}\n\n/**\n * 通过 dataIndex 安全读取值。\n *\n * @param source 数据记录。\n * @param dataIndex 属性路径。\n * @returns 读取结果。\n */\nexport function getValueByDataIndex(\n source: unknown,\n dataIndex?: ValueDataIndex,\n) {\n if (dataIndex == null) {\n return undefined;\n }\n\n const path = Array.isArray(dataIndex) ? dataIndex : [dataIndex];\n let current: unknown = source;\n\n for (const key of path) {\n if (\n current == null ||\n (typeof current !== \"object\" && typeof current !== \"function\")\n ) {\n return undefined;\n }\n current = (current as Record<string | number, unknown>)[key];\n }\n\n return current;\n}\n","/**\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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canvas-components/utils",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Clipboard and export utilities for canvas-components.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -26,6 +26,16 @@
|
|
|
26
26
|
"types": "./dist/export/index.d.ts",
|
|
27
27
|
"import": "./dist/export/index.js",
|
|
28
28
|
"require": "./dist/export/index.cjs"
|
|
29
|
+
},
|
|
30
|
+
"./data": {
|
|
31
|
+
"types": "./dist/data/index.d.ts",
|
|
32
|
+
"import": "./dist/data/index.js",
|
|
33
|
+
"require": "./dist/data/index.cjs"
|
|
34
|
+
},
|
|
35
|
+
"./geometry": {
|
|
36
|
+
"types": "./dist/geometry/index.d.ts",
|
|
37
|
+
"import": "./dist/geometry/index.js",
|
|
38
|
+
"require": "./dist/geometry/index.cjs"
|
|
29
39
|
}
|
|
30
40
|
},
|
|
31
41
|
"publishConfig": {
|