ooxml-excel-editor 1.1.0 → 1.2.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/README.md +148 -4
  3. package/dist/chunks/plugin-overlay-BBrNby8v.js +8965 -0
  4. package/dist/chunks/worker-client.stub-CJlmpAgJ.js +190 -0
  5. package/dist/components/ExcelViewer.vue.d.ts +170 -19
  6. package/dist/components/ExportProgressOverlay.vue.d.ts +11 -0
  7. package/dist/components/FilterPopup.vue.d.ts +4 -4
  8. package/dist/components/ViewerToolbar.vue.d.ts +2 -0
  9. package/dist/composables/useExcelDocument.d.ts +1 -0
  10. package/dist/core/edit/clipboard-html.d.ts +24 -0
  11. package/dist/core/edit/commands.d.ts +45 -1
  12. package/dist/core/edit/context-menu.d.ts +19 -0
  13. package/dist/core/edit/edit-controller.d.ts +70 -2
  14. package/dist/core/edit/permissions.d.ts +41 -2
  15. package/dist/core/edit/types.d.ts +62 -0
  16. package/dist/core/export/abort.d.ts +21 -0
  17. package/dist/core/export/exporter.d.ts +2 -1
  18. package/dist/core/export/types.d.ts +8 -0
  19. package/dist/core/export/wps-cellimages.d.ts +6 -0
  20. package/dist/core/export/xlsx-writer.d.ts +9 -0
  21. package/dist/core/format/color.d.ts +5 -0
  22. package/dist/core/format/number-format.d.ts +3 -0
  23. package/dist/core/layout/autofit.d.ts +3 -0
  24. package/dist/core/layout/grid-metrics.d.ts +14 -2
  25. package/dist/core/loader-json.d.ts +23 -0
  26. package/dist/core/model/clone.d.ts +3 -4
  27. package/dist/core/model/inspect.d.ts +43 -0
  28. package/dist/core/model/mutations.d.ts +16 -1
  29. package/dist/core/model/types.d.ts +44 -2
  30. package/dist/core/parser/cell-image-parser.d.ts +9 -0
  31. package/dist/core/parser/row-meta-parser.d.ts +3 -0
  32. package/dist/core/plugin.d.ts +144 -6
  33. package/dist/core/progress.d.ts +23 -0
  34. package/dist/core/render/canvas-renderer.d.ts +56 -2
  35. package/dist/core/render/conditional.d.ts +7 -0
  36. package/dist/core/template/style-overlay.d.ts +9 -0
  37. package/dist/core/viewer/controller.d.ts +209 -6
  38. package/dist/core/viewer/lightbox-host.d.ts +16 -0
  39. package/dist/core.js +1 -1
  40. package/dist/index.js +1169 -821
  41. package/dist/react/ExcelViewer.d.ts +134 -3
  42. package/dist/react/ExportProgressOverlay.d.ts +6 -0
  43. package/dist/react/use-excel-document.d.ts +2 -0
  44. package/dist/react.js +718 -281
  45. package/dist/style.css +1 -1
  46. package/package.json +1 -1
  47. package/dist/chunks/plugin-overlay-Cfnn9EOi.js +0 -7144
  48. package/dist/chunks/worker-client.stub-BQVZfaLd.js +0 -7
