@4399ywkf/editor 0.6.0 → 0.7.0
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 +80 -2
- package/dist/SheetView-SDBRSTVS.js +3 -0
- package/dist/{SheetView-DSADIZNS.js.map → SheetView-SDBRSTVS.js.map} +1 -1
- package/dist/chunk-5HMKRNIH.js +27 -0
- package/dist/chunk-5HMKRNIH.js.map +1 -0
- package/dist/chunk-DGUNVCOM.js +711 -0
- package/dist/chunk-DGUNVCOM.js.map +1 -0
- package/dist/chunk-HPSPOM2O.js +128 -0
- package/dist/chunk-HPSPOM2O.js.map +1 -0
- package/dist/chunk-KRP5V7VF.js +130 -0
- package/dist/chunk-KRP5V7VF.js.map +1 -0
- package/dist/chunk-SBTKDJAL.js +107 -0
- package/dist/chunk-SBTKDJAL.js.map +1 -0
- package/dist/{chunk-L6ZR5HHW.js → chunk-SYCK6Y5F.js} +15 -10
- package/dist/chunk-SYCK6Y5F.js.map +1 -0
- package/dist/chunk-WF7PIIFR.js +21 -0
- package/dist/chunk-WF7PIIFR.js.map +1 -0
- package/dist/{types-C37MAt8o.d.ts → csv-parse-D0zTBvDB.d.ts} +39 -1
- package/dist/csv.d.ts +6 -3
- package/dist/csv.js +6 -125
- package/dist/csv.js.map +1 -1
- package/dist/docx.d.ts +15 -0
- package/dist/docx.js +61 -3
- package/dist/docx.js.map +1 -1
- package/dist/import-GVZDLWA2.js +6 -0
- package/dist/import-GVZDLWA2.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/pdf.d.ts +1 -1
- package/dist/pptx.d.ts +1 -1
- package/dist/{registry-BBL8yeIT.d.ts → registry-XJFJXtZ_.d.ts} +6 -0
- package/dist/sheet-runtime.d.ts +212 -0
- package/dist/sheet-runtime.js +416 -0
- package/dist/sheet-runtime.js.map +1 -0
- package/dist/sheet.d.ts +7 -5
- package/dist/sheet.js +1 -1
- package/dist/xlsx.d.ts +118 -7
- package/dist/xlsx.js +7 -78
- package/dist/xlsx.js.map +1 -1
- package/package.json +7 -3
- package/dist/SheetView-DSADIZNS.js +0 -3
- package/dist/chunk-32WQX3NR.js +0 -37
- package/dist/chunk-32WQX3NR.js.map +0 -1
- package/dist/chunk-L6ZR5HHW.js.map +0 -1
package/README.md
CHANGED
|
@@ -24,6 +24,12 @@ import "@4399ywkf/editor/styles"
|
|
|
24
24
|
|
|
25
25
|
云文档与本地 doc 是**同一套 tiptap**,不做区分。
|
|
26
26
|
|
|
27
|
+
「AI 可操作」指的是有结构化操作面可挂:doc 走 [`./doc-runtime`](#ai-操作面),
|
|
28
|
+
sheet 走 `./sheet-runtime`,工具定义在 [`@4399ywkf/editor-mcp`](../editor-mcp)。
|
|
29
|
+
|
|
30
|
+
导入导出都**在本地转换,文档不出内网**:docx ⇄ doc、xlsx/csv/tsv ⇄ sheet,
|
|
31
|
+
不引 SheetJS、不依赖任何转换服务。
|
|
32
|
+
|
|
27
33
|
## 为什么引擎是懒加载的
|
|
28
34
|
|
|
29
35
|
主入口只有 **3KB**(格式路由),tiptap 的 698KB 在独立 chunk 里,Univer / pdf.js / pptx-preview 都是可选 peer。
|
|
@@ -36,11 +42,13 @@ Univer sheets 核心 gzip 后 871KB;无条件打进主包会直接毁掉阅读
|
|
|
36
42
|
```ts
|
|
37
43
|
import { NotionEditor, ArticleViewer } from "@4399ywkf/editor/doc"
|
|
38
44
|
import { ImportDocx, ExportDocx } from "@4399ywkf/editor/docx"
|
|
39
|
-
import { downloadXlsx } from "@4399ywkf/editor/xlsx"
|
|
45
|
+
import { downloadXlsx, importSheetSource } from "@4399ywkf/editor/xlsx"
|
|
40
46
|
import { downloadCsv } from "@4399ywkf/editor/csv"
|
|
41
47
|
import { SheetView } from "@4399ywkf/editor/sheet"
|
|
42
48
|
import { PdfView } from "@4399ywkf/editor/pdf"
|
|
43
49
|
import { PptxView, repairPptx } from "@4399ywkf/editor/pptx"
|
|
50
|
+
import { DocRuntime } from "@4399ywkf/editor/doc-runtime" // AI 可驱动的文档操作面
|
|
51
|
+
import { SheetRuntime } from "@4399ywkf/editor/sheet-runtime" // 同上,表格版
|
|
44
52
|
import "@4399ywkf/editor/styles"
|
|
45
53
|
```
|
|
46
54
|
|
|
@@ -197,6 +205,50 @@ if (warnings.length) toast(warnings.join("\n"))
|
|
|
197
205
|
「序列号 + 数字格式」,csv 里会写成 `45678`。格式码有转义、区域前缀、还有和 `mm`
|
|
198
206
|
同形的分钟,猜错日期比原样给出序列号更糟,所以只警告不转换。
|
|
199
207
|
|
|
208
|
+
## xlsx / csv / tsv 导入
|
|
209
|
+
|
|
210
|
+
导出的反方向,同一套约定:**本地解析,文档不出内网**,不引 SheetJS。
|
|
211
|
+
路由层直接给 `source` 就行,`File` / `Blob` / URL 都收:
|
|
212
|
+
|
|
213
|
+
```tsx
|
|
214
|
+
<DocumentView
|
|
215
|
+
format="sheet"
|
|
216
|
+
source={file}
|
|
217
|
+
onWarnings={(w) => toast(w.join("\n"))} // ← 别吞,见下
|
|
218
|
+
onError={(e) => toast(e.message)}
|
|
219
|
+
/>
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
也可以只要快照,自己塞给 Univer:
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
import { importSheetSource } from "@4399ywkf/editor/xlsx"
|
|
226
|
+
|
|
227
|
+
const { workbook, warnings, format } = await importSheetSource(file)
|
|
228
|
+
univerAPI.createWorkbook(workbook)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Node 侧没有全局 `DOMParser`,把 `@xmldom/xmldom` 的传进去即可
|
|
232
|
+
(`importXlsx(bytes, { DOMParser })`)—— 解析层是纯函数,整条链路不碰 DOM。
|
|
233
|
+
|
|
234
|
+
**能保住的**:多工作表(顺序 / 隐藏)、值与类型、公式(普通 / 共享 / 数组)、
|
|
235
|
+
数字格式(含内建表)、字体 / 颜色 / 填充 / 边框 / 对齐 / 换行 / 旋转、合并单元格、
|
|
236
|
+
行高列宽、隐藏行列、冻结窗格、网格线、标签颜色、`quotePrefix`(强制文本)。
|
|
237
|
+
|
|
238
|
+
**保不住的逐个点名**(进 `warnings`):图片 / 图表、透视表、条件格式、数据校验、
|
|
239
|
+
筛选、超链接、批注、宏、主题色、1904 日期系统。和导出侧一样 ——
|
|
240
|
+
**打开文件才发现少了东西,远比导入时被告知糟糕**。
|
|
241
|
+
|
|
242
|
+
`.xls` 是老的二进制复合文档,明确不解析:报错会直接告诉用户「另存为 .xlsx」,
|
|
243
|
+
而不是给一个空表。
|
|
244
|
+
|
|
245
|
+
csv / tsv 两处有立场的处理:
|
|
246
|
+
|
|
247
|
+
- **编码嗅探**:UTF-8 严格解码优先,失败退 GBK(简中环境相当一部分 csv 是 Excel
|
|
248
|
+
直接另存的),退了会在 `warnings` 里说明。
|
|
249
|
+
- **类型推断保守**:前导零(`0123`)和超过 15 位有效数字的「数字」保留为强制文本 ——
|
|
250
|
+
转成 number 会失真,宁可留原文也不悄悄改值。订单号、身份证号就是这么被毁掉的。
|
|
251
|
+
|
|
200
252
|
## docx 导入导出
|
|
201
253
|
|
|
202
254
|
API 形态对齐 `@tiptap-pro/extension-import-docx` / `-export-docx`,但**在本地解析**,
|
|
@@ -223,6 +275,32 @@ editor.chain().exportDocx({ onCompleteExport: (blob) => save(blob) }).run()
|
|
|
223
275
|
|
|
224
276
|
已知缺口:`fldChar` 复杂域、修订痕迹、页眉页脚 / 脚注、超链接导出未建外部关系。
|
|
225
277
|
|
|
278
|
+
## AI 操作面
|
|
279
|
+
|
|
280
|
+
要让 AI 改**用户此刻正在看的那个实例**(而不是复制一份文本出去改),
|
|
281
|
+
挂对应的 runtime 即可。两层都只认编辑器实例,**不知道 MCP / HTTP 存在**:
|
|
282
|
+
|
|
283
|
+
```tsx
|
|
284
|
+
import { DocRuntime } from "@4399ywkf/editor/doc-runtime"
|
|
285
|
+
import { SheetRuntime } from "@4399ywkf/editor/sheet-runtime"
|
|
286
|
+
|
|
287
|
+
const doc = useMemo(() => new DocRuntime(), [])
|
|
288
|
+
const sheet = useMemo(() => new SheetRuntime(), [])
|
|
289
|
+
|
|
290
|
+
<NotionEditor onEditorReady={(editor) => doc.setEditor(editor)} />
|
|
291
|
+
<DocumentView format="sheet" onReady={(api) => sheet.setUniverAPI(api)} />
|
|
292
|
+
|
|
293
|
+
await doc.call("doc_replace_text", { ... }) // 两个 runtime 的 call 是同构的
|
|
294
|
+
await sheet.call("sheet_read", { range: "A1:D20" })
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
- `doc-runtime`:LiteXML(对 ProseMirror JSON 的有损压缩,省 1.55x 以上 token)+ 8 类操作。
|
|
298
|
+
- `sheet-runtime`:读走快照(CSV 文本,比 JSON 单元格矩阵省几倍 token),
|
|
299
|
+
写走 Univer facade 的 command 体系(这样才有撤销栈和协同广播)。
|
|
300
|
+
|
|
301
|
+
工具定义(name / JSON Schema / description)和传输(浏览器桥 / hub / stdio MCP)
|
|
302
|
+
都在 [`@4399ywkf/editor-mcp`](../editor-mcp),本包一行传输代码都没有。
|
|
303
|
+
|
|
226
304
|
## 注册自有格式
|
|
227
305
|
|
|
228
306
|
内置通道覆盖不了、或保真度不够时,宿主可以用同名 `registerFormat` 直接覆盖。
|
|
@@ -268,6 +346,6 @@ schema 不一致时一端产生的节点到另一端会被 y-prosemirror 当非
|
|
|
268
346
|
```bash
|
|
269
347
|
pnpm install
|
|
270
348
|
pnpm build # tsup + 样式编译
|
|
271
|
-
pnpm test #
|
|
349
|
+
pnpm test # 232 个用例
|
|
272
350
|
pnpm typecheck
|
|
273
351
|
```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"SheetView-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"SheetView-SDBRSTVS.js"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// src/xlsx/cell.ts
|
|
2
|
+
function numericKeys(o) {
|
|
3
|
+
if (!o) return [];
|
|
4
|
+
return Object.keys(o).map(Number).filter((n) => Number.isInteger(n) && n >= 0).sort((a, b) => a - b);
|
|
5
|
+
}
|
|
6
|
+
function matrixRow(matrix, row) {
|
|
7
|
+
let r = matrix[row];
|
|
8
|
+
if (!r) {
|
|
9
|
+
r = {};
|
|
10
|
+
matrix[row] = r;
|
|
11
|
+
}
|
|
12
|
+
return r;
|
|
13
|
+
}
|
|
14
|
+
function richTextToPlain(cell) {
|
|
15
|
+
const stream = cell.p?.body?.dataStream;
|
|
16
|
+
if (typeof stream !== "string") return void 0;
|
|
17
|
+
return stream.replace(/\r\n$/, "").replace(/\r/g, "\n");
|
|
18
|
+
}
|
|
19
|
+
function looksLikeDateFormat(pattern) {
|
|
20
|
+
if (!pattern) return false;
|
|
21
|
+
const bare = pattern.replace(/"[^"]*"/g, "").replace(/\\./g, "");
|
|
22
|
+
return /[yYdD]/.test(bare) || /h/i.test(bare) || /\[\$-/.test(pattern);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { looksLikeDateFormat, matrixRow, numericKeys, richTextToPlain };
|
|
26
|
+
//# sourceMappingURL=chunk-5HMKRNIH.js.map
|
|
27
|
+
//# sourceMappingURL=chunk-5HMKRNIH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/xlsx/cell.ts"],"names":[],"mappings":";AAWO,SAAS,YAAY,CAAA,EAAkD;AAC5E,EAAA,IAAI,CAAC,CAAA,EAAG,OAAO,EAAC;AAChB,EAAA,OAAO,MAAA,CAAO,KAAK,CAAC,CAAA,CACjB,IAAI,MAAM,CAAA,CACV,MAAA,CAAO,CAAC,CAAA,KAAM,MAAA,CAAO,UAAU,CAAC,CAAA,IAAK,KAAK,CAAC,CAAA,CAC3C,KAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA;AACzB;AAGO,SAAS,SAAA,CAAa,QAAmB,GAAA,EAAgC;AAC9E,EAAA,IAAI,CAAA,GAAI,OAAO,GAAG,CAAA;AAClB,EAAA,IAAI,CAAC,CAAA,EAAG;AACN,IAAA,CAAA,GAAI,EAAC;AACL,IAAA,MAAA,CAAO,GAAG,CAAA,GAAI,CAAA;AAAA,EAChB;AACA,EAAA,OAAO,CAAA;AACT;AAGO,SAAS,gBAAgB,IAAA,EAAoC;AAClE,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,CAAA,EAAG,IAAA,EAAM,UAAA;AAC7B,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,EAAU,OAAO,MAAA;AACvC,EAAA,OAAO,OAAO,OAAA,CAAQ,OAAA,EAAS,EAAE,CAAA,CAAE,OAAA,CAAQ,OAAO,IAAI,CAAA;AACxD;AASO,SAAS,oBAAoB,OAAA,EAA6C;AAC/E,EAAA,IAAI,CAAC,SAAS,OAAO,KAAA;AAErB,EAAA,MAAM,IAAA,GAAO,QAAQ,OAAA,CAAQ,UAAA,EAAY,EAAE,CAAA,CAAE,OAAA,CAAQ,QAAQ,EAAE,CAAA;AAC/D,EAAA,OAAO,QAAA,CAAS,IAAA,CAAK,IAAI,CAAA,IAAK,IAAA,CAAK,KAAK,IAAI,CAAA,IAAK,OAAA,CAAQ,IAAA,CAAK,OAAO,CAAA;AACvE","file":"chunk-5HMKRNIH.js","sourcesContent":["/** 读写 Univer 快照时 xlsx 与 csv 两条路径共用的小工具。 */\n\nimport type { CellData, Matrix } from \"./types.ts\"\n\n/**\n * 稀疏矩阵的行号/列号。\n *\n * Univer 的 `cellData` 是 `{ [row]: { [col]: cell } }` 的普通对象,键是字符串。\n * 直接 `Object.keys()` 会得到 `[\"10\", \"2\"]` 这种字典序,必须转数字再排 ——\n * 否则导出的行序就是乱的。\n */\nexport function numericKeys(o: Record<number, unknown> | undefined): number[] {\n if (!o) return []\n return Object.keys(o)\n .map(Number)\n .filter((n) => Number.isInteger(n) && n >= 0)\n .sort((a, b) => a - b)\n}\n\n/** 取稀疏矩阵的一行,不存在则建。导入侧写 cellData 用 */\nexport function matrixRow<T>(matrix: Matrix<T>, row: number): Record<number, T> {\n let r = matrix[row]\n if (!r) {\n r = {}\n matrix[row] = r\n }\n return r\n}\n\n/** 富文本只取纯文本。Univer 的 dataStream 用 \\r 断段、结尾还带一个 \\r\\n */\nexport function richTextToPlain(cell: CellData): string | undefined {\n const stream = cell.p?.body?.dataStream\n if (typeof stream !== \"string\") return undefined\n return stream.replace(/\\r\\n$/, \"\").replace(/\\r/g, \"\\n\")\n}\n\n/**\n * 这个单元格的数字格式是不是日期/时间。\n *\n * 只做**粗判**,用来给 csv 提示「这里会导出成序列号」,不用来做转换 ——\n * Excel 的格式码有转义(`\\d`、`\"年\"`)、有区域前缀(`[$-409]`)、\n * 还有和 `mm` 同形的分钟,真解析是个坑。猜错日期比原样给出序列号更糟。\n */\nexport function looksLikeDateFormat(pattern: string | undefined | null): boolean {\n if (!pattern) return false\n // 去掉引号里的字面量和反斜杠转义,剩下的才是真正的格式符\n const bare = pattern.replace(/\"[^\"]*\"/g, \"\").replace(/\\\\./g, \"\")\n return /[yYdD]/.test(bare) || /h/i.test(bare) || /\\[\\$-/.test(pattern)\n}\n"]}
|