@4399ywkf/editor 0.5.0 → 0.6.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/xlsx/csv.ts","../src/csv.ts"],"names":["text"],"mappings":"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","file":"csv.js","sourcesContent":["/**\n * Univer 快照 → CSV。\n *\n * **csv 是单表格式,工作簿是多表的**,这是产品决定不是技术决定。本实现的口径:\n * 导**一张**表,其余的在 `warnings` 里**逐个点名**,和 xlsx 导出「如实报告丢了什么」\n * 保持一致 —— 静悄悄只给一张表,用户往往到对账时才发现少了东西。\n *\n * 「哪张是活动表」只有运行时的 Univer 实例知道,**快照里根本没有这个字段**。\n * 所以:传 `univerAPI` 时取真正的活动表;只传快照时取 `sheetOrder` 的第一张,\n * 并且照样把这件事写进 warnings。要指定就用 `options.sheet`(表 id 或表名)。\n */\n\nimport { looksLikeDateFormat, numericKeys, richTextToPlain } from \"./cell.ts\"\nimport type { CellData, StyleData, WorkbookData, WorksheetData } from \"./types.ts\"\n\nexport interface CsvOptions {\n /** 导哪张表:工作表 id 或表名。不传则用活动表(拿不到就用第一张) */\n sheet?: string\n /** 分隔符,默认 `,`。用 `\\t` 就是 tsv */\n delimiter?: string\n /** 行分隔,默认 `\\r\\n`(RFC 4180 规定,Excel 也最稳) */\n newline?: string\n /**\n * 是否加 UTF-8 BOM,默认 **true**。\n * 不加的话 Excel 会按本地编码(简中系统是 GBK)解析,中文全是乱码 ——\n * 这是 csv 导出最常见的投诉,默认就得挡掉。\n */\n bom?: boolean\n /** 公式格写 Univer 算好的值(默认)还是写公式文本 */\n formulas?: \"value\" | \"formula\"\n}\n\nexport interface CsvResult {\n /** 文本内容,不含 BOM */\n text: string\n /** 可直接落盘/上传的字节,按 `bom` 决定是否带 BOM */\n bytes: Uint8Array\n /** 导出时丢掉/降级了什么。**要展示给用户** */\n warnings: string[]\n stats: {\n sheetName: string\n rows: number\n columns: number\n cells: number\n /** 没被导出的工作表数 */\n skippedSheets: number\n }\n}\n\nexport const CSV_MIME = \"text/csv;charset=utf-8\"\n\n/** RFC 4180:字段含分隔符、引号或换行时整体加引号,内部引号翻倍 */\nfunction escapeField(value: string, delimiter: string): string {\n if (!value) return \"\"\n const needsQuote =\n value.includes(delimiter) || value.includes('\"') || value.includes(\"\\n\") || value.includes(\"\\r\")\n return needsQuote ? `\"${value.replace(/\"/g, '\"\"')}\"` : value\n}\n\nexport function csvFromSnapshot(workbook: WorkbookData, options: CsvOptions = {}): CsvResult {\n const { delimiter = \",\", newline = \"\\r\\n\", bom = true, formulas = \"value\" } = options\n\n const warnings: string[] = []\n const order = (\n workbook.sheetOrder?.length ? workbook.sheetOrder : Object.keys(workbook.sheets ?? {})\n ).filter((id) => workbook.sheets?.[id])\n\n if (!order.length) {\n return {\n text: \"\",\n bytes: encode(\"\", bom),\n warnings: [\"工作簿里没有工作表\"],\n stats: { sheetName: \"\", rows: 0, columns: 0, cells: 0, skippedSheets: 0 },\n }\n }\n\n // 指定 → 按 id 或表名找;没指定 → 第一张\n const wanted = options.sheet\n const pickedId =\n (wanted &&\n (order.find((id) => id === wanted) ??\n order.find((id) => (workbook.sheets?.[id] as WorksheetData)?.name === wanted))) ||\n (order[0] as string)\n if (\n wanted &&\n pickedId !== wanted &&\n (workbook.sheets?.[pickedId] as WorksheetData)?.name !== wanted\n ) {\n warnings.push(\n `找不到工作表「${wanted}」,已改导「${(workbook.sheets?.[pickedId] as WorksheetData)?.name ?? pickedId}」`,\n )\n }\n\n const sheet = workbook.sheets?.[pickedId] as WorksheetData\n const sheetName = sheet?.name ?? pickedId\n\n // 点名没导出的表 —— 这条是 csv 导出最容易被忽略的损失\n const skipped = order.filter((id) => id !== pickedId)\n if (skipped.length) {\n const names = skipped.map((id) => `「${(workbook.sheets?.[id] as WorksheetData)?.name ?? id}」`)\n warnings.push(\n `csv 是单表格式,只导出了「${sheetName}」。未导出的 ${skipped.length} 张表:${names.join(\"\")}`,\n )\n }\n\n const styleMap = workbook.styles ?? {}\n const resolveStyle = (s: StyleData | string | null | undefined): StyleData | undefined => {\n if (!s) return undefined\n if (typeof s === \"string\") return styleMap[s] ?? undefined\n return s\n }\n\n const cellData = sheet?.cellData ?? {}\n const rows = numericKeys(cellData)\n let maxCol = -1\n for (const r of rows) {\n const cols = numericKeys(cellData[r])\n const last = cols[cols.length - 1]\n if (last !== undefined && last > maxCol) maxCol = last\n }\n const maxRow = rows.length ? (rows[rows.length - 1] as number) : -1\n\n let cells = 0\n let sawDateFormat = false\n let sawRichText = false\n\n const lines: string[] = []\n for (let r = 0; r <= maxRow; r++) {\n const row = cellData[r]\n const fields: string[] = []\n for (let c = 0; c <= maxCol; c++) {\n const cell = row?.[c]\n const text = cell ? cellToText(cell) : \"\"\n if (text) cells++\n fields.push(escapeField(text, delimiter))\n }\n lines.push(fields.join(delimiter))\n }\n\n function cellToText(cell: CellData): string {\n if (formulas === \"formula\" && cell.f) return cell.f\n\n const rich = richTextToPlain(cell)\n if (rich !== undefined) {\n sawRichText = true\n return rich\n }\n\n const v = cell.v\n if (v === undefined || v === null) return \"\"\n if (typeof v === \"boolean\") return v ? \"TRUE\" : \"FALSE\"\n if (typeof v === \"number\") {\n // 日期在 Univer 里是「序列号 + 数字格式」,值本身就是个数字。\n // 这里不猜着转,只记下来在 warnings 里说清楚\n if (looksLikeDateFormat(resolveStyle(cell.s)?.n?.pattern)) sawDateFormat = true\n return String(v)\n }\n return String(v)\n }\n\n if (sawDateFormat) {\n warnings.push(\n \"有单元格用的是日期/时间格式,csv 里会写成 Excel 序列号(如 45678)而不是日期文本 —— \" +\n \"csv 不带格式信息,导入方需要自己按日期列解析\",\n )\n }\n if (sawRichText) warnings.push(\"富文本单元格已压平成纯文本,段内的字体与颜色不保留\")\n if (sheet?.mergeData?.length) {\n warnings.push(`${sheet.mergeData.length} 处合并单元格已拆开:值留在左上角,其余为空`)\n }\n if (formulas === \"value\") {\n const hasFormula = rows.some((r) => numericKeys(cellData[r]).some((c) => cellData[r]?.[c]?.f))\n if (hasFormula) warnings.push(\"公式已写成 Univer 算出的值,公式本身不保留\")\n }\n\n const text = lines.join(newline)\n return {\n text,\n bytes: encode(text, bom),\n warnings,\n stats: {\n sheetName,\n rows: maxRow + 1,\n columns: maxCol + 1,\n cells,\n skippedSheets: skipped.length,\n },\n }\n}\n\nfunction encode(text: string, bom: boolean): Uint8Array {\n const body = new TextEncoder().encode(text)\n if (!bom) return body\n const out = new Uint8Array(body.length + 3)\n out.set([0xef, 0xbb, 0xbf])\n out.set(body, 3)\n return out\n}\n\n/**\n * 从 Univer 实例上问出当前活动表的 id。\n *\n * 参数是 `unknown` 而不是 `FUniver`:`@univerjs/presets` 是可选 peer,\n * 写具体类型会让没装它的项目 typecheck 直接红。\n */\nexport function activeSheetId(univerAPI: unknown): string | undefined {\n const book = (univerAPI as { getActiveWorkbook?: () => unknown } | null)?.getActiveWorkbook?.()\n const sheet = (book as { getActiveSheet?: () => unknown } | null)?.getActiveSheet?.()\n const id = (sheet as { getSheetId?: () => string } | null)?.getSheetId?.()\n return typeof id === \"string\" && id ? id : undefined\n}\n","/**\n * `@4399ywkf/editor/csv` —— 表格导出 CSV。\n *\n * 独立子路径而不是塞进 `./xlsx`:csv 这条路**一个依赖都不需要**\n * (xlsx 那边要 fflate 打 zip),几 KB 就够。只要 csv 的宿主不该为 zip 买单。\n *\n * ```ts\n * import { downloadCsv } from \"@4399ywkf/editor/csv\"\n *\n * const { warnings } = downloadCsv(univerAPI, \"明细.csv\")\n * if (warnings.length) toast(warnings.join(\"\\n\")) // ← 里面会点名哪些表没导\n * ```\n *\n * **csv 是单表格式,工作簿是多表的。** 本实现只导一张表,其余的在 `warnings`\n * 里逐个点名。传 `univerAPI` 时导真正的活动表;只传快照时导第一张 ——\n * 快照里根本没有「活动表」这个字段。要指定就用 `options.sheet`(表 id 或表名)。\n */\n\nimport {\n activeSheetId,\n CSV_MIME,\n type CsvOptions,\n type CsvResult,\n csvFromSnapshot,\n} from \"./xlsx/csv\"\nimport { toSnapshot } from \"./xlsx/snapshot\"\nimport type { WorkbookData } from \"./xlsx/types\"\n\nexport type { CsvOptions, CsvResult } from \"./xlsx/csv\"\nexport { CSV_MIME, csvFromSnapshot } from \"./xlsx/csv\"\nexport type { CellData, WorkbookData, WorksheetData } from \"./xlsx/types\"\n\n/**\n * Univer 实例或快照 → CSV。\n *\n * 传实例时会自动锁定**当前活动表** —— 这也是唯一能拿到活动表的途径。\n */\nexport function exportCsv(source: WorkbookData | unknown, options: CsvOptions = {}): CsvResult {\n const snapshot = toSnapshot(source)\n // 已显式指定就不去猜;否则只在传的是实例时才问得出活动表\n const sheet = options.sheet ?? (snapshot === source ? undefined : activeSheetId(source))\n return csvFromSnapshot(snapshot, { ...options, sheet })\n}\n\n/** Univer 实例或快照 → Blob,便于交给上传接口 */\nexport function csvBlob(source: WorkbookData | unknown, options?: CsvOptions): Blob {\n return new Blob([exportCsv(source, options).bytes as BlobPart], { type: CSV_MIME })\n}\n\n/**\n * 触发浏览器下载。返回 warnings / stats —— 别丢,\n * 「另外几张表没导出」只能从这里知道。\n */\nexport function downloadCsv(\n source: WorkbookData | unknown,\n filename = \"表格.csv\",\n options?: CsvOptions,\n): CsvResult {\n const result = exportCsv(source, options)\n if (typeof document === \"undefined\") {\n throw new Error(\"downloadCsv 需要浏览器环境,服务端请改用 exportCsv 自己落盘\")\n }\n const url = URL.createObjectURL(new Blob([result.bytes as BlobPart], { type: CSV_MIME }))\n const a = document.createElement(\"a\")\n a.href = url\n a.download = filename.endsWith(\".csv\") ? filename : `${filename}.csv`\n document.body.appendChild(a)\n a.click()\n a.remove()\n // 立刻 revoke 会让部分浏览器(Safari)来不及取数据\n setTimeout(() => URL.revokeObjectURL(url), 10_000)\n return result\n}\n"]}
package/dist/index.js CHANGED
@@ -43,6 +43,8 @@ registerFormat({
43
43
  collaborative: false,
44
44
  // Univer 协同属于 Pro,OSS 核心不含
45
45
  importExtensions: [".xlsx", ".csv"],
46
+ // 导出实现分别在 ./xlsx 与 ./csv 两个子路径。csv 是单表格式,
47
+ // 只导活动表、其余表在 warnings 里点名
46
48
  exportFormats: ["xlsx", "csv"]
47
49
  },
48
50
  load: () => import('./SheetView-DSADIZNS.js')
@@ -61,6 +63,19 @@ registerFormat({
61
63
  },
62
64
  load: () => import('./PdfView-JDCHTG7Y.js')
63
65
  });