@@ -0,0 +1,190 @@
1
+ import { c as g, p as M } from "./plugin-overlay-BBrNby8v.js";
2
+ const b = Array(17).fill("#000000");
3
+ function x() {
4
+ return {
5
+ font: { name: "Calibri", size: 11, bold: !1, italic: !1, underline: !1, strike: !1, color: "#000000" },
6
+ fill: { type: "none" },
7
+ borders: {},
8
+ hAlign: "general",
9
+ vAlign: "bottom",
10
+ wrapText: !1,
11
+ shrinkToFit: !1,
12
+ textRotation: 0,
13
+ indent: 0,
14
+ numFmt: "General"
15
+ };
16
+ }
17
+ function k(e, o) {
18
+ return {
19
+ name: e,
20
+ index: o,
21
+ state: "visible",
22
+ dimension: { rows: 0, cols: 0 },
23
+ cells: /* @__PURE__ */ new Map(),
24
+ styles: [x()],
25
+ merges: [],
26
+ columns: /* @__PURE__ */ new Map(),
27
+ rows: /* @__PURE__ */ new Map(),
28
+ defaultColWidth: 64,
29
+ defaultRowHeight: 20,
30
+ freeze: { frozenRows: 0, frozenCols: 0 },
31
+ conditional: [],
32
+ dataValidations: [],
33
+ images: [],
34
+ charts: [],
35
+ shapes: [],
36
+ sparklines: [],
37
+ showGridLines: !0
38
+ };
39
+ }
40
+ function I(e, o) {
41
+ if (e == null || e === "") return { raw: null, type: "empty" };
42
+ if (typeof e == "number") return { raw: e, type: "number" };
43
+ if (typeof e == "boolean") return { raw: e, type: "boolean" };
44
+ if (e instanceof Date) return { raw: e, type: "date" };
45
+ if (typeof e != "string") return { raw: String(e), type: "string" };
46
+ if (!o) return { raw: e, type: "string" };
47
+ const t = e.trim();
48
+ if (/^[+-]?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(t)) {
49
+ const r = Number(t);
50
+ if (Number.isFinite(r)) return { raw: r, type: "number" };
51
+ }
52
+ if (/^(TRUE|FALSE)$/i.test(t)) return { raw: /^TRUE$/i.test(t), type: "boolean" };
53
+ if (/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:?\d{2})?)?$/.test(t)) {
54
+ const r = new Date(t);
55
+ if (!isNaN(r.getTime())) return { raw: r, type: "date" };
56
+ }
57
+ return { raw: e, type: "string" };
58
+ }
59
+ function T(e, o) {
60
+ return o.map((t) => e[t]);
61
+ }
62
+ function A(e, o, t = {}) {
63
+ const r = t.startRow ?? 0, i = t.startCol ?? 0, c = t.autoInfer ?? !0;
64
+ let a = 0, m = 0, u = !1;
65
+ if (!o.length) return { lastRow: 0, lastCol: 0, wrote: !1 };
66
+ const s = o[0], w = s !== null && typeof s == "object" && !Array.isArray(s), p = w ? t.columns ?? Object.keys(s) : [];
67
+ let d = r;
68
+ if (w && (t.headerRow ?? !0)) {
69
+ for (let n = 0; n < p.length; n++) {
70
+ const l = d, f = i + n;
71
+ e.cells.set(g(l, f), { row: l, col: f, type: "string", raw: p[n], styleId: 0 }), a = Math.max(a, l), m = Math.max(m, f), u = !0;
72
+ }
73
+ d++;
74
+ }
75
+ for (let n = 0; n < o.length; n++) {
76
+ const l = o[n], f = Array.isArray(l) ? l : T(l, p);
77
+ for (let h = 0; h < f.length; h++) {
78
+ const y = d + n - (w && (t.headerRow ?? !0), 0), C = i + h, R = I(f[h], c);
79
+ R.type !== "empty" && (e.cells.set(g(y, C), { row: y, col: C, type: R.type, raw: R.raw, styleId: 0 }), a = Math.max(a, y), m = Math.max(m, C), u = !0);
80
+ }
81
+ }
82
+ return { lastRow: a, lastCol: m, wrote: u };
83
+ }
84
+ function E(e, o = {}) {
85
+ const t = o.themeColors && o.themeColors.length === 17 ? o.themeColors : b, r = o.autoInfer ?? !0, i = o.headerRow ?? !0;
86
+ if (e && typeof e == "object" && !Array.isArray(e) && Array.isArray(e.sheets))
87
+ return { sheets: e.sheets.map((d, n) => {
88
+ const l = k(d.name || `Sheet${n + 1}`, n), { lastRow: f, lastCol: h, wrote: y } = A(l, d.rows ?? [], { headerRow: i, autoInfer: r });
89
+ return l.dimension = y ? { rows: f + 1, cols: h + 1 } : { rows: 0, cols: 0 }, l;
90
+ }), activeSheet: 0, themeColors: t, date1904: !1 };
91
+ const c = k(o.sheetName || "Sheet1", 0), a = e ?? [], { lastRow: m, lastCol: u, wrote: s } = A(c, a, { headerRow: i, autoInfer: r });
92
+ return c.dimension = s ? { rows: m + 1, cols: u + 1 } : { rows: 0, cols: 0 }, { sheets: [c], activeSheet: 0, themeColors: t, date1904: !1 };
93
+ }
94
+ function L(e) {
95
+ return !!e && typeof e == "object" && Array.isArray(e.sheets) && typeof e.activeSheet == "number" && Array.isArray(e.themeColors);
96
+ }
97
+ function S(e, o) {
98
+ const t = o.sheets[0], r = e.sheets[0];
99
+ if (!t) return e;
100
+ if (!r)
101
+ return {
102
+ sheets: [z(t, t.name)],
103
+ activeSheet: 0,
104
+ themeColors: o.themeColors,
105
+ date1904: e.date1904,
106
+ cellImages: e.cellImages
107
+ };
108
+ const i = {
109
+ name: r.name || t.name,
110
+ index: 0,
111
+ state: "visible",
112
+ dimension: { rows: 0, cols: 0 },
113
+ cells: /* @__PURE__ */ new Map(),
114
+ styles: t.styles.map((s) => ({ ...s })),
115
+ merges: t.merges.map((s) => ({ ...s })),
116
+ columns: new Map(t.columns),
117
+ rows: new Map(t.rows),
118
+ defaultColWidth: t.defaultColWidth,
119
+ defaultRowHeight: t.defaultRowHeight,
120
+ freeze: { ...t.freeze },
121
+ // 条件格式 / 数据验证 不带过来 —— 数据可能不在模板的目标列上, 套规则会误命中
122
+ conditional: [],
123
+ dataValidations: [],
124
+ // 模板的图 / 图表 / 形状 全部不带 —— 模板是"样式骨架", 不是内容
125
+ images: [],
126
+ charts: [],
127
+ shapes: [],
128
+ sparklines: [],
129
+ showGridLines: t.showGridLines
130
+ };
131
+ let c = 0, a = 0;
132
+ for (const s of r.cells.values()) {
133
+ const w = t.cells.get(g(s.row, s.col));
134
+ i.cells.set(g(s.row, s.col), {
135
+ row: s.row,
136
+ col: s.col,
137
+ type: s.type,
138
+ raw: s.raw,
139
+ rich: s.rich,
140
+ formula: s.formula,
141
+ hyperlink: s.hyperlink,
142
+ comment: s.comment,
143
+ styleId: (w == null ? void 0 : w.styleId) ?? 0,
144
+ dispImgId: s.dispImgId
145
+ }), s.row > c && (c = s.row), s.col > a && (a = s.col);
146
+ }
147
+ const m = t.columns.size ? Math.max(...t.columns.keys()) + 1 : 0, u = t.rows.size ? Math.max(...t.rows.keys()) + 1 : 0;
148
+ return i.dimension = {
149
+ rows: Math.max(r.dimension.rows, c + 1, u),
150
+ cols: Math.max(r.dimension.cols, a + 1, m)
151
+ }, {
152
+ sheets: [i],
153
+ activeSheet: 0,
154
+ themeColors: o.themeColors,
155
+ date1904: e.date1904,
156
+ cellImages: e.cellImages
157
+ };
158
+ }
159
+ function z(e, o) {
160
+ return {
161
+ name: o,
162
+ index: 0,
163
+ state: "visible",
164
+ dimension: { rows: 0, cols: 0 },
165
+ cells: /* @__PURE__ */ new Map(),
166
+ styles: e.styles.map((t) => ({ ...t })),
167
+ merges: e.merges.map((t) => ({ ...t })),
168
+ columns: new Map(e.columns),
169
+ rows: new Map(e.rows),
170
+ defaultColWidth: e.defaultColWidth,
171
+ defaultRowHeight: e.defaultRowHeight,
172
+ freeze: { ...e.freeze },
173
+ conditional: [],
174
+ dataValidations: [],
175
+ images: [],
176
+ charts: [],
177
+ shapes: [],
178
+ sparklines: [],
179
+ showGridLines: e.showGridLines
180
+ };
181
+ }
182
+ function G(e, o) {
183
+ return M(e, o);
184
+ }
185
+ export {
186
+ S as a,
187
+ L as i,
188
+ E as j,
189
+ G as p
190
+ };
@@ -1,9 +1,12 @@
1
- import { ExcelPlugin, ToolbarItem } from '../core/plugin';
1
+ import { ExcelPlugin, PermissionDeniedPayload, ToolbarItem } from '../core/plugin';
2
2
  import { ExcelSource } from '../core/loader';
