ooxml-excel-editor 1.11.0 → 1.14.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/CHANGELOG.md CHANGED
@@ -2,6 +2,45 @@
2
2
 
3
3
  本项目遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/) 与 [语义化版本](https://semver.org/lang/zh-CN/)。
4
4
 
5
+ ## [1.14.0] - 2026-06-15
6
+
7
+ > 新增**内置公式引擎**(MIT,零依赖)设为 recalc 默认引擎(取代 GPL 的 HyperFormula),+ **公式自动补全**。覆盖日常 ~60 个常用函数;需更全覆盖可注入 HyperFormula 或自研引擎。
8
+
9
+ ### 新增 — 内置 MIT 公式引擎(默认)
10
+
11
+ - **从零实现**(`formula/builtin/`):词法 + 表达式解析(运算符优先级 / `A1` 绝对相对 / 区域 `A1:B2` / 跨表 `Sheet1!A1` / 函数 / 一元 ± / `%`)→ AST;求值器(错误就近传播 `#DIV/0! #N/A #NAME? #NUM! #REF! #VALUE!`);**依赖图 + 拓扑级联重算 + 循环引用检测**(环上格 → `#REF!`)。
12
+ - **函数 ~60**:聚合(SUM/AVERAGE/MAX/MIN/COUNT/COUNTA/PRODUCT/SUMPRODUCT)、数学(ROUND/ROUNDUP/ROUNDDOWN/ABS/INT/MOD/SQRT/POWER/CEILING/FLOOR…)、逻辑(IF/IFERROR/IFNA/AND/OR/NOT/XOR/IFS)、文本(LEFT/RIGHT/MID/LEN/CONCAT/UPPER/LOWER/TRIM/SUBSTITUTE/FIND/SEARCH…)、查找(VLOOKUP/HLOOKUP/INDEX/MATCH/CHOOSE)、条件聚合(SUMIF/COUNTIF/AVERAGEIF)、信息(ISNUMBER/ISBLANK/ISERROR…)、日期(TODAY/NOW/DATE/YEAR/MONTH/DAY/WEEKDAY/DAYS)。
13
+ - **★ 默认引擎变更**:recalc(`:recalc`,opt-in)的默认引擎由 **HyperFormula → 内置引擎**。好处:**MIT 无 GPL 顾虑、零额外依赖、不再懒加载 ~400KB**。代价:函数集比 HyperFormula 的 ~395 小(日常足够)。
14
+ - **HyperFormula 仍可用**:注入 `:formula-engine="hyperFormulaEngineFactory"`(或自研)获得更全覆盖。`core` 新导出 `builtinFormulaEngineFactory` / `BuiltinFormulaEngine` / `FUNCTION_NAMES` / `hyperFormulaEngineFactory`;`defaultFormulaEngineFactory` 保留为 HyperFormula 别名(向后兼容显式注入它的旧代码)。
15
+ - **解析/显示不受影响**:打开文件仍显示原件缓存的计算结果(与引擎无关);引擎只在编辑后重算时介入。
16
+ ### 新增 — 公式自动补全
17
+
18
+ - 在框架无关默认单元格编辑器(`edit/formula-autocomplete.ts`,三壳自动都有)里:输 `=SU` 时下方弹**函数名列表 + 参数提示**(`FUNCTION_SIGNATURES`);↑↓ 选、Enter/Tab 接受(插入 `NAME(` 并把光标移进括号)、Esc 关、点选即填。只在公式(`=` 开头)且光标处于函数名 token 时弹,不影响普通文本编辑。列表来源 = 引擎实际支持的函数(`FUNCTION_NAMES`),所见即所得。
19
+ - 测试:`formula/builtin/__tests__`(parse 12 + eval 11 + engine 7 = 30 例:运算符/函数/级联/循环/跨表);`e2e/formula-autocomplete.e2e.ts`(=SU→弹 SUM→点选插入,三壳);现有 `edit-formula.e2e.ts` 重算 e2e 改由内置引擎驱动仍全过。基线:**419 单测 + 192 e2e**。
20
+
21
+ ## [1.13.0] - 2026-06-15
22
+
23
+ > 新增 **不连续多区域选择**(Ctrl/⌘ + 点击)。选区模型从单矩形扩成多矩形;纯框架无关 core 交互,壳只转发鼠标。
24
+
25
+ ### 新增 — Ctrl 多区域选择
26
+
27
+ - **Ctrl/⌘ + 点击** 行头 / 列头 / 单元格 → 把当前选区收进多选集再起新区,**加选不相邻**区域(Shift 仍是连续区间,已有);普通点击 / 键盘导航 / `selectCell` / 全选回到单选。
28
+ - 选区模型加 `selRanges[]` + `getSelectionRanges()`(全部矩形,末个为活动区)/ `hasMultiSelection()`;`canvas-renderer` 加 `setExtraSelection` 画所有附加区(填充 + 边框;多选时不画自动填充柄,对齐 Excel)。
29
+ - **复制**:多选时各区按出现顺序**逐行堆叠**成块 → TSV + HTML 表写剪贴板(覆盖最常见的"Ctrl 点多个行头复制非相邻行",粘到 Excel/WPS / app 内都成堆叠块)。
30
+ - **状态栏统计**跨所有选区聚合(count/sum/avg/min/max);新增控制器 `getSelectionStats()`,三壳状态栏改用它。
31
+ - 三壳句柄 + 插件 `ViewerApi` 暴露 `getSelectionRanges` / `hasMultiSelection`。测试:`e2e/multi-select.e2e.ts`(Ctrl+点击两不邻行头 → 2 区域 + 回单选,Vue/React/Vue2)。基线:**389 单测 + 189 e2e**。
32
+
33
+ ## [1.12.0] - 2026-06-15
34
+
35
+ > 新增 **格式刷**(Format Painter)。纯框架无关 core 交互(控制器采样 + onMouseUp 刷),壳只加工具栏按钮;需 `editable`。
36
+
37
+ ### 新增 — 格式刷
38
+
39
+ - 工具栏 `format-painter` 入口:先选**源格**点按钮采样其完整样式(字体/填充/边框/对齐/换行/数字格式),再**点或拖**目标格/区域即刷上(单次撤销);`Esc` 或再点按钮退出,待刷时光标变 `copy`。
40
+ - 控制器 `startFormatPainter(sticky?)` / `isFormatPainterArmed()` / `cancelFormatPainter()`;刷动作在 `onMouseUp` 选区完成后应用(复用 setStyle)。三壳句柄 + 插件 `ViewerApi` 暴露;三 demo 工具栏加 `format-painter` 入口(工具栏按钮 active 态反映待刷)。
41
+ - 测试:`e2e/format-painter.e2e.ts`(采样红底 → 刷到目标格 + undo,Vue/React/Vue2 三壳)。
42
+ - 顺手:`toolbar` 溢出相关 e2e 宽屏断言 1280→1680(工具栏又加了按钮,宽屏才全部容纳)。基线:**389 单测 + 186 e2e**。
43
+
5
44
  ## [1.11.0] - 2026-06-15
6
45
 
7
46
  > 三个编辑小件合并:**查找替换补全 + 数字格式编辑器 + 批注编辑**。都复用已有引擎/对话框套路;对话框均为框架无关 DOM(三壳共用一份,UI 天然 1:1)。
package/README.md CHANGED
@@ -48,7 +48,7 @@ const src = ref<File>() // 绑个 <input type="file" @change> 给它即可
48
48
  - 📋 **从 Excel/WPS 富粘贴**:`Ctrl+V` 解析剪贴板 HTML → 还原字体/颜色/填充/边框/对齐/合并单元格,整块单次撤销。**Excel/WPS 把格式放在 `<style>` 块的 CSS 类里(`<td class="xl65">`),解析时会把类规则合并进每格** —— 不只读内联 `style=`。**`Ctrl+V` 走 `paste` 事件拿原始 HTML**;`navigator.clipboard.read()`(右键菜单粘贴用)会**净化**删掉 `<style>`/注释,所以右键粘贴从 WPS 拿的格式不如 `Ctrl+V` 全。图片走多通道:data-uri `<img>` / **WPS VML `o:gfxdata`**(区域复制的内嵌图藏在 VML 里,是个 zip,解出来落格)/ 单图 blob / 拖文件;**数字格式**(日期/货币)也从 `mso-number-format` 解析还原,不再变成裸序列号。**注**:Excel 某些版本只给 `file:///` 本地路径的 `<img>`(浏览器读不到)而不带 `o:gfxdata`,那种区域图仍救不回。
49
49
  - 📋 **应用内 1:1 复制粘贴**:本组件自己 `Ctrl+C` 的内容会把**完整模型快照**嵌进剪贴板(`<table data-ooxml-clip>`),`Ctrl+V` 时识别并 1:1 还原 —— 数字不会退化成文本、边框/数字格式/合并/DISPIMG 图片/**行高**全保留;因为快照随剪贴板走,**Vue3/Vue2/React 三壳之间、跨标签页互相复制结果都一致**。粘到外部应用(Excel/WPS/Word)则读可见 `<table>`(近似)。**列宽以目标现有表头为准、不被源覆盖**(列宽整列共享,改了会动表头;同 Excel 默认粘贴)。
50
50
  - 📝 **文本溢出**到相邻空格、**自动行高**
51
- - 🖱 **交互**:单元格选区(合并感知)、拖选、公式栏、状态栏(计数/求和/均值/最值)、超链接可点、裁切文本悬停看全文、Ctrl+C 复制(**同应用内 1:1 保真**:含数字原始值/数字格式/边框/合并/图片/行高,跨 Vue3/Vue2/React 实例互相复制都一致;**列宽以目标表头为准不覆盖**;另带 TSV/HTML 供贴进 Excel/WPS)、**Ctrl+F 查找替换**(高亮 + 上/下定位 + 计数 + 区分大小写/全字匹配;编辑模式带替换 / 全部替换)、**自动筛选**(点下拉真能筛:去重值多选 + 搜值 + 清除)、**自动填充柄**(编辑模式拖选区右下角填序列:等差/日期/星期月份/文本递增,见 [编辑](#编辑可选默认只读))
51
+ - 🖱 **交互**:单元格选区(合并感知)、拖选、公式栏、状态栏(计数/求和/均值/最值)、超链接可点、裁切文本悬停看全文、Ctrl+C 复制(**同应用内 1:1 保真**:含数字原始值/数字格式/边框/合并/图片/行高,跨 Vue3/Vue2/React 实例互相复制都一致;**列宽以目标表头为准不覆盖**;另带 TSV/HTML 供贴进 Excel/WPS)、**Ctrl+F 查找替换**(高亮 + 上/下定位 + 计数 + 区分大小写/全字匹配;编辑模式带替换 / 全部替换)、**自动筛选**(点下拉真能筛:去重值多选 + 搜值 + 清除)、**自动填充柄**(编辑模式拖选区右下角填序列:等差/日期/星期月份/文本递增,见 [编辑](#编辑可选默认只读))、**不连续多选**(Ctrl/⌘ 点击行头/列头/格 加选不相邻区域,复制堆叠 + 状态栏跨区统计)
52
52
  - 🖨 **导出 / 打印**:整表/选区/多表导出 **PNG/JPEG**、**PDF**(位图 + **矢量·文字可选可搜**两种)、**系统打印**(可另存 PDF);默认还原原生 `pageSetup`(纸张/方向/页边距/缩放/打印区域/**打印标题行列每页重复**);宽表**横向跨页**(页矩阵);`beforeRenderPage` 注入页眉/页脚/水印、`configureDoc` 注册字体;内置「导出设置」对话框
53
53
  - ⚡ **按需加载**(无图表文件不下载 echarts、不导出 PDF 不下载 jspdf)、**友好错误兜底**(损坏/加密/旧 .xls)、解析失败自动给出可读提示
54
54
 
@@ -94,7 +94,7 @@ npm i hyperformula
94
94
 
95
95
  > **三壳 UI 1:1**: Vue 3 SFC 是参考实现 (Standard), Vue 2 / React 1:1 复刻视觉与交互 (工具栏 SVG 图标 / 下拉子菜单 / 公式栏 / 状态栏 / dialog / 浮层 / 演示 demo 全部对齐). 详见 [docs/Vue2.md](./docs/Vue2.md) 跟 Vue 3 的差异速查 + [CLAUDE.md](./CLAUDE.md) 第 7 中心原则。
96
96
 
97
- > ⚠️ **公式重算的许可证**:默认公式引擎是 [HyperFormula](https://hyperformula.handsontable.com/),**GPL-3.0 / 商业 双授权**。本组件以 `licenseKey: 'gpl-v3'` 调用(适合开源/GPL 场景)。**商业闭源项目**请改用 `formulaEngine` prop 注入你自己持有商业 license 的引擎(或自研引擎),只需实现 `FormulaEngine` 接口即可。不开启 `recalc` 时完全不加载 hyperformula,无许可证负担。
97
+ > 公式重算的引擎(1.14.0 起):默认是**内置 MIT 引擎**(零依赖,覆盖 ~60 常用函数,无许可证负担)。需要更全函数集时,`formulaEngine` prop 注入 **HyperFormula**(`hyperFormulaEngineFactory`,GPL-3.0/商业双授权,~395 函数)或自研引擎(实现 `FormulaEngine` 接口)。
98
98
 
99
99
  ## 使用
100
100
 
@@ -302,7 +302,7 @@ viewer.value.getRangeData(viewer.value.getSelection()) // 取"我选中的"区
302
302
  | `readOnlyCellStyle` | `boolean \| CellStyleOverride \| CellStyleFn` | **只读视觉钩子**(Phase C, 2026-06-08)— 默认 `false` 无视觉差异(老行为);`true` 套内置浅灰底 `#f5f7fa`;对象 = 固定样式给所有只读格;函数 = 按格自定义。仅在该格 `editable=false` 时套用,跟 `editableTargets` 配合一眼看出哪些格可编辑。**鼠标光标**: 编辑模式下悬停只读格自动变 `not-allowed`(内置,不可关)。 |
303
303
  | `editor` | `EditorResolver` | 自定义单元格编辑器工厂(返回任意 DOM) |
304
304
  | `recalc` | `boolean` | 公式重算(默认 `false`;需 `editable`) |
305
- | `formulaEngine` | `FormulaEngineFactory` | 自定义/自研公式引擎(默认 HyperFormula) |
305
+ | `formulaEngine` | `FormulaEngineFactory` | 自定义/自研公式引擎(默认 = 内置 MIT 引擎;可注入 `hyperFormulaEngineFactory` 或自研) |
306
306
  | `pasteBehavior` | `Partial<PasteBehavior>` | 粘贴行为(默认 = 覆盖式 1:1)。逐项可配:`cellStyle`/`fill`(`overwrite`/`merge`/`skip`)·`rowHeight`(`source`/`keep`)·`colWidth`(`firstRowOnly`/`source`/`keep`)·`sourceMerges`(`apply`/`skip`)·`targetMerges`(`clear`/`keep`,默认清=修旧合并吞列)·`images`(`apply`/`skip`)。缺项回落默认。也可运行时 `viewer.setPasteBehavior(cfg)` / 右键「选择性粘贴」/ 工具栏「⚙ 粘贴配置」面板 |
307
307
  | `readOnlyPrompt` | `'dialog' \| 'toast' \| 'none'` | 粘贴撞只读格的内置提醒(默认 `'dialog'`):`dialog` 弹窗**列出具体哪些格**只读 / `toast` 顶部气泡 / `none` 只发 `permission-denied` 事件。逐格精确(编辑模式下也可能有只读格) |
308
308
  | `cellImageFit` | `'fill' \| 'contain' \| 'cover'` | WPS 单元格内嵌图贴合方式(默认 `contain` 等比,与 WPS 渲染一致) |
@@ -407,6 +407,14 @@ const myEditor: EditorResolver = (cell, pos) => {
407
407
  - 全部入撤销栈、发 `cell-change`/`image-change`、翻脏标记。(`convertImageToCell(imgIdx,row,col)` 仍保留,用于显式指定目标格。)
408
408
  - **导出往返**:`downloadXlsx()` / `exportXlsx()` 导出时,在 ExcelJS 写出后**于 zip 层回注** WPS 私有件(`cellimages.xml` + rels + media + `[Content_Types].xml`/`workbook.xml.rels` 补丁,从模型重建),原有的 + App 内新转的内嵌图导出后用 WPS 打开都正常显示。rebuild / overlay 两种保真模式均覆盖;无字节的 blob-only 图除外。
409
409
 
410
+ ### 不连续多区域选择(1.13.0)
411
+
412
+ **Ctrl/⌘ + 点击** 行头 / 列头 / 单元格 → 加选不相邻区域(Shift 仍是连续区间);普通点击 / 键盘导航回单选。多选时复制把各区**逐行堆叠**成块(TSV + HTML,粘到 Excel/WPS/app 内都成堆叠块),状态栏统计跨所有区聚合。`getSelectionRanges()` / `hasMultiSelection()` 读多选状态。纯框架无关 core 交互,三壳一致。
413
+
414
+ ### 格式刷(1.12.0)
415
+
416
+ 工具栏 `format-painter` 入口:先选**源格**点按钮采样其完整样式(字体/填充/边框/对齐/换行/数字格式),再**点或拖**目标格/区域即把格式刷上(单次撤销);`Esc` 或再点按钮退出,待刷时光标变 `copy`。也可 `startFormatPainter()` / `isFormatPainterArmed()` / `cancelFormatPainter()` 直调。纯框架无关 core 交互,三壳一致。
417
+
410
418
  ### 数字格式 / 批注 / 查找替换(1.11.0)
411
419
 
412
420
  - **查找替换**:`Ctrl+F` 打开查找栏,编辑模式下多出替换行 —— 替换输入 + 「替换」(替换当前并跳下一个)/「全部替换」(整体单次撤销),支持区分大小写 / 全字匹配,跳过只读格。
@@ -429,7 +437,13 @@ const myEditor: EditorResolver = (cell, pos) => {
429
437
 
430
438
  ### 公式重算(可换引擎)
431
439
 
432
- 开 `:recalc` 后,编辑公式格或被公式引用的格 → 依赖格**自动级联重算**,每个变动都发 `cell-change`(`source: 'api'|'ui'|'undo'|'redo'`)。默认引擎 [HyperFormula](https://hyperformula.handsontable.com/)(可选 peer,`npm i hyperformula`;**GPL-3.0/商业双授权**,商业项目用 `:formula-engine` 注入持牌/自研引擎,实现 `FormulaEngine` 接口即可)。`isRecalcReady()` 查引擎是否就绪(异步懒加载)
440
+ 开 `:recalc` 后,编辑公式格或被公式引用的格 → 依赖格**自动级联重算**,每个变动都发 `cell-change`(`source: 'api'|'ui'|'undo'|'redo'`)。
441
+
442
+ **默认引擎(1.14.0 起)= 内置 MIT 引擎**:从零实现的解析 + 求值 + 依赖图 + 拓扑级联 + 循环检测,**零依赖、无 GPL**,覆盖日常 ~60 个常用函数(SUM/AVERAGE/IF/IFERROR/VLOOKUP/INDEX/MATCH/SUMIF/COUNTIF/ROUND/LEFT/MID/CONCAT/DATE/TODAY… 见 `FUNCTION_NAMES` 导出)。函数集比 HyperFormula 小,但日常足够。
443
+
444
+ 需要更全覆盖:`:formula-engine="hyperFormulaEngineFactory"` 注入 **HyperFormula**(可选 peer `npm i hyperformula`,GPL-3.0/商业双授权,~395 函数),或注入自研引擎(实现 `FormulaEngine` 接口)。`isRecalcReady()` 查引擎是否就绪。**打开文件的显示值与引擎无关**(读原件缓存结果),引擎只在编辑后重算时介入。
445
+
446
+ **公式自动补全**(1.14.0):在单元格里输 `=SU` 时下方弹**函数名列表 + 参数提示**;↑↓ 选、Enter/Tab 接受(插入 `SUM(` 并把光标移进括号)、Esc 关、点选即填。列表 = 引擎实际支持的函数(所见即所得),框架无关默认编辑器内置,三壳一致。
433
447
 
434
448
  ### 事件 = 前后完整快照
435
449
 
@@ -632,7 +646,7 @@ viewer.closeContextMenu()
632
646
  <ExcelViewer :toolbar="['find','filter','separator','zoom','export']" /> <!-- 控制项/顺序/分隔 -->
633
647
  <ExcelViewer :toolbar="false" /> <!-- 隐藏整条 -->
634
648
  ```
635
- - **内置 id**:`find`(查找)、`filter`(切换自动筛选 —— 文件没设也能点出下拉)、`sort`(按活动单元格所在列升序/降序;未开启自动筛选时会先按选区/已用区建立范围)、`clear-filter`(清除筛选,无筛选时禁用)、`copy`(复制选区)、`pivot-table`(透视表入口:选中带表头数据区后选择生成位置,可输出到现有工作表单元格或新建工作表;创建后打开 WPS 风格右侧字段面板,需 `pivotTable` + `editable`,功能未开启时不渲染)、`conditional-format`(条件格式管理入口:列出当前表规则可删/可编辑 + 新建全 6 类规则,需 `conditionalFormat` + `editable`,功能未开启时不渲染)、`number-format`(数字格式编辑入口:分类 + 预览 + 自定义格式代码,需 `editable`)、`wrap-text`(自动换行 toggle,WPS 风格,需 `editable`)、`image-tools`(图片工具 ▾:选区/整表/整列 浮动 ⇄ 嵌入互转,需 `editable`)、`template`(模板 ▾:仅 JSON / 模型数据源下生效;导入 .xlsx 当样式捐赠者;xlsx 数据源下禁用)、`freeze`(冻结/取消)、`zoom`(缩放下拉)、`export`(导出/打印下拉)、`'separator'`/`'|'`(分隔线)。
649
+ - **内置 id**:`find`(查找)、`filter`(切换自动筛选 —— 文件没设也能点出下拉)、`sort`(按活动单元格所在列升序/降序;未开启自动筛选时会先按选区/已用区建立范围)、`clear-filter`(清除筛选,无筛选时禁用)、`copy`(复制选区)、`pivot-table`(透视表入口:选中带表头数据区后选择生成位置,可输出到现有工作表单元格或新建工作表;创建后打开 WPS 风格右侧字段面板,需 `pivotTable` + `editable`,功能未开启时不渲染)、`conditional-format`(条件格式管理入口:列出当前表规则可删/可编辑 + 新建全 6 类规则,需 `conditionalFormat` + `editable`,功能未开启时不渲染)、`number-format`(数字格式编辑入口:分类 + 预览 + 自定义格式代码,需 `editable`)、`format-painter`(格式刷:采样源格样式刷到目标,需 `editable`)、`wrap-text`(自动换行 toggle,WPS 风格,需 `editable`)、`image-tools`(图片工具 ▾:选区/整表/整列 浮动 ⇄ 嵌入互转,需 `editable`)、`template`(模板 ▾:仅 JSON / 模型数据源下生效;导入 .xlsx 当样式捐赠者;xlsx 数据源下禁用)、`freeze`(冻结/取消)、`zoom`(缩放下拉)、`export`(导出/打印下拉)、`'separator'`/`'|'`(分隔线)。
636
650
  - **富项类型**(`ToolbarItem`):`type:'separator'` 分隔线;`items: ToolbarItem[]` 变下拉子菜单;`disabled?(viewer)` 禁用态;`iconSvg`(内联 SVG,优先于 `icon` emoji)/ `icon` / `label` / `title` / `onClick(viewer)` / `active?(viewer)`。
637
651
  - **响应式溢出**:宽度不足时,放不下的项自动折叠进「⋯ 更多」下拉。
638
652
  - **插件贡献**:`ExcelPlugin.toolbar: ToolbarItem[]`,插件加载即追加(opt-in)。