66
+ registerFormat({
67
+ format: "pptx",
68
+ label: "演示文稿",
69
+ extensions: [".pptx", ".ppsx", ".potx", ".pptm", ".ppsm", ".potm"],
70
+ capabilities: {
71
+ editable: false,
72
+ aiOperable: false,
73
+ collaborative: false,
74
+ importExtensions: [".pptx"],
75
+ exportFormats: []
76
+ },
77
+ load: () => import('./PptxView-ZH4FZKNO.js')
78
+ });
64
79
  function DocumentView({
65
80
  format,
66
81
  source,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/registry.ts","../src/DocumentView.tsx","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * 格式注册表 —— 整个包的骨架。\n *\n * 设计取自腾讯 WorkBuddy 的三通道结构:**按「文档住在哪 / 是什么」分通道,\n * 每个通道一个独立引擎,上面加一层路由**。它没有试图用一套编辑器覆盖全部格式,\n * 我们也不该。\n *\n * 三条硬约束:\n *\n * 1. **引擎必须懒加载。** Univer sheets 核心 gzip 后 871KB、pdf.js 也有几百 KB。\n * 塞进主包会毁掉阅读侧的首屏 —— 只有用户真的打开一个表格 / PDF 时才该下载。\n *\n * 2. **能力要可申报,不能靠猜。** `capabilities` 明确说清每种格式能不能编辑、\n * 能不能被 AI 结构化操作。上层据此决定给什么 UI,而不是先渲染再报错。\n *\n * 3. **宿主可注册自有引擎。** 内置覆盖不了的格式(如 pptx)留给宿主接,\n * 而不是我们假装支持。\n */\nimport type { ComponentType } from \"react\"\nimport type { SheetOptions } from \"./sheet-options\"\n\nexport type DocumentFormat = \"doc\" | \"sheet\" | \"pdf\" | \"pptx\" | (string & {})\n\nexport interface FormatCapabilities {\n /** 能否编辑。false 表示只读预览 */\n editable: boolean\n /** 能否被 AI 通过结构化工具面操作(读结构、按 id 定位、增删改) */\n aiOperable: boolean\n /** 能否协同编辑 */\n collaborative: boolean\n /** 支持导入的扩展名 */\n importExtensions: string[]\n /** 支持导出的格式 */\n exportFormats: string[]\n}\n\nexport interface FormatAdapter {\n format: DocumentFormat\n /** 展示名,给 UI 用 */\n label: string\n capabilities: FormatCapabilities\n /** 该格式认领哪些扩展名(小写、带点) */\n extensions: string[]\n /**\n * 懒加载视图组件。**必须是动态 import**,否则引擎会被打进主包。\n */\n load: () => Promise<{ default: ComponentType<DocumentViewProps> }>\n}\n\nexport interface DocumentViewProps {\n /** 文档来源:URL / File / 已有内容 */\n source?: string | Blob | File\n /** 已有内容(doc 走 tiptap JSON 或 HTML;sheet 走 Univer snapshot) */\n content?: unknown\n readOnly?: boolean\n /** 协同房间号,仅 collaborative 为 true 的格式有意义 */\n room?: string\n className?: string\n /**\n * sheet 通道专属配置(Univer preset 与 UI 开关),其它格式忽略。\n *\n * 放在这里而不是只给 `SheetView`,是因为宿主通常只见得到 `DocumentView`\n * 这一层路由 —— 配置进不来的话,只读预览就只能顶着整条编辑工具条。\n */\n sheet?: SheetOptions\n /** 引擎就绪回调,拿到底层实例(tiptap Editor / Univer API / PDFDocumentProxy) */\n onReady?: (instance: unknown) => void\n onError?: (error: Error) => void\n}\n\nconst registry = new Map<DocumentFormat, FormatAdapter>()\n\nexport function registerFormat(adapter: FormatAdapter): void {\n registry.set(adapter.format, adapter)\n}\n\nexport function getFormat(format: DocumentFormat): FormatAdapter | undefined {\n return registry.get(format)\n}\n\nexport function listFormats(): FormatAdapter[] {\n return [...registry.values()]\n}\n\n/** 按扩展名判定格式。传文件名、路径或裸扩展名都行。 */\nexport function detectFormat(nameOrExt: string): DocumentFormat | undefined {\n const m = /\\.([a-z0-9]+)$/i.exec(nameOrExt.trim())\n const ext = `.${(m ? m[1] : nameOrExt.replace(/^\\./, \"\")).toLowerCase()}`\n for (const a of registry.values()) if (a.extensions.includes(ext)) return a.format\n return undefined\n}\n\n/* --------------------------- 内置格式 --------------------------- */\n\nregisterFormat({\n format: \"doc\",\n label: \"文档\",\n extensions: [\".doc\", \".docx\", \".dot\", \".dotx\", \".docm\", \".dotm\", \".wps\", \".wpt\", \".md\", \".html\"],\n capabilities: {\n editable: true,\n aiOperable: true,\n collaborative: true,\n importExtensions: [\".docx\", \".md\", \".html\"],\n exportFormats: [\"docx\", \"html\", \"json\", \"markdown\"],\n },\n load: () => import(\"./views/DocView\"),\n})\n\nregisterFormat({\n format: \"sheet\",\n label: \"表格\",\n extensions: [\".xls\", \".xlsx\", \".xlt\", \".xltx\", \".xlsm\", \".xltm\", \".csv\", \".tsv\"],\n capabilities: {\n editable: true,\n aiOperable: true,\n collaborative: false, // Univer 协同属于 Pro,OSS 核心不含\n importExtensions: [\".xlsx\", \".csv\"],\n exportFormats: [\"xlsx\", \"csv\"],\n },\n load: () => import(\"./views/SheetView\"),\n})\n\nregisterFormat({\n format: \"pdf\",\n label: \"PDF\",\n extensions: [\".pdf\"],\n capabilities: {\n editable: false, // 只读预览。PDF 编辑是 OOXML 引擎那一档的事\n aiOperable: false,\n collaborative: false,\n importExtensions: [\".pdf\"],\n exportFormats: [],\n },\n load: () => import(\"./views/PdfView\"),\n})\n\n/**\n * pptx 刻意**不内置**。\n *\n * 调研结论:Univer Slides 官方文档原文写着「请勿用于生产环境」,\n * `@univerjs/slides` 只有 0.17MB 骨架;开源世界里没有第二个可用的\n * 前端 pptx 编辑/渲染引擎。真要做只有 OnlyOffice / Collabora 那一档\n * (AGPL,需法务口径 + 独立部署)。\n *\n * 与其假装支持,不如把口子留给宿主:\n *\n * ```ts\n * registerFormat({\n * format: \"pptx\",\n * label: \"演示文稿\",\n * extensions: [\".ppt\", \".pptx\"],\n * capabilities: { editable: false, aiOperable: false, collaborative: false,\n * importExtensions: [], exportFormats: [] },\n * load: () => import(\"./MyOnlyOfficeSlideView\"),\n * })\n * ```\n */\n","import { Suspense, lazy, useMemo, type ComponentType, type ReactNode } from \"react\"\nimport { detectFormat, getFormat, type DocumentFormat, type DocumentViewProps } from \"./registry\"\n\nexport interface DocumentViewComponentProps extends DocumentViewProps {\n /** 文档格式。不传则尝试从 source 的扩展名推断 */\n format?: DocumentFormat\n /** 引擎加载中的占位 */\n fallback?: ReactNode\n /** 格式不支持时的兜底渲染。不传则渲染一段说明文字 */\n unsupported?: (format: string) => ReactNode\n}\n\n/**\n * 按格式路由到对应引擎,引擎按需下载。\n *\n * 为什么用 registry + lazy 而不是 if/else 直接 import:\n * 直接 import 会让 Univer(871KB gzip)和 pdf.js 无条件进主包,\n * 哪怕用户从头到尾只看文章。这在阅读侧是不可接受的 ——\n * 本仓刚做完「服务端直出 588KB」的优化,一个表格引擎就能全毁掉。\n */\nexport function DocumentView({\n format,\n source,\n fallback,\n unsupported,\n ...rest\n}: DocumentViewComponentProps) {\n const resolved = useMemo<DocumentFormat | undefined>(() => {\n if (format) return format\n const name = typeof source === \"string\" ? source : (source as File | undefined)?.name\n if (!name) return undefined\n return detectFormat(name)\n }, [format, source])\n\n const adapter = resolved ? getFormat(resolved) : undefined\n\n const View = useMemo<ComponentType<DocumentViewProps> | null>(() => {\n if (!adapter) return null\n return lazy(adapter.load)\n }, [adapter])\n\n if (!adapter || !View) {\n return (\n <>\n {unsupported?.(String(resolved ?? \"unknown\")) ?? (\n <div data-editor-unsupported={String(resolved ?? \"unknown\")}>\n 暂不支持该格式{resolved ? `(${resolved})` : \"\"}。\n 可通过 registerFormat() 注册自有引擎。\n </div>\n )}\n </>\n )\n }\n\n return (\n <Suspense fallback={fallback ?? <div data-editor-loading={adapter.format} />}>\n <View source={source} {...rest} />\n </Suspense>\n )\n}\n","/**\n * @4399ywkf/editor —— 多格式文档编辑器\n *\n * 主入口只放**格式路由与能力申报**,具体引擎全部懒加载。\n * 直接 import 这里不会把 tiptap / Univer / pdf.js 打进你的主包。\n *\n * ```tsx\n * import { DocumentView, detectFormat } from \"@4399ywkf/editor\"\n * import \"@4399ywkf/editor/styles\"\n *\n * <DocumentView format={detectFormat(\"年度报告.docx\")} content={html} />\n * ```\n *\n * 需要直接用某个引擎时走子路径,能拿到完整 API:\n *\n * ```ts\n * import { NotionEditor } from \"@4399ywkf/editor/doc\"\n * import { ImportDocx, ExportDocx } from \"@4399ywkf/editor/docx\"\n * ```\n */\n\nexport { DocumentView, type DocumentViewComponentProps } from \"./DocumentView\"\nexport {\n type DocumentFormat,\n type DocumentViewProps,\n detectFormat,\n type FormatAdapter,\n type FormatCapabilities,\n getFormat,\n listFormats,\n registerFormat,\n} from \"./registry\"\n\nexport type { SheetOptions, SheetUiOptions } from \"./sheet-options\"\n\nexport const VERSION = \"0.1.0\"\n"]}