3
- import { CellModel, CellStyleFn, MergeRange, TransformModelFn, WorkbookModel } from '../core/model/types';
3
+ import { JsonInput, JsonLoadOptions } from '../core/loader-json';
4
+ import { CellModel, CellStyleFn, CellStyleOverride, MergeRange, TransformModelFn, WorkbookModel } from '../core/model/types';
4
5
  import { ParseProgress } from '../core/progress';
5
6
  import { ReadOptions } from '../core/model/data-access';
6
7
  import { ViewerTheme } from '../core/render/theme';
8
+ import { ContextMenuBeforePayload, ContextMenuShowPayload, ContextMenuTransform } from '../core/viewer/controller';
9
+ import { EditableTarget } from '../core/edit/types';
7
10
  import { FormulaEngineFactory } from '../core/formula/engine';
8
11
  import { CellChangePayload, DimChangePayload, DirtyChangePayload, ImageChangePayload, StructChangePayload } from '../core/edit/edit-controller';
9
12
  import { EditorResolver } from '../core/edit/editor-context';
@@ -11,6 +14,27 @@ import { ImageExportOptions, PdfExportOptions, PrintOptions } from '../core/expo
11
14
  import { ResolvedToolbarItem } from './toolbar-types';
12
15
  type __VLS_Props = {
13
16
  src?: ExcelSource;
17
+ /**
18
+ * 直接喂 WorkbookModel 或 JsonInput(P3):绕过 parser,常用于"从后端拿 JSON 直接渲染"或
19
+ * "前端构造好模型再渲染"。WorkbookModel-shape 直用,JsonInput(二维数组 / 对象数组 / `{sheets:[...]}`)
20
+ * 走 `jsonToWorkbook` 自动构造。优先级:`workbook` > `src`(两者都给时取 `workbook`)。
21
+ */
22
+ workbook?: WorkbookModel | JsonInput;
23
+ /** JSON 直渲选项(`workbook` = JsonInput 时生效) */
24
+ jsonOptions?: JsonLoadOptions;
25
+ /**
26
+ * 渲染模板(P3 重设计 2026-06-08):一份 .xlsx 当**样式捐赠者** —— 模板的 styling
27
+ * (styles / merges / 列宽 / 行高 / freeze / theme)套到无格式数据源上,模板的 raw 文字 / 占位符
28
+ * / 图 / 图表 / 条件格式 全部丢弃。
29
+ *
30
+ * ⚠️ **只在数据源是 :workbook(JSON / 模型)时生效**;`:src`(.xlsx)数据源自带格式,
31
+ * 给 `:templateFile` 会被忽略并 console.warn。
32
+ *
33
+ * 工具栏内置 `template` 项可在运行时切换/导入/清除,无需重新挂载。
34
+ */
35
+ templateFile?: ExcelSource;
36
+ /** 模板显示名(标题栏 `· 模板: xxx` 后缀);不给则取运行时 File.name */
37
+ templateName?: string;
14
38
  fileName?: string;
15
39
  /** 外观主题(覆盖默认配色) */
16
40
  theme?: Partial<ViewerTheme>;
@@ -18,6 +42,10 @@ type __VLS_Props = {
18
42
  transformModel?: TransformModelFn;
19
43
  /** 渲染钩子: 按单元格覆盖样式 */
20
44
  cellStyle?: CellStyleFn;
45
+ /** WPS 单元格内嵌图(DISPIMG)贴合方式:contain 等比(默认,与 WPS 渲染一致)/ fill 拉伸铺满 / cover 等比裁剪 */
46
+ cellImageFit?: 'fill' | 'contain' | 'cover';
47
+ /** 图片点击放大灯箱(默认 true):只读模式单击图放大、编辑模式右键「查看大图」;false 关闭 */
48
+ imageLightbox?: boolean;
21
49
  /** 单击超链接是否默认在新标签打开(false 时只派发 hyperlink-click 事件) */
22
50
  openLinks?: boolean;
23
51
  /** 插件列表(打包主题/钩子/事件/overlay) */
@@ -37,12 +65,52 @@ type __VLS_Props = {
37
65
  }) => boolean | void;
38
66
  /** 只读区域(0-based 闭区间);命中即只读 */
39
67
  readOnlyRanges?: MergeRange[];
68
+ /**
69
+ * **可编辑白名单**(2026-06-08 新增) —— 设了就是白名单语义:默认只读,只有命中**任一**
70
+ * target 的格才可编辑。4 种 target 形状:`{row,col}` 单格 / `{row}` 整行 / `{col}` 整列 /
71
+ * `MergeRange` 矩形。可单值可数组,允许**不相邻**多个 target.
72
+ *
73
+ * `undefined`(不传)= 不启用白名单(老行为:默认全可编辑);`[]`(显式空数组)= 全只读.
74
+ * 与 `readOnlyRanges` / `cellReadOnly` 叠加 — 白名单命中后仍可被它们二次"黑"掉.
75
+ */
76
+ editableTargets?: EditableTarget | EditableTarget[];
77
+ /**
78
+ * **严格尺寸闸门**(Phase B, 2026-06-08) —— 默认 `false`: setColumnWidth/setRowHeight/autoFit 仅受全局
79
+ * `editable` 控制(老行为). 设 `true` + `editableTargets` 启用了 → 该列/行至少有 1 格在白名单内才能改尺寸.
80
+ */
81
+ strictDimensions?: boolean;
82
+ /**
83
+ * **只读单元格视觉钩子** (Phase C, 2026-06-08):
84
+ * - `false` (默认) = 无视觉差异 (老行为不变)
85
+ * - `true` = 套内置默认 (浅灰底 `#f5f7fa`,跟工具栏一致)
86
+ * - `CellStyleOverride` 对象 = 固定样式给所有只读格 (如黄底高亮)
87
+ * - `CellStyleFn` 函数 = 按格自定义
88
+ *
89
+ * 跟 `editableTargets` 配合: 白名单未覆盖的格自动套此视觉, 用户一眼看出哪些可编辑.
90
+ */
91
+ readOnlyCellStyle?: boolean | CellStyleOverride | CellStyleFn;
40
92
  /** 自定义单元格编辑器(按格返回工厂;覆盖插件 editor)。需 editable 开启 */
41
93
  editor?: EditorResolver;
42
94
  /** 公式重算(E4):默认 false 沿用缓存值。开启后编辑公式/被引用格 → 依赖格自动重算。需 editable */
43
95
  recalc?: boolean;
44
96
  /** 自定义/自研公式引擎工厂(可换引擎);不给则用默认 HyperFormula(需 npm i hyperformula) */
45
97
  formulaEngine?: FormulaEngineFactory;
98
+ /**
99
+ * 内置导出进度遮罩(P1.5):默认 `true` —— 调 `viewer.downloadPdf` / `downloadImage` / `downloadXlsx` /
100
+ * `print` / 选区图片批量转换 时,壳自动建 `AbortController` + 接 `onProgress` →
101
+ * 显示居中模态(stage 标签 + 进度条 + 取消按钮)。**关闭** `:export-progress="false"` 走纯回调
102
+ * 路径(用户自己接 `opts.onProgress`/`opts.signal`)。**完全自渲染**用 `#export-progress` 插槽
103
+ * (拿到 `{ state, busy, cancel }`)。
104
+ */
105
+ exportProgress?: boolean;
106
+ /**
107
+ * 右键菜单(Plan C):
108
+ * - `false` → 不弹内置菜单(`before-context-menu` / `context-menu` 事件仍触发,用户自渲染)
109
+ * - 函数 `(ctx, items) => MenuItem[] | undefined` → 在内置 items 上加 / 减 / 重排;返 `undefined` 用原样
110
+ * - 不传(默认)→ editable 时显示内置菜单,非 editable 走浏览器默认菜单
111
+ * 与 `@before-context-menu` / `@context-menu` 事件叠加使用。
112
+ */
113
+ contextMenu?: boolean | ContextMenuTransform;
46
114
  };