1
+ {"version":3,"sources":["../src/registry.ts","../src/DocumentView.tsx","../src/index.ts"],"names":[],"mappings":";;;;;;AAsEA,IAAM,QAAA,uBAAe,GAAA,EAAmC;AAEjD,SAAS,eAAe,OAAA,EAA8B;AAC3D,EAAA,QAAA,CAAS,GAAA,CAAI,OAAA,CAAQ,MAAA,EAAQ,OAAO,CAAA;AACtC;AAEO,SAAS,UAAU,MAAA,EAAmD;AAC3E,EAAA,OAAO,QAAA,CAAS,IAAI,MAAM,CAAA;AAC5B;AAEO,SAAS,WAAA,GAA+B;AAC7C,EAAA,OAAO,CAAC,GAAG,QAAA,CAAS,MAAA,EAAQ,CAAA;AAC9B;AAGO,SAAS,aAAa,SAAA,EAA+C;AAC1E,EAAA,MAAM,CAAA,GAAI,iBAAA,CAAkB,IAAA,CAAK,SAAA,CAAU,MAAM,CAAA;AACjD,EAAA,MAAM,GAAA,GAAM,CAAA,CAAA,EAAA,CAAK,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,SAAA,CAAU,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA,EAAG,WAAA,EAAa,CAAA,CAAA;AACvE,EAAA,KAAA,MAAW,CAAA,IAAK,QAAA,CAAS,MAAA,EAAO,EAAG,IAAI,CAAA,CAAE,UAAA,CAAW,QAAA,CAAS,GAAG,CAAA,EAAG,OAAO,CAAA,CAAE,MAAA;AAC5E,EAAA,OAAO,MAAA;AACT;AAIA,cAAA,CAAe;AAAA,EACb,MAAA,EAAQ,KAAA;AAAA,EACR,KAAA,EAAO,IAAA;AAAA,EACP,UAAA,EAAY,CAAC,MAAA,EAAQ,OAAA,EAAS,MAAA,EAAQ,OAAA,EAAS,OAAA,EAAS,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAO,OAAO,CAAA;AAAA,EAC/F,YAAA,EAAc;AAAA,IACZ,QAAA,EAAU,IAAA;AAAA,IACV,UAAA,EAAY,IAAA;AAAA,IACZ,aAAA,EAAe,IAAA;AAAA,IACf,gBAAA,EAAkB,CAAC,OAAA,EAAS,KAAA,EAAO,OAAO,CAAA;AAAA,IAC1C,aAAA,EAAe,CAAC,MAAA,EAAQ,MAAA,EAAQ,QAAQ,UAAU;AAAA,GACpD;AAAA,EACA,IAAA,EAAM,MAAM,OAAO,uBAAiB;AACtC,CAAC,CAAA;AAED,cAAA,CAAe;AAAA,EACb,MAAA,EAAQ,OAAA;AAAA,EACR,KAAA,EAAO,IAAA;AAAA,EACP,UAAA,EAAY,CAAC,MAAA,EAAQ,OAAA,EAAS,QAAQ,OAAA,EAAS,OAAA,EAAS,OAAA,EAAS,MAAA,EAAQ,MAAM,CAAA;AAAA,EAC/E,YAAA,EAAc;AAAA,IACZ,QAAA,EAAU,IAAA;AAAA,IACV,UAAA,EAAY,IAAA;AAAA,IACZ,aAAA,EAAe,KAAA;AAAA;AAAA,IACf,gBAAA,EAAkB,CAAC,OAAA,EAAS,MAAM,CAAA;AAAA;AAAA;AAAA,IAGlC,aAAA,EAAe,CAAC,MAAA,EAAQ,KAAK;AAAA,GAC/B;AAAA,EACA,IAAA,EAAM,MAAM,OAAO,yBAAmB;AACxC,CAAC,CAAA;AAED,cAAA,CAAe;AAAA,EACb,MAAA,EAAQ,KAAA;AAAA,EACR,KAAA,EAAO,KAAA;AAAA,EACP,UAAA,EAAY,CAAC,MAAM,CAAA;AAAA,EACnB,YAAA,EAAc;AAAA,IACZ,QAAA,EAAU,KAAA;AAAA;AAAA,IACV,UAAA,EAAY,KAAA;AAAA,IACZ,aAAA,EAAe,KAAA;AAAA,IACf,gBAAA,EAAkB,CAAC,MAAM,CAAA;AAAA,IACzB,eAAe;AAAC,GAClB;AAAA,EACA,IAAA,EAAM,MAAM,OAAO,uBAAiB;AACtC,CAAC,CAAA;AAsBD,cAAA,CAAe;AAAA,EACb,MAAA,EAAQ,MAAA;AAAA,EACR,KAAA,EAAO,MAAA;AAAA,EACP,YAAY,CAAC,OAAA,EAAS,SAAS,OAAA,EAAS,OAAA,EAAS,SAAS,OAAO,CAAA;AAAA,EACjE,YAAA,EAAc;AAAA,IACZ,QAAA,EAAU,KAAA;AAAA,IACV,UAAA,EAAY,KAAA;AAAA,IACZ,aAAA,EAAe,KAAA;AAAA,IACf,gBAAA,EAAkB,CAAC,OAAO,CAAA;AAAA,IAC1B,eAAe;AAAC,GAClB;AAAA,EACA,IAAA,EAAM,MAAM,OAAO,wBAAkB;AACvC,CAAC,CAAA;ACtJM,SAAS,YAAA,CAAa;AAAA,EAC3B,MAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA;AAAA,EACA,GAAG;AACL,CAAA,EAA+B;AAC7B,EAAA,MAAM,QAAA,GAAW,QAAoC,MAAM;AACzD,IAAA,IAAI,QAAQ,OAAO,MAAA;AACnB,IAAA,MAAM,IAAA,GAAO,OAAO,MAAA,KAAW,QAAA,GAAW,SAAU,MAAA,EAA6B,IAAA;AACjF,IAAA,IAAI,CAAC,MAAM,OAAO,MAAA;AAClB,IAAA,OAAO,aAAa,IAAI,CAAA;AAAA,EAC1B,CAAA,EAAG,CAAC,MAAA,EAAQ,MAAM,CAAC,CAAA;AAEnB,EAAA,MAAM,OAAA,GAAU,QAAA,GAAW,SAAA,CAAU,QAAQ,CAAA,GAAI,MAAA;AAEjD,EAAA,MAAM,IAAA,GAAO,QAAiD,MAAM;AAClE,IAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AACrB,IAAA,OAAO,IAAA,CAAK,QAAQ,IAAI,CAAA;AAAA,EAC1B,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAA,IAAI,CAAC,OAAA,IAAW,CAAC,IAAA,EAAM;AACrB,IAAA,uBACE,GAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA,WAAA,GAAc,MAAA,CAAO,QAAA,IAAY,SAAS,CAAC,CAAA,oBAC1C,IAAA,CAAC,KAAA,EAAA,EAAI,yBAAA,EAAyB,MAAA,CAAO,QAAA,IAAY,SAAS,CAAA,EAAG,QAAA,EAAA;AAAA,MAAA,SAAA;AAAA,MACnD,QAAA,GAAW,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA,CAAA,GAAM,EAAA;AAAA,MAAG;AAAA,KAAA,EAE1C,CAAA,EAEJ,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACE,GAAA,CAAC,QAAA,EAAA,EAAS,QAAA,EAAU,QAAA,wBAAa,KAAA,EAAA,EAAI,qBAAA,EAAqB,OAAA,CAAQ,MAAA,EAAQ,GACxE,QAAA,kBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,MAAA,EAAiB,GAAG,MAAM,CAAA,EAClC,CAAA;AAEJ;;;ACxBO,IAAM,OAAA,GAAU","file":"index.js","sourcesContent":["/**\n * 格式注册表 —— 整个包的骨架。\n *\n * 设计取自腾讯 WorkBuddy 的三通道结构:**按「文档住在哪 / 是什么」分通道,\n * 每个通道一个独立引擎,上面加一层路由**。它没有试图用一套编辑器覆盖全部格式,\n * 我们也不该。\n *\n * 三条硬约束:\n *\n * 1. **引擎必须懒加载。** Univer sheets 核心 gzip 后 871KB、pdf.js 也有几百 KB。\n * 塞进主包会毁掉阅读侧的首屏 —— 只有用户真的打开一个表格 / PDF 时才该下载。\n *\n * 2. **能力要可申报,不能靠猜。** `capabilities` 明确说清每种格式能不能编辑、\n * 能不能被 AI 结构化操作。上层据此决定给什么 UI,而不是先渲染再报错。\n *\n * 3. **宿主可注册自有引擎。** 内置覆盖不了的格式(如 pptx)留给宿主接,\n * 而不是我们假装支持。\n */\nimport type { ComponentType } from \"react\"\nimport type { SheetOptions } from \"./sheet-options\"\n\nexport type DocumentFormat = \"doc\" | \"sheet\" | \"pdf\" | \"pptx\" | (string & {})\n\nexport interface FormatCapabilities {\n /** 能否编辑。false 表示只读预览 */\n editable: boolean\n /** 能否被 AI 通过结构化工具面操作(读结构、按 id 定位、增删改) */\n aiOperable: boolean\n /** 能否协同编辑 */\n collaborative: boolean\n /** 支持导入的扩展名 */\n importExtensions: string[]\n /** 支持导出的格式 */\n exportFormats: string[]\n}\n\nexport interface FormatAdapter {\n format: DocumentFormat\n /** 展示名,给 UI 用 */\n label: string\n capabilities: FormatCapabilities\n /** 该格式认领哪些扩展名(小写、带点) */\n extensions: string[]\n /**\n * 懒加载视图组件。**必须是动态 import**,否则引擎会被打进主包。\n */\n load: () => Promise<{ default: ComponentType<DocumentViewProps> }>\n}\n\nexport interface DocumentViewProps {\n /** 文档来源:URL / File / 已有内容 */\n source?: string | Blob | File\n /** 已有内容(doc 走 tiptap JSON 或 HTML;sheet 走 Univer snapshot) */\n content?: unknown\n readOnly?: boolean\n /** 协同房间号,仅 collaborative 为 true 的格式有意义 */\n room?: string\n className?: string\n /**\n * sheet 通道专属配置(Univer preset 与 UI 开关),其它格式忽略。\n *\n * 放在这里而不是只给 `SheetView`,是因为宿主通常只见得到 `DocumentView`\n * 这一层路由 —— 配置进不来的话,只读预览就只能顶着整条编辑工具条。\n */\n sheet?: SheetOptions\n /** 引擎就绪回调,拿到底层实例(tiptap Editor / Univer API / PDFDocumentProxy) */\n onReady?: (instance: unknown) => void\n onError?: (error: Error) => void\n}\n\nconst registry = new Map<DocumentFormat, FormatAdapter>()\n\nexport function registerFormat(adapter: FormatAdapter): void {\n registry.set(adapter.format, adapter)\n}\n\nexport function getFormat(format: DocumentFormat): FormatAdapter | undefined {\n return registry.get(format)\n}\n\nexport function listFormats(): FormatAdapter[] {\n return [...registry.values()]\n}\n\n/** 按扩展名判定格式。传文件名、路径或裸扩展名都行。 */\nexport function detectFormat(nameOrExt: string): DocumentFormat | undefined {\n const m = /\\.([a-z0-9]+)$/i.exec(nameOrExt.trim())\n const ext = `.${(m ? m[1] : nameOrExt.replace(/^\\./, \"\")).toLowerCase()}`\n for (const a of registry.values()) if (a.extensions.includes(ext)) return a.format\n return undefined\n}\n\n/* --------------------------- 内置格式 --------------------------- */\n\nregisterFormat({\n format: \"doc\",\n label: \"文档\",\n extensions: [\".doc\", \".docx\", \".dot\", \".dotx\", \".docm\", \".dotm\", \".wps\", \".wpt\", \".md\", \".html\"],\n capabilities: {\n editable: true,\n aiOperable: true,\n collaborative: true,\n importExtensions: [\".docx\", \".md\", \".html\"],\n exportFormats: [\"docx\", \"html\", \"json\", \"markdown\"],\n },\n load: () => import(\"./views/DocView\"),\n})\n\nregisterFormat({\n format: \"sheet\",\n label: \"表格\",\n extensions: [\".xls\", \".xlsx\", \".xlt\", \".xltx\", \".xlsm\", \".xltm\", \".csv\", \".tsv\"],\n capabilities: {\n editable: true,\n aiOperable: true,\n collaborative: false, // Univer 协同属于 Pro,OSS 核心不含\n importExtensions: [\".xlsx\", \".csv\"],\n // 导出实现分别在 ./xlsx 与 ./csv 两个子路径。csv 是单表格式,\n // 只导活动表、其余表在 warnings 里点名\n exportFormats: [\"xlsx\", \"csv\"],\n },\n load: () => import(\"./views/SheetView\"),\n})\n\nregisterFormat({\n format: \"pdf\",\n label: \"PDF\",\n extensions: [\".pdf\"],\n capabilities: {\n editable: false, // 只读预览。PDF 编辑是 OOXML 引擎那一档的事\n aiOperable: false,\n collaborative: false,\n importExtensions: [\".pdf\"],\n exportFormats: [],\n },\n load: () => import(\"./views/PdfView\"),\n})\n\n/**\n * pptx **只读预览**,引擎是 `pptx-preview`(可选 peer)。\n *\n * 只申报 OOXML 那几个扩展名。`.ppt` / `.pps` / `.pot` 是二进制复合文档、\n * 根本不是 zip,该库解不了 —— 列进来就是假申报,宁可让它落到「暂不支持」。\n *\n * **编辑仍然不做。** Univer Slides 官方文档原文写着「请勿用于生产环境」,\n * 开源世界里没有第二个可用的前端 pptx 编辑引擎;真要做只有\n * OnlyOffice / Collabora 那一档(AGPL,需法务口径 + 独立部署)。\n *\n * 预览的保真度边界见 `views/PptxView` 的注释 —— 尤其**图表渲染不出数据**。\n * 需要更高保真的宿主可以用同名 `registerFormat` 覆盖掉本通道:\n *\n * ```ts\n * registerFormat({ format: \"pptx\", label: \"演示文稿\", extensions: [\".pptx\"],\n * capabilities: { editable: false, aiOperable: false, collaborative: false,\n * importExtensions: [], exportFormats: [] },\n * load: () => import(\"./MyOnlyOfficeSlideView\") })\n * ```\n */\nregisterFormat({\n format: \"pptx\",\n label: \"演示文稿\",\n extensions: [\".pptx\", \".ppsx\", \".potx\", \".pptm\", \".ppsm\", \".potm\"],\n capabilities: {\n editable: false,\n aiOperable: false,\n collaborative: false,\n importExtensions: [\".pptx\"],\n exportFormats: [],\n },\n load: () => import(\"./views/PptxView\"),\n})\n","import { Suspense, lazy, useMemo, type ComponentType, type ReactNode } from \"react\"\nimport { detectFormat, getFormat, type DocumentFormat, type DocumentViewProps } from \"./registry\"\n\nexport interface DocumentViewComponentProps extends DocumentViewProps {\n /** 文档格式。不传则尝试从 source 的扩展名推断 */\n format?: DocumentFormat\n /** 引擎加载中的占位 */\n fallback?: ReactNode\n /** 格式不支持时的兜底渲染。不传则渲染一段说明文字 */\n unsupported?: (format: string) => ReactNode\n}\n\n/**\n * 按格式路由到对应引擎,引擎按需下载。\n *\n * 为什么用 registry + lazy 而不是 if/else 直接 import:\n * 直接 import 会让 Univer(871KB gzip)和 pdf.js 无条件进主包,\n * 哪怕用户从头到尾只看文章。这在阅读侧是不可接受的 ——\n * 本仓刚做完「服务端直出 588KB」的优化,一个表格引擎就能全毁掉。\n */\nexport function DocumentView({\n format,\n source,\n fallback,\n unsupported,\n ...rest\n}: DocumentViewComponentProps) {\n const resolved = useMemo<DocumentFormat | undefined>(() => {\n if (format) return format\n const name = typeof source === \"string\" ? source : (source as File | undefined)?.name\n if (!name) return undefined\n return detectFormat(name)\n }, [format, source])\n\n const adapter = resolved ? getFormat(resolved) : undefined\n\n const View = useMemo<ComponentType<DocumentViewProps> | null>(() => {\n if (!adapter) return null\n return lazy(adapter.load)\n }, [adapter])\n\n if (!adapter || !View) {\n return (\n <>\n {unsupported?.(String(resolved ?? \"unknown\")) ?? (\n <div data-editor-unsupported={String(resolved ?? \"unknown\")}>\n 暂不支持该格式{resolved ? `(${resolved})` : \"\"}。\n 可通过 registerFormat() 注册自有引擎。\n </div>\n )}\n </>\n )\n }\n\n return (\n <Suspense fallback={fallback ?? <div data-editor-loading={adapter.format} />}>\n <View source={source} {...rest} />\n </Suspense>\n )\n}\n","/**\n * @4399ywkf/editor —— 多格式文档编辑器\n *\n * 主入口只放**格式路由与能力申报**,具体引擎全部懒加载。\n * 直接 import 这里不会把 tiptap / Univer / pdf.js 打进你的主包。\n *\n * ```tsx\n * import { DocumentView, detectFormat } from \"@4399ywkf/editor\"\n * import \"@4399ywkf/editor/styles\"\n *\n * <DocumentView format={detectFormat(\"年度报告.docx\")} content={html} />\n * ```\n *\n * 需要直接用某个引擎时走子路径,能拿到完整 API:\n *\n * ```ts\n * import { NotionEditor } from \"@4399ywkf/editor/doc\"\n * import { ImportDocx, ExportDocx } from \"@4399ywkf/editor/docx\"\n * ```\n */\n\nexport { DocumentView, type DocumentViewComponentProps } from \"./DocumentView\"\nexport {\n type DocumentFormat,\n type DocumentViewProps,\n detectFormat,\n type FormatAdapter,\n type FormatCapabilities,\n getFormat,\n listFormats,\n registerFormat,\n} from \"./registry\"\n\nexport type { SheetOptions, SheetUiOptions } from \"./sheet-options\"\n\nexport const VERSION = \"0.1.0\"\n"]}
package/dist/pptx.d.ts ADDED
@@ -0,0 +1,36 @@
1
+ import { D as DocumentViewProps } from './registry-BBL8yeIT.js';
2
+ import * as react from 'react';
3
+
4
+ /**
5
+ * pptx 的「幽灵 slideMaster」修复。
6
+ *
7
+ * 很多 pptx 的 `[Content_Types].xml` 里声明了 zip 中**并不存在**的
8
+ * `ppt/slideMasters/slideMasterN.xml`。PowerPoint 自己不介意,但 `pptx-preview`
9
+ * 会因为解析不到这些部件而整份失败 —— 表现是 `slideCount === 0`、面板一片空白,
10
+ * 不抛错、不报警。
11
+ *
12
+ * 这不是边缘情况:在 17 份真实文件上实测,**12 份中招**(AI 生成的和
13
+ * PowerPoint 16 存出来的都有)。裸接这个库只有 5/17 能打开,加上本修复后 17/17。
14
+ *
15
+ * 做法与腾讯 WorkBuddy 内置 pptx 预览里的 `checkPPTXFile` 一致:删掉指向缺失
16
+ * 部件的 `<Override>` 再重新打包。只处理 slideMaster —— 其它部件缺失时该库
17
+ * 能自己降级,动它反而可能改坏。
18
+ */
19
+ interface RepairPptxResult {
20
+ /** 修好的字节;没问题时**原样返回入参**,不做无谓的解压重打包 */
21
+ bytes: Uint8Array;
22
+ /** 删掉了几条幽灵声明。0 表示这份文件本来就是好的 */
23
+ removed: number;
24
+ /** 修复过程中放弃的原因(文件不是 zip、没有 [Content_Types].xml 等) */
25
+ skipped?: string;
26
+ }
27
+ /**
28
+ * @param input pptx 原始字节
29
+ * @returns 可交给 `pptx-preview` 的字节。**任何异常都退回原字节** ——
30
+ * 修不了也不该让预览失败,让引擎自己去报它的错。
31
+ */
32
+ declare function repairPptx(input: Uint8Array): RepairPptxResult;
33
+
34
+ declare function PptxView({ source, content, className, onReady, onError, }: DocumentViewProps): react.JSX.Element;
35
+
36
+ export { DocumentViewProps, PptxView, type RepairPptxResult, repairPptx };
package/dist/pptx.js ADDED
@@ -0,0 +1,3 @@
1
+ export { PptxView, repairPptx } from './chunk-5XG4YMAB.js';
2
+ //# sourceMappingURL=pptx.js.map
3
+ //# sourceMappingURL=pptx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"pptx.js"}
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Univer 快照的结构化镜像。
3
+ *
4
+ * 为什么不直接 `import type { IWorkbookData } from "@univerjs/core"`:
5
+ * 那是**可选 peer**。没装 `@univerjs/presets` 的项目一解析不到这个模块,
6
+ * 整个包的 typecheck 就红了 —— 而「拿快照出 xlsx」恰恰是最不该逼人装 871KB
7
+ * 渲染引擎的场景(服务端定时导出、Node 里跑批都只有 JSON)。
8
+ *
9
+ * 所以这里只声明导出真正读到的字段,字段名与取值语义和 `@univerjs/core`
10
+ * 逐一对齐。Univer 加字段不会影响这里;改字段含义会 —— 那种时候本文件是
11
+ * 唯一需要改的地方。
12
+ */
13
+ type CellValue = string | number | boolean;
14
+ interface ColorStyle {
15
+ /** `#RRGGBB` / `rgb(r,g,b)` / `rgba(r,g,b,a)` */
16
+ rgb?: string | null;
17
+ /** 主题色 token。xlsx 侧解析不了,直接忽略 */
18
+ th?: number;
19
+ }
20
+ /** 下划线 / 删除线 / 上划线 */
21
+ interface TextDecorationData {
22
+ /** 0 关 1 开 */
23
+ s?: number;
24
+ cl?: ColorStyle | null;
25
+ t?: number;
26
+ }
27
+ interface BorderStyleData {
28
+ /** 对齐 `BorderStyleTypes` */
29
+ s?: number;
30
+ cl?: ColorStyle | null;
31
+ }
32
+ interface BorderData {
33
+ t?: BorderStyleData | null;
34
+ r?: BorderStyleData | null;
35
+ b?: BorderStyleData | null;
36
+ l?: BorderStyleData | null;
37
+ }
38
+ interface TextRotation {
39
+ /** 角度,-90 ~ 90,正数逆时针 */
40
+ a?: number;
41
+ /** 1 = 竖排 */
42
+ v?: number;
43
+ }
44
+ interface StyleData {
45
+ /** fontFamily */
46
+ ff?: string | null;
47
+ /** fontSize,pt */
48
+ fs?: number;
49
+ /** italic */
50
+ it?: number;
51
+ /** bold */
52
+ bl?: number;
53
+ /** underline */
54
+ ul?: TextDecorationData | null;
55
+ /** strikethrough */
56
+ st?: TextDecorationData | null;
57
+ /** overline —— xlsx 没有对应表达 */
58
+ ol?: TextDecorationData | null;
59
+ /** background */
60
+ bg?: ColorStyle | null;
61
+ /** border */
62
+ bd?: BorderData | null;
63
+ /** font color */
64
+ cl?: ColorStyle | null;
65
+ /** 上下标 */
66
+ va?: number | null;
67
+ /** 数字格式 */
68
+ n?: {
69
+ pattern?: string;
70
+ } | null;
71
+ /** textRotation */
72
+ tr?: TextRotation | null;
73
+ /** horizontalAlign */
74
+ ht?: number | null;
75
+ /** verticalAlign */
76
+ vt?: number | null;
77
+ /** wrapStrategy */
78
+ tb?: number | null;
79
+ }
80
+ /** 富文本单元格。导出只取纯文本 —— xlsx 的富文本要拆成 `<si><r>` 段,收益不抵复杂度 */
81
+ interface RichTextData {
82
+ body?: {
83
+ dataStream?: string;
84
+ } | null;
85
+ }
86
+ interface CellData {
87
+ v?: CellValue | null;
88
+ /** 对齐 `CellValueType` */
89
+ t?: number | null;
90
+ /** 原始公式,含前导 `=` */
91
+ f?: string | null;
92
+ /** 共享公式组 id。同组里只有一个单元格带 `f` */
93
+ si?: string | null;
94
+ /** 数组公式的引用范围 */
95
+ ref?: string | null;
96
+ /** 样式 id 或内联样式 */
97
+ s?: StyleData | string | null;
98
+ /** 富文本 */
99
+ p?: RichTextData | null;
100
+ }
101
+ interface RowData {
102
+ /** 高度 px */
103
+ h?: number;
104
+ /** 自适应高度 px,`ia` 为 1 时用它 */
105
+ ah?: number;
106
+ /** 是否自适应 */
107
+ ia?: number;
108
+ /** 隐藏 */
109
+ hd?: number;
110
+ s?: StyleData | string | null;
111
+ }
112
+ interface ColumnData {
113
+ /** 宽度 px */
114
+ w?: number;
115
+ hd?: number;
116
+ s?: StyleData | string | null;
117
+ }
118
+ interface CellRange {
119
+ startRow: number;
120
+ startColumn: number;
121
+ endRow: number;
122
+ endColumn: number;
123
+ }
124
+ interface FreezeData {
125
+ /** 冻结列数 */
126
+ xSplit: number;
127
+ /** 冻结行数 */
128
+ ySplit: number;
129
+ startRow: number;
130
+ startColumn: number;
131
+ }
132
+ /** `IObjectMatrixPrimitiveType<T>`:行号 → 列号 → 值,两层都是稀疏对象 */
133
+ type Matrix<T> = Record<number, Record<number, T> | undefined>;
134
+ interface WorksheetData {
135
+ id?: string;
136
+ name?: string;
137
+ /** `#RRGGBB` */
138
+ tabColor?: string;
139
+ /** 1 = 隐藏 */
140
+ hidden?: number;
141
+ freeze?: FreezeData;
142
+ rowCount?: number;
143
+ columnCount?: number;
144
+ /** px */
145
+ defaultColumnWidth?: number;
146
+ /** px */
147
+ defaultRowHeight?: number;
148
+ mergeData?: CellRange[];
149
+ cellData?: Matrix<CellData>;
150
+ rowData?: Record<number, RowData | undefined>;
151
+ columnData?: Record<number, ColumnData | undefined>;
152
+ /** 0 = 不显示网格线 */
153
+ showGridlines?: number;
154
+ /** 1 = 从右向左 */
155
+ rightToLeft?: number;
156
+ defaultStyle?: StyleData | string | null;
157
+ }
158
+ interface WorkbookData {
159
+ id?: string;
160
+ name?: string;
161
+ /** 工作表顺序。缺省时按 `sheets` 的键序 */
162
+ sheetOrder?: string[];
163
+ sheets?: Record<string, WorksheetData | undefined>;
164
+ /** 样式表:`CellData.s` 为字符串时查这里 */
165
+ styles?: Record<string, StyleData | null | undefined>;
166
+ defaultStyle?: StyleData | string | null;
167
+ /**
168
+ * 各插件自己序列化的数据(图片、条件格式、数据校验、筛选……)。
169
+ * 导出读不了它们的私有结构,但**能据此如实报告丢了什么** —— 见 `warnings`。
170
+ */
171
+ resources?: Array<{
172
+ id?: string;
173
+ name: string;
174
+ data: string;
175
+ }>;
176
+ }
177
+
178
+ export type { CellData as C, RowData as R, StyleData as S, WorkbookData as W, WorksheetData as a, CellRange as b, CellValue as c, ColumnData as d };
package/dist/xlsx.d.ts CHANGED
@@ -1,179 +1,5 @@
1
- /**
2
- * Univer 快照的结构化镜像。
3
- *
4
- * 为什么不直接 `import type { IWorkbookData } from "@univerjs/core"`:
5
- * 那是**可选 peer**。没装 `@univerjs/presets` 的项目一解析不到这个模块,
6
- * 整个包的 typecheck 就红了 —— 而「拿快照出 xlsx」恰恰是最不该逼人装 871KB
7
- * 渲染引擎的场景(服务端定时导出、Node 里跑批都只有 JSON)。
8
- *
9
- * 所以这里只声明导出真正读到的字段,字段名与取值语义和 `@univerjs/core`
10
- * 逐一对齐。Univer 加字段不会影响这里;改字段含义会 —— 那种时候本文件是
11
- * 唯一需要改的地方。
12
- */
13
- type CellValue = string | number | boolean;
14
- interface ColorStyle {
15
- /** `#RRGGBB` / `rgb(r,g,b)` / `rgba(r,g,b,a)` */
16
- rgb?: string | null;
17
- /** 主题色 token。xlsx 侧解析不了,直接忽略 */
18
- th?: number;
19
- }
20
- /** 下划线 / 删除线 / 上划线 */
21
- interface TextDecorationData {
22
- /** 0 关 1 开 */
23
- s?: number;
24
- cl?: ColorStyle | null;
25
- t?: number;
26
- }
27
- interface BorderStyleData {
28
- /** 对齐 `BorderStyleTypes` */
29
- s?: number;
30
- cl?: ColorStyle | null;
31
- }
32
- interface BorderData {
33
- t?: BorderStyleData | null;
34
- r?: BorderStyleData | null;
35
- b?: BorderStyleData | null;
36
- l?: BorderStyleData | null;
37
- }
38
- interface TextRotation {
39
- /** 角度,-90 ~ 90,正数逆时针 */
40
- a?: number;
41
- /** 1 = 竖排 */
42
- v?: number;
43
- }
44
- interface StyleData {
45
- /** fontFamily */
46
- ff?: string | null;
47
- /** fontSize,pt */
48
- fs?: number;
49
- /** italic */
50
- it?: number;
51
- /** bold */
52
- bl?: number;
53
- /** underline */
54
- ul?: TextDecorationData | null;
55
- /** strikethrough */
56
- st?: TextDecorationData | null;
57
- /** overline —— xlsx 没有对应表达 */
58
- ol?: TextDecorationData | null;
59
- /** background */
60
- bg?: ColorStyle | null;
61
- /** border */
62
- bd?: BorderData | null;
63
- /** font color */
64
- cl?: ColorStyle | null;
65
- /** 上下标 */
66
- va?: number | null;
67
- /** 数字格式 */
68
- n?: {
69
- pattern?: string;
70
- } | null;
71
- /** textRotation */
72
- tr?: TextRotation | null;
73
- /** horizontalAlign */
74
- ht?: number | null;
75
- /** verticalAlign */
76
- vt?: number | null;
77
- /** wrapStrategy */
78
- tb?: number | null;
79
- }
80
- /** 富文本单元格。导出只取纯文本 —— xlsx 的富文本要拆成 `<si><r>` 段,收益不抵复杂度 */
81
- interface RichTextData {
82
- body?: {
83
- dataStream?: string;
84
- } | null;
85
- }
86
- interface CellData {
87
- v?: CellValue | null;
88
- /** 对齐 `CellValueType` */
89
- t?: number | null;
90
- /** 原始公式,含前导 `=` */
91
- f?: string | null;
92
- /** 共享公式组 id。同组里只有一个单元格带 `f` */
93
- si?: string | null;
94
- /** 数组公式的引用范围 */
95
- ref?: string | null;
96
- /** 样式 id 或内联样式 */
97
- s?: StyleData | string | null;
98
- /** 富文本 */
99
- p?: RichTextData | null;
100
- }
101
- interface RowData {
102
- /** 高度 px */
103
- h?: number;
104
- /** 自适应高度 px,`ia` 为 1 时用它 */
105
- ah?: number;
106
- /** 是否自适应 */
107
- ia?: number;
108
- /** 隐藏 */
109
- hd?: number;
110
- s?: StyleData | string | null;
111
- }
112
- interface ColumnData {
113
- /** 宽度 px */
114
- w?: number;
115
- hd?: number;
116
- s?: StyleData | string | null;
117
- }
118
- interface CellRange {
119
- startRow: number;
120
- startColumn: number;
121
- endRow: number;
122
- endColumn: number;
123
- }
124
- interface FreezeData {
125
- /** 冻结列数 */
126
- xSplit: number;
127
- /** 冻结行数 */
128
- ySplit: number;
129
- startRow: number;
130
- startColumn: number;
131
- }
132
- /** `IObjectMatrixPrimitiveType<T>`:行号 → 列号 → 值,两层都是稀疏对象 */
133
- type Matrix<T> = Record<number, Record<number, T> | undefined>;
134
- interface WorksheetData {
135
- id?: string;
136
- name?: string;
137
- /** `#RRGGBB` */
138
- tabColor?: string;
139
- /** 1 = 隐藏 */
140
- hidden?: number;
141
- freeze?: FreezeData;
142
- rowCount?: number;
143
- columnCount?: number;
144
- /** px */
145
- defaultColumnWidth?: number;
146
- /** px */
147
- defaultRowHeight?: number;
148
- mergeData?: CellRange[];
149
- cellData?: Matrix<CellData>;
150
- rowData?: Record<number, RowData | undefined>;
151
- columnData?: Record<number, ColumnData | undefined>;
152
- /** 0 = 不显示网格线 */
153
- showGridlines?: number;
154
- /** 1 = 从右向左 */
155
- rightToLeft?: number;
156
- defaultStyle?: StyleData | string | null;
157
- }
158
- interface WorkbookData {
159
- id?: string;
160
- name?: string;
161
- /** 工作表顺序。缺省时按 `sheets` 的键序 */
162
- sheetOrder?: string[];
163
- sheets?: Record<string, WorksheetData | undefined>;
164
- /** 样式表:`CellData.s` 为字符串时查这里 */
165
- styles?: Record<string, StyleData | null | undefined>;
166
- defaultStyle?: StyleData | string | null;
167
- /**
168
- * 各插件自己序列化的数据(图片、条件格式、数据校验、筛选……)。
169
- * 导出读不了它们的私有结构,但**能据此如实报告丢了什么** —— 见 `warnings`。
170
- */
171
- resources?: Array<{
172
- id?: string;
173
- name: string;
174
- data: string;
175
- }>;
176
- }
1
+ import { W as WorkbookData } from './types-C37MAt8o.js';
2
+ export { C as CellData, b as CellRange, c as CellValue, d as ColumnData, R as RowData, S as StyleData, a as WorksheetData } from './types-C37MAt8o.js';
177
3
 