47
115
  /** 单元格当前屏幕矩形(render-area 相对坐标);供 overlay slot / 命令式定位 */
48
116
  declare function rectOf(row: number, col: number): {
@@ -58,6 +126,7 @@ declare function rectOfRange(range: MergeRange): {
58
126
  w: number;
59
127
  h: number;
60
128
  } | null;
129
+ declare function cancelExport(): void;
61
130
  declare function __VLS_template(): {
62
131
  attrs: Partial<{}>;
63
132
  slots: {
@@ -100,6 +169,17 @@ declare function __VLS_template(): {
100
169
  } | null;
101
170
  range: string;
102
171
  }): any;
172
+ 'export-progress'?(_: {
173
+ state: {
174
+ stage: import('../core/progress').ExportStage;
175
+ sheetIndex?: number | undefined;
176
+ pageIndex?: number | undefined;
177
+ ratio?: number | undefined;
178
+ label?: string | undefined;
179
+ } | null;
180
+ busy: boolean;
181
+ cancel: typeof cancelExport;
182
+ }): any;
103
183
  };
104
184
  refs: {
105
185
  rootEl: HTMLDivElement;
@@ -113,6 +193,7 @@ declare function __VLS_template(): {
113
193
  spacerEl: HTMLDivElement;
114
194
  pluginOvEl: HTMLDivElement;
115
195
  editorSlotEl: HTMLDivElement;
196
+ templateInputEl: HTMLInputElement;
116
197
  };
117
198
  rootEl: HTMLDivElement;
118
199
  };
@@ -128,6 +209,8 @@ declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {
128
209
  rectOfRange(range: MergeRange): import('../core/plugin').Rect | null;
129
210
  redraw(): void;
130
211
  isCellEditable(row: number, col: number): boolean;
212
+ setEditableTargets(targets: EditableTarget | EditableTarget[] | undefined): void;
213
+ getEditableTargets(): EditableTarget | EditableTarget[] | undefined;
131
214
  exportImage(opts?: ImageExportOptions): Promise<Blob>;
132
215
  downloadImage(opts?: ImageExportOptions): Promise<void>;
133
216
  exportPdf(opts?: PdfExportOptions): Promise<Blob>;
@@ -162,34 +245,85 @@ declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {
162
245
  col: number;
163
246
  } | null;
164
247
  getCellSnapshot(row: number, col: number): import('../core').CellSnapshot | null;
248
+ inspectCell(row: number, col: number): import('../core/plugin').CellInspection | null;
165
249
  beginEdit(row: number, col: number): boolean;
166
250
  cancelEdit(): void;
167
251
  isEditing(): boolean;
168
- setStyle(range: MergeRange, patch: import('../core/model/types').CellStyleOverride): boolean;
252
+ setStyle(range: MergeRange, patch: CellStyleOverride): boolean;
253
+ getActiveFillColor(): string;
254
+ getActiveFontColor(): string;
255
+ setSelectionFill(color: string | null): boolean;
256
+ setSelectionFontColor(color: string): boolean;
257
+ getSelectionWrapState(): "all" | "none" | "mixed";
258
+ toggleWrapTextOnSelection(): boolean;
259
+ mergeCells(range: MergeRange): boolean;
260
+ unmergeCells(range: MergeRange): boolean;
261
+ pasteText(text: string, at?: {
262
+ row: number;
263
+ col: number;
264
+ }): boolean;
265
+ pasteRichHtml(html: string, at?: {
266
+ row: number;
267
+ col: number;
268
+ }): boolean;
269
+ pasteImageBlob(blob: Blob, at?: {
270
+ row: number;
271
+ col: number;
272
+ }): Promise<boolean>;
169
273
  getImages(): import('../core/model/types').ImageAnchor[];
170
274
  addImage(anchor: import('../core/model/types').ImageAnchor): number;
171
275
  removeImage(index: number): boolean;
172
276
  moveImage(index: number, dxPx: number, dyPx: number): boolean;
173
277
  resizeImage(index: number, widthPx: number, heightPx: number): boolean;
278
+ getCellEditString(): string;
279
+ canEditActiveCell(): boolean;
280
+ commitActiveCellValue(value: string, move?: "down"): boolean;
281
+ getCellImages(): {
282
+ id: string;
283
+ src: string;
284
+ mime?: string;
285
+ }[];
286
+ getCellImageAt(row: number, col: number): {
287
+ id: string;
288
+ src: string;
289
+ mime?: string;
290
+ } | null;
291
+ openImageLightbox(src: string, fileName?: string, mime?: string): void;
292
+ setCellImageFit(fit: "fill" | "contain" | "cover"): void;
293
+ convertImageToCell(imageIndex: number, row: number, col: number): boolean;
294
+ convertImageToCellAuto(imageIndex: number): boolean;
295
+ convertAllImagesToCells(col?: number): number;
296
+ convertImagesInRangeToCell(range: MergeRange): Promise<number>;
297
+ convertCellImagesInRangeToFloat(range: MergeRange, size?: {
298
+ width: number;
299
+ height: number;
300
+ }): Promise<number>;
301
+ openContextMenu(x: number, y: number, items?: import('../core/plugin').MenuItem[]): void;
302
+ closeContextMenu(): void;
303
+ convertCellImageToFloat(row: number, col: number, size?: {
304
+ width: number;
305
+ height: number;
306
+ }): boolean;
174
307
  insertRows(at: number, count?: number): boolean;
175
308
  deleteRows(at: number, count?: number): boolean;
176
309
  insertCols(at: number, count?: number): boolean;
177
310
  deleteCols(at: number, count?: number): boolean;
178
- setColumnWidth(col: number, width: number): boolean;
179
- setRowHeight(row: number, height: number): boolean;
311
+ setColumnWidth(target: import('../core/edit/types').DimTarget, width: number): number;
312
+ setRowHeight(target: import('../core/edit/types').DimTarget, height: number): number;
313
+ autoFitColumns(target?: import('../core/edit/types').DimTarget): number;
314
+ autoFitRows(target?: import('../core/edit/types').DimTarget): number;
315
+ resetColumnWidth(target: import('../core/edit/types').DimTarget): number;
316
+ resetRowHeight(target: import('../core/edit/types').DimTarget): number;
180
317
  isRecalcReady(): boolean;
318
+ getVirtualExtent(): {
319
+ rows: number;
320
+ cols: number;
321
+ };
181
322
  isDirty(): boolean;
182
323
  resetToOriginal(): boolean;
183
324
  }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