178
4
  /**
179
5
  * Univer 快照 → xlsx 的各个 XML 部件。
@@ -217,6 +43,15 @@ interface SerializeXlsxResult {
217
43
  }
218
44
  declare function serializeXlsx(workbook: WorkbookData, options?: SerializeXlsxOptions): SerializeXlsxResult;
219
45
 
46
+ /** 从 Univer 实例取快照。xlsx 与 csv 两条导出路径共用。 */
47
+
48
+ /**
49
+ * 参数类型是 `unknown` 而不是 `FUniver`:`@univerjs/presets` 是可选 peer,
50
+ * 写成具体类型会让没装它的项目 typecheck 直接红。运行时按 facade 的两个
51
+ * 方法名依次试探(`getSnapshot` 是新名字,`save` 是旧的)。
52
+ */
53
+ declare function snapshotFromUniver(univerAPI: unknown): WorkbookData;
54
+
220
55
  /**
221
56
  * `@4399ywkf/editor/xlsx` —— 表格导出。
222
57
  *
@@ -251,14 +86,6 @@ interface XlsxResult {
251
86
  }
252
87
  /** 纯函数:Univer 快照 → .xlsx 字节。不依赖 DOM 与引擎,服务端 / 测试直接可用。 */
253
88
  declare function xlsxFromSnapshot(workbook: WorkbookData, options?: SerializeXlsxOptions): XlsxResult;
254
- /**
255
- * 从 Univer 实例取快照。
256
- *
257
- * 参数类型是 `unknown` 而不是 `FUniver`:`@univerjs/presets` 是可选 peer,
258
- * 写成具体类型会让没装它的项目 typecheck 直接红。运行时按 facade 的两个
259
- * 方法名依次试探(`getSnapshot` 是新名字,`save` 是旧的)。
260
- */
261
- declare function snapshotFromUniver(univerAPI: unknown): WorkbookData;
262
89
  /** Univer 实例或快照 → .xlsx 字节 */
263
90
  declare function exportXlsx(source: WorkbookData | unknown, options?: SerializeXlsxOptions): XlsxResult;
264
91
  /** Univer 实例或快照 → Blob,便于交给上传接口 */
@@ -270,4 +97,4 @@ declare function xlsxBlob(source: WorkbookData | unknown, options?: SerializeXls
270
97
  */
271
98
  declare function downloadXlsx(source: WorkbookData | unknown, filename?: string, options?: SerializeXlsxOptions): XlsxResult;
272
99
 
273
- export { type CellData, type CellRange, type CellValue, type ColumnData, type RowData, type SerializeXlsxOptions, type SerializeXlsxResult, type StyleData, type WorkbookData, type WorksheetData, XLSX_MIME, type XlsxResult, downloadXlsx, exportXlsx, serializeXlsx, snapshotFromUniver, xlsxBlob, xlsxFromSnapshot };
100
+ export { type SerializeXlsxOptions, type SerializeXlsxResult, WorkbookData, XLSX_MIME, type XlsxResult, downloadXlsx, exportXlsx, serializeXlsx, snapshotFromUniver, xlsxBlob, xlsxFromSnapshot };
package/dist/xlsx.js CHANGED
@@ -1,7 +1,7 @@
1
+ import { numericKeys, richTextToPlain, toSnapshot } from './chunk-32WQX3NR.js';
2
+ export { snapshotFromUniver } from './chunk-32WQX3NR.js';
1
3
  import { zipSync } from 'fflate';
2
4
 
3
- // src/xlsx/index.ts
4
-
5
5
  // src/xlsx/types.ts
6
6
  var CELL_TYPE = {
7
7
  /** 强制文本:用户输入 `'0123` 这类本该被当数字的内容 */
@@ -277,15 +277,6 @@ var BAD_SHEET_NAME = /[\\/?*[\]:]/g;
277
277
  var RELS_NS = 'xmlns="http://schemas.openxmlformats.org/package/2006/relationships"';
278
278
  var MAIN_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
279
279
  var DOC_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
280
- function numericKeys(o) {
281
- if (!o) return [];
282
- return Object.keys(o).map(Number).filter((n) => Number.isInteger(n) && n >= 0).sort((a, b) => a - b);
283
- }
284
- function richTextToPlain(cell) {
285
- const stream = cell.p?.body?.dataStream;
286
- if (typeof stream !== "string") return void 0;
287
- return stream.replace(/\r\n$/, "").replace(/\r/g, "\n");
288
- }
289
280
  function serializeXlsx(workbook, options = {}) {
290
281
  const { cachedFormulaValues = true, creator = "@4399ywkf/editor", created = /* @__PURE__ */ new Date() } = options;
291
282
  const warnings = [];
@@ -570,22 +561,6 @@ function xlsxFromSnapshot(workbook, options = {}) {
570
561
  const { files, warnings, stats } = serializeXlsx(workbook, options);
571
562
  return { bytes: zipSync(files, { level: 6 }), warnings, stats };
572
563
  }
573
- function snapshotFromUniver(univerAPI) {
574
- const api = univerAPI;
575
- const book = api?.getActiveWorkbook?.();
576
- if (!book) throw new Error("拿不到当前工作簿:univerAPI 无效,或表格尚未就绪");
577
- const snapshot = book.getSnapshot?.() ?? book.save?.();
578
- if (!snapshot || typeof snapshot !== "object") {
579
- throw new Error("当前 Univer 版本没有 getSnapshot() / save(),无法取快照");
580
- }
581
- return snapshot;
582
- }
583
- function toSnapshot(source) {
584
- const maybe = source;
585
- if (maybe && typeof maybe === "object" && ("sheets" in maybe || "sheetOrder" in maybe))
586
- return maybe;
587
- return snapshotFromUniver(source);
588
- }
589
564
  function exportXlsx(source, options) {
590
565
  return xlsxFromSnapshot(toSnapshot(source), options);
591
566
  }
@@ -608,6 +583,6 @@ function downloadXlsx(source, filename = "工作簿.xlsx", options) {
608
583
  return result;
609
584
  }
610
585
 
611
- export { XLSX_MIME, downloadXlsx, exportXlsx, serializeXlsx, snapshotFromUniver, xlsxBlob, xlsxFromSnapshot };
586
+ export { XLSX_MIME, downloadXlsx, exportXlsx, serializeXlsx, xlsxBlob, xlsxFromSnapshot };
612
587
  //# sourceMappingURL=xlsx.js.map
613
588
  //# sourceMappingURL=xlsx.js.map