184
325
  error: (message: string) => any;
185
326
  progress: (progress: ParseProgress) => any;
186
- "cell-change": (payload: CellChangePayload) => any;
187
- "edit-start": (payload: unknown) => any;
188
- "edit-commit": (payload: unknown) => any;
189
- "dim-change": (payload: DimChangePayload) => any;
190
- "dirty-change": (payload: DirtyChangePayload) => any;
191
- "image-change": (payload: ImageChangePayload) => any;
192
- "struct-change": (payload: StructChangePayload) => any;
193
327
  "cell-click": (payload: {
194
328
  row: number;
195
329
  col: number;
@@ -218,17 +352,20 @@ declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {
218
352
  col: number;
219
353
  };
220
354
  }) => any;
355
+ "cell-change": (payload: CellChangePayload) => any;
356
+ "edit-start": (payload: unknown) => any;
357
+ "edit-commit": (payload: unknown) => any;
358
+ "dim-change": (payload: DimChangePayload) => any;
359
+ "dirty-change": (payload: DirtyChangePayload) => any;
360
+ "image-change": (payload: ImageChangePayload) => any;
361
+ "struct-change": (payload: StructChangePayload) => any;
362
+ "permission-denied": (payload: PermissionDeniedPayload) => any;
221
363
  rendered: (workbook: WorkbookModel) => any;
364
+ "before-context-menu": (payload: ContextMenuBeforePayload) => any;
365
+ "context-menu": (payload: ContextMenuShowPayload) => any;
222
366
  }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
223
367
  onError?: ((message: string) => any) | undefined;
224
368
  onProgress?: ((progress: ParseProgress) => any) | undefined;
225
- "onCell-change"?: ((payload: CellChangePayload) => any) | undefined;
226
- "onEdit-start"?: ((payload: unknown) => any) | undefined;
227
- "onEdit-commit"?: ((payload: unknown) => any) | undefined;
228
- "onDim-change"?: ((payload: DimChangePayload) => any) | undefined;
229
- "onDirty-change"?: ((payload: DirtyChangePayload) => any) | undefined;
230
- "onImage-change"?: ((payload: ImageChangePayload) => any) | undefined;
231
- "onStruct-change"?: ((payload: StructChangePayload) => any) | undefined;
232
369
  "onCell-click"?: ((payload: {
233
370
  row: number;
234
371
  col: number;
@@ -257,10 +394,23 @@ declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {
257
394
  col: number;
258
395
  };
259
396
  }) => any) | undefined;
397
+ "onCell-change"?: ((payload: CellChangePayload) => any) | undefined;
398
+ "onEdit-start"?: ((payload: unknown) => any) | undefined;
399
+ "onEdit-commit"?: ((payload: unknown) => any) | undefined;
400
+ "onDim-change"?: ((payload: DimChangePayload) => any) | undefined;
401
+ "onDirty-change"?: ((payload: DirtyChangePayload) => any) | undefined;
402
+ "onImage-change"?: ((payload: ImageChangePayload) => any) | undefined;
403
+ "onStruct-change"?: ((payload: StructChangePayload) => any) | undefined;
404
+ "onPermission-denied"?: ((payload: PermissionDeniedPayload) => any) | undefined;
260
405
  onRendered?: ((workbook: WorkbookModel) => any) | undefined;
406
+ "onBefore-context-menu"?: ((payload: ContextMenuBeforePayload) => any) | undefined;
407
+ "onContext-menu"?: ((payload: ContextMenuShowPayload) => any) | undefined;
261
408
  }>, {
262
409
  toolbar: boolean | Array<string | ToolbarItem>;
410
+ imageLightbox: boolean;
263
411
  openLinks: boolean;
412
+ exportProgress: boolean;
413
+ contextMenu: boolean | ContextMenuTransform;
264
414
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
265
415
  rootEl: HTMLDivElement;
266
416
  renderAreaEl: HTMLDivElement;
@@ -273,6 +423,7 @@ declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {
273
423
  spacerEl: HTMLDivElement;
274
424
  pluginOvEl: HTMLDivElement;
275
425
  editorSlotEl: HTMLDivElement;
426
+ templateInputEl: HTMLInputElement;
276
427
  }, HTMLDivElement>;
277
428
  declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
278
429
  export default _default;
@@ -0,0 +1,11 @@
1
+ import { ExportProgress } from '../core/progress';
2
+ type __VLS_Props = {
3
+ state: ExportProgress | null;
4
+ busy: boolean;
5
+ };
6
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
7
+ cancel: () => any;
8
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
9
+ onCancel?: (() => any) | undefined;
10
+ }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
11
+ export default _default;
@@ -6,14 +6,14 @@ type __VLS_Props = {
6
6
  sortDir?: 'asc' | 'desc' | null;
7
7
  };
8
8
  declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
9
- sort: (dir: "asc" | "desc") => any;
10
- close: () => any;
9
+ sort: (dir: "desc" | "asc") => any;
11
10
  apply: (checked: string[]) => any;
11
+ close: () => any;
12
12
  clear: () => any;
13
13
  }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
14
- onSort?: ((dir: "asc" | "desc") => any) | undefined;
15
- onClose?: (() => any) | undefined;
14
+ onSort?: ((dir: "desc" | "asc") => any) | undefined;
16
15
  onApply?: ((checked: string[]) => any) | undefined;
16
+ onClose?: (() => any) | undefined;
17
17
  onClear?: (() => any) | undefined;
18
18
  }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
19
19
  rootEl: HTMLDivElement;
@@ -1,5 +1,7 @@
1
1
  type __VLS_Props = {
2
2
  fileName?: string;
3
+ /** 模板名(运行时或 prop 给出);非空时拼接到标题尾部 ` · 模板: <name>` */
4
+ templateName?: string;
3
5
  sheetCount: number;
4
6
  zoom: number;
5
7
  };
@@ -6,6 +6,7 @@ export declare function useExcelDocument(): {
6
6
  error: import('vue').Ref<string | null, string | null>;
7
7
  workbook: import('vue').ShallowRef<WorkbookModel | null, WorkbookModel | null>;
8
8
  load: (src: ExcelSource, transform?: TransformModelFn) => Promise<void>;
9
+ loadModel: (model: WorkbookModel, transform?: TransformModelFn) => void;
9
10
  progress: import('vue').Ref<{
10
11
  stage: "read" | "parse" | "build";
11
12
  ratio?: number | undefined;
@@ -0,0 +1,24 @@
1
+ import { CellStyleOverride, MergeRange } from '../model/types';
2
+ import { CellValue } from '../model/data-access';
3
+ export interface ParsedClipboard {
4
+ /** 二维值(原始串/数字/公式,交 setCellValue 推断);稠密对齐 */
5
+ values: CellValue[][];
6
+ /** 逐格样式覆盖(只含解析出的字段) */
7
+ styles: {
8
+ row: number;
9
+ col: number;
10
+ patch: CellStyleOverride;
11
+ }[];
12
+ /** 合并区(rowspan/colspan>1) */
13
+ merges: MergeRange[];
14
+ /** data-uri 图片(row,col,dataUrl) */
15
+ images: {
16
+ row: number;
17
+ col: number;
18
+ dataUrl: string;
19
+ }[];
20
+ }
21
+ /**
22
+ * 解析剪贴板 HTML → {values, styles, merges, images}。非浏览器环境 / 无 <table> 返 null(调用方回退 TSV)。
23
+ */
24
+ export declare function parseClipboardHtml(html: string): ParsedClipboard | null;
@@ -1,4 +1,4 @@
1
- import { CellModel, CellStyleOverride, ColumnInfo, ImageAnchor, RowInfo, SheetModel, WorkbookModel } from '../model/types';
1
+ import { CellModel, CellStyleOverride, ColumnInfo, ImageAnchor, MergeRange, RowInfo, SheetModel, WorkbookModel } from '../model/types';
2
2
  import { CellValue } from '../model/data-access';
3
3
  import { StructOp } from '../model/structure';
4
4
  export type CellPos = {
@@ -58,6 +58,50 @@ export type EditCommand = {
58
58
  } | {
59
59
  kind: 'restore-wb';
60
60
  snapshot: WorkbookModel;
61
+ } | {
62
+ kind: 'merge-cells';
63
+ range: MergeRange;
64
+ } | {
65
+ kind: 'unmerge-cells';
66
+ range: MergeRange;
67
+ } | {
68
+ kind: 'restore-merges';
69
+ merges: MergeRange[];
70
+ cells: {
71
+ row: number;
72
+ col: number;
73
+ cell: CellModel | null;
74
+ }[];
75
+ } | {
76
+ kind: 'convert-to-cell';
77
+ imageIndex: number;
78
+ row: number;
79
+ col: number;
80
+ } | {
81
+ kind: 'convert-to-cells';
82
+ targets: {
83
+ imageIndex: number;
84
+ row: number;
85
+ col: number;
86
+ }[];
87
+ } | {
88
+ kind: 'convert-to-float';
89
+ row: number;
90
+ col: number;
91
+ size?: {
92
+ width: number;
93
+ height: number;
94
+ };
95
+ } | {
96
+ kind: 'convert-to-floats';
97
+ cells: {
98
+ row: number;
99
+ col: number;
100
+ size?: {
101
+ width: number;
102
+ height: number;
103
+ };
104
+ }[];
61
105
  };
62
106
  /** dim 命令(列宽/行高)— 仅维度族,无格位置 */
63
107
  export type DimCommand = Extract<EditCommand, {
@@ -0,0 +1,19 @@
1
+ /**
2
+ * 右键上下文菜单宿主(框架无关 DOM)—— 挂到 document.body 的 fixed 菜单,点项执行 action + 关闭,
3
+ * 点外部 / Esc 关闭,贴边自动翻转。Vue / React 壳只把 contextmenu 事件转给 controller,菜单逻辑全在这。
4
+ */
5
+ export interface MenuItem {
6
+ label?: string;
7
+ action?: () => void;
8
+ disabled?: boolean;
9
+ /** true = 分隔线 */
10
+ separator?: boolean;
11
+ }
12
+ export declare class ContextMenuHost {
13
+ private el;
14
+ private cleanup;
15
+ isOpen(): boolean;
16
+ show(x: number, y: number, items: MenuItem[]): void;
17
+ close(): void;
18
+ dispose(): void;
19
+ }