ooxml-excel-editor 1.3.3 → 1.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/CHANGELOG.md +218 -0
- package/README.md +27 -8
- package/dist/chunks/index-BNQIWClg.js +12532 -0
- package/dist/chunks/{index.es-D9BGYyEt.js → index.es-BVXJfTmn.js} +1 -1
- package/dist/chunks/{index.es-n6H_ncuE.js → index.es-gb2_kTSZ.js} +1 -1
- package/dist/chunks/{jspdf.es.min-Dbn0akWf.js → jspdf.es.min-C7JL2eZm.js} +2 -2
- package/dist/chunks/{jspdf.es.min-B6-ocR7J.js → jspdf.es.min-CBWDsR7H.js} +2 -2
- package/dist/chunks/plugin-overlay-C_qauTcv.js +11057 -0
- package/dist/chunks/{toolbar-icons-fOm95ASq.js → toolbar-icons-CD7G5Aof.js} +62 -71
- package/dist/components/ExcelViewer.vue.d.ts +29 -1
- package/dist/core/edit/clipboard-html.d.ts +12 -0
- package/dist/core/edit/clipboard-snapshot.d.ts +76 -0
- package/dist/core/edit/context-menu.d.ts +14 -1
- package/dist/core/edit/edit-controller.d.ts +22 -1
- package/dist/core/edit/paste-behavior.d.ts +33 -0
- package/dist/core/edit/types.d.ts +20 -0
- package/dist/core/export/exporter.d.ts +2 -0
- package/dist/core/export/pivot-tables.d.ts +17 -0
- package/dist/core/export/xlsx-writer.d.ts +6 -0
- package/dist/core/index.d.ts +4 -2
- package/dist/core/model/mutations.d.ts +2 -0
- package/dist/core/model/types.d.ts +61 -0
- package/dist/core/parser/pivot-parser.d.ts +3 -0
- package/dist/core/plugin.d.ts +47 -5
- package/dist/core/render/canvas-renderer.d.ts +12 -0
- package/dist/core/render/pivot-toggle.d.ts +13 -0
- package/dist/core/viewer/controller.d.ts +82 -6
- package/dist/core/viewer/overlay-manager.d.ts +1 -0
- package/dist/core/viewer/paste-config-host.d.ts +12 -0
- package/dist/core/viewer/pivot-dialog-host.d.ts +48 -0
- package/dist/core/viewer/readonly-prompt-host.d.ts +23 -0
- package/dist/core.js +67 -64
- package/dist/index.d.ts +2 -2
- package/dist/index.js +948 -873
- package/dist/react/ExcelViewer.d.ts +25 -4
- package/dist/react.js +621 -535
- package/dist/style.css +1 -1
- package/dist/vue2.css +1 -1
- package/dist/vue2.js +1 -1
- package/package.json +1 -1
- package/dist/chunks/index-6q8kSGQg.js +0 -10575
- package/dist/chunks/plugin-overlay-BUrPrpT2.js +0 -9146
package/dist/core/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export type { ParseProgress } from './progress';
|
|
|
10
10
|
export { cellDisplayText, getCell, getCellValue, getCellStyle, getCellText, getSheetData, getRangeData, sheetToJSON, getWorkbookJSON, } from './model/data-access';
|
|
11
11
|
export type { CellValue, ReadOptions, SheetToJSONOptions } from './model/data-access';
|
|
12
12
|
export { cellKey } from './model/types';
|
|
13
|
-
export type { WorkbookModel, SheetModel, CellModel, CellStyle, MergeRange, ConditionalRule, ChartSpec, ImageAnchor, ShapeSpec, Sparkline, CssColor, TransformModelFn, CellStyleFn, CellStyleOverride, } from './model/types';
|
|
13
|
+
export type { WorkbookModel, SheetModel, CellModel, CellStyle, MergeRange, ConditionalRule, ChartSpec, ImageAnchor, ShapeSpec, Sparkline, PivotTableModel, PivotButton, PivotTableLayout, PivotFilterRule, PivotValueRule, PivotSummary, PivotFilterMode, CssColor, TransformModelFn, CellStyleFn, CellStyleOverride, } from './model/types';
|
|
14
14
|
export { CanvasRenderer } from './render/canvas-renderer';
|
|
15
15
|
export type { ViewState, RendererOptions } from './render/canvas-renderer';
|
|
16
16
|
export { ViewerController } from './viewer/controller';
|
|
@@ -20,6 +20,8 @@ export type { OverlayQuads } from './viewer/overlay-manager';
|
|
|
20
20
|
export { PluginOverlayHost } from './viewer/plugin-overlay';
|
|
21
21
|
export { resolveEditable } from './edit/permissions';
|
|
22
22
|
export type { EditConfig, EditPermission } from './edit/types';
|
|
23
|
+
export type { PasteBehavior } from './edit/paste-behavior';
|
|
24
|
+
export { DEFAULT_PASTE_BEHAVIOR, PASTE_PRESET_VALUES_ONLY, resolvePasteBehavior } from './edit/paste-behavior';
|
|
23
25
|
export { EditController } from './edit/edit-controller';
|
|
24
26
|
export type { EditControllerHost, EditEventName, EditSource, CellChangePayload, DimChangePayload, DirtyChangePayload, ImageChangePayload, StructChangePayload, } from './edit/edit-controller';
|
|
25
27
|
export { isDimCommand, isImageCommand, isStructCommand } from './edit/commands';
|
|
@@ -41,7 +43,7 @@ export type { ShiftSpec, ShiftAxis } from './formula/refs';
|
|
|
41
43
|
export { CellEditorHost } from './edit/editor-host';
|
|
42
44
|
export type { CellEditorContext, CellEditorFactory, EditorResolver, EditorCommitValue } from './edit/editor-context';
|
|
43
45
|
export { definePlugin } from './plugin';
|
|
44
|
-
export type { ExcelPlugin, ExcelPluginContext, OverlayContext, OverlayNode, PluginEvent, Rect, ToolbarItem, ViewerApi, } from './plugin';
|
|
46
|
+
export type { ExcelPlugin, ExcelPluginContext, OverlayContext, OverlayNode, PluginEvent, Rect, ToolbarItem, ViewerApi, CreatePivotTableOptions, PivotOutput, } from './plugin';
|
|
45
47
|
export { GridMetrics, colIndexToLetters } from './layout/grid-metrics';
|
|
46
48
|
export { formatValue } from './format/number-format';
|
|
47
49
|
export { DEFAULT_THEME, mergeTheme } from './render/theme';
|
|
@@ -23,6 +23,8 @@ export declare function cloneImageAnchor(a: ImageAnchor): ImageAnchor;
|
|
|
23
23
|
export declare function addImage(sheet: SheetModel, anchor: ImageAnchor, index?: number): number;
|
|
24
24
|
/** 删一张图(调用方负责为 undo 捕获前态)。 */
|
|
25
25
|
export declare function removeImage(sheet: SheetModel, index: number): void;
|
|
26
|
+
/** 整个 CellModel 落格(承载公式/超链/批注/富文本/dispImgId 等 setCellValue 推不出的字段)+ 撑维度。 */
|
|
27
|
+
export declare function setCellModel(sheet: SheetModel, cell: CellModel): void;
|
|
26
28
|
/**
|
|
27
29
|
* 浮动图 → WPS 单元格内嵌图(DISPIMG)。
|
|
28
30
|
* 取 sheet.images[imageIndex] 的字节登记到 wb.cellImages(新 id),目标格设 =DISPIMG 公式 + dispImgId,
|
|
@@ -219,12 +219,19 @@ export interface SheetModel {
|
|
|
219
219
|
autoFilterRange?: MergeRange;
|
|
220
220
|
/** 含"列表"型数据验证的区域(选中时画下拉箭头) */
|
|
221
221
|
dataValidations: MergeRange[];
|
|
222
|
+
/** 列表型数据验证的可选值(点下拉箭头弹选;range 内任一格命中即用 options)。可选 —— 老数据/无选项时缺省 */
|
|
223
|
+
dataValidationLists?: {
|
|
224
|
+
range: MergeRange;
|
|
225
|
+
options: string[];
|
|
226
|
+
}[];
|
|
222
227
|
images: ImageAnchor[];
|
|
223
228
|
charts: ChartSpec[];
|
|
224
229
|
/** 形状 / 文本框(DrawingML sp) */
|
|
225
230
|
shapes: ShapeSpec[];
|
|
226
231
|
/** 迷你图(单元格内嵌折线/柱/盈亏图) */
|
|
227
232
|
sparklines: Sparkline[];
|
|
233
|
+
/** 透视表只读 UI 元数据:用于叠加字段按钮/下拉箭头;数据仍按普通单元格显示 */
|
|
234
|
+
pivotTables: PivotTableModel[];
|
|
228
235
|
/** 手动分页符(0-based 边界索引): 在这些行上方/列左侧画分页虚线 */
|
|
229
236
|
pageBreaks?: {
|
|
230
237
|
rows: number[];
|
|
@@ -284,6 +291,53 @@ export interface Sparkline {
|
|
|
284
291
|
color?: CssColor;
|
|
285
292
|
negativeColor?: CssColor;
|
|
286
293
|
}
|
|
294
|
+
/** 透视表字段按钮(只读 UI):按钮锚在对应标题/筛选单元格上。 */
|
|
295
|
+
export interface PivotButton {
|
|
296
|
+
row: number;
|
|
297
|
+
col: number;
|
|
298
|
+
label: string;
|
|
299
|
+
kind: 'row' | 'col' | 'page' | 'data' | 'field';
|
|
300
|
+
}
|
|
301
|
+
/** 透视表模型(只读):范围来自 pivotTableDefinition/location,字段来自 cacheFields + axis/dataFields。 */
|
|
302
|
+
export interface PivotTableModel {
|
|
303
|
+
name: string;
|
|
304
|
+
range: MergeRange;
|
|
305
|
+
fields: string[];
|
|
306
|
+
buttons: PivotButton[];
|
|
307
|
+
/** 静态透视表来源:当前模型内的源表 index + 源数据区域。用于运行时重建/后续导出。 */
|
|
308
|
+
source?: {
|
|
309
|
+
sheetIndex: number;
|
|
310
|
+
range: MergeRange;
|
|
311
|
+
};
|
|
312
|
+
/** 运行时透视布局元数据:字段 index 均为源数据区域内的绝对列 index。 */
|
|
313
|
+
layout?: PivotTableLayout;
|
|
314
|
+
/** 已折叠的外层行分组 key(行字段 ≥2 时,外层分组可折叠隐藏明细;空/缺省 = 全展开)。 */
|
|
315
|
+
collapsed?: string[];
|
|
316
|
+
/** 运行时:可折叠的分组表头所在输出行(绝对行号)+ 外层 key;每次重算刷新,供渲染折叠按钮 + 命中测试。 */
|
|
317
|
+
rowGroups?: {
|
|
318
|
+
row: number;
|
|
319
|
+
key: string;
|
|
320
|
+
}[];
|
|
321
|
+
}
|
|
322
|
+
export type PivotSummary = 'sum' | 'count' | 'avg' | 'max' | 'min';
|
|
323
|
+
/** all=全部 / non-empty=非空 / equals=单值等于 / include=多选包含(values 列出保留值,空=不约束)。 */
|
|
324
|
+
export type PivotFilterMode = 'all' | 'non-empty' | 'equals' | 'include';
|
|
325
|
+
export interface PivotFilterRule {
|
|
326
|
+
field: number;
|
|
327
|
+
mode: PivotFilterMode;
|
|
328
|
+
value?: string;
|
|
329
|
+
values?: string[];
|
|
330
|
+
}
|
|
331
|
+
export interface PivotValueRule {
|
|
332
|
+
field: number;
|
|
333
|
+
summary: PivotSummary;
|
|
334
|
+
}
|
|
335
|
+
export interface PivotTableLayout {
|
|
336
|
+
filters: PivotFilterRule[];
|
|
337
|
+
columns: number[];
|
|
338
|
+
rows: number[];
|
|
339
|
+
values: PivotValueRule[];
|
|
340
|
+
}
|
|
287
341
|
export interface WorkbookModel {
|
|
288
342
|
sheets: SheetModel[];
|
|
289
343
|
activeSheet: number;
|
|
@@ -297,6 +351,13 @@ export interface WorkbookModel {
|
|
|
297
351
|
cellImages?: Map<string, CellImage>;
|
|
298
352
|
}
|
|
299
353
|
export declare const cellKey: (row: number, col: number) => string;
|
|
354
|
+
/**
|
|
355
|
+
* 规范的"空白默认样式"——所有 SheetModel.styles[0] 必须是它(中性、无填充、无边框)。
|
|
356
|
+
* 空格 / 新建格 / setCellValue 落的格 / applyStyleOverride 的兜底基样式都回落到 styleId 0,
|
|
357
|
+
* 因此 index 0 绝不能是"恰好第一个被解析到的单元格样式"(否则那个格的底色/边框会冒到所有默认格,
|
|
358
|
+
* 见 parser 把首格 A1 绿底当默认导致粘贴/编辑串色的 bug)。loader-json / parser / clipboard-snapshot 共用此工厂。
|
|
359
|
+
*/
|
|
360
|
+
export declare function makeDefaultStyle(): CellStyle;
|
|
300
361
|
/** 数据钩子: 解析后、渲染前改模型(返回新模型或就地改) */
|
|
301
362
|
export type TransformModelFn = (workbook: WorkbookModel) => WorkbookModel | void;
|
|
302
363
|
/** 单元格样式覆盖(各字段可选;font/fill/borders 允许部分,与解析样式浅合并) */
|
package/dist/core/plugin.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { CellStyleFn, CellStyleOverride, ImageAnchor, MergeRange, TransformModelFn, WorkbookModel } from './model/types';
|
|
1
|
+
import { CellStyleFn, CellStyleOverride, ImageAnchor, MergeRange, PivotTableLayout, TransformModelFn, WorkbookModel } from './model/types';
|
|
2
2
|
import { CellValue, ReadOptions, SheetToJSONOptions } from './model/data-access';
|
|
3
3
|
import { CellSnapshot } from './model/snapshot';
|
|
4
4
|
import { CellInspection } from './model/inspect';
|
|
5
5
|
import { MenuItem } from './edit/context-menu';
|
|
6
6
|
import { EditorResolver } from './edit/editor-context';
|
|
7
7
|
import { EditableTarget } from './edit/types';
|
|
8
|
+
import { PasteBehavior } from './edit/paste-behavior';
|
|
8
9
|
import { ViewerTheme } from './render/theme';
|
|
9
10
|
import { ExcelSource } from './loader';
|
|
10
11
|
import { ImageExportOptions, PdfExportOptions, PrintOptions } from './export/types';
|
|
@@ -15,6 +16,24 @@ export interface Rect {
|
|
|
15
16
|
w: number;
|
|
16
17
|
h: number;
|
|
17
18
|
}
|
|
19
|
+
export type PivotOutput = {
|
|
20
|
+
kind: 'current-sheet';
|
|
21
|
+
cell: string;
|
|
22
|
+
} | {
|
|
23
|
+
kind: 'new-sheet';
|
|
24
|
+
};
|
|
25
|
+
export interface CreatePivotTableOptions {
|
|
26
|
+
/** 源数据区域,第一行作为字段名。缺省时使用当前选区。 */
|
|
27
|
+
sourceRange?: MergeRange;
|
|
28
|
+
/** 源数据所在 sheet index。缺省为当前活动表。 */
|
|
29
|
+
sourceSheetIndex?: number;
|
|
30
|
+
/** 输出位置。缺省为当前表源区域右侧空两列。 */
|
|
31
|
+
output?: PivotOutput;
|
|
32
|
+
/** 透视表布局。缺省:第一个文本字段为行字段,第一个数值字段为值字段。 */
|
|
33
|
+
layout?: Partial<PivotTableLayout>;
|
|
34
|
+
/** 是否打开右侧字段面板。缺省 false;工具栏入口会打开。 */
|
|
35
|
+
showPanel?: boolean;
|
|
36
|
+
}
|
|
18
37
|
export type PluginEvent = 'cell-click' | 'cell-dblclick' | 'selection-change' | 'sheet-change' | 'hyperlink-click' | 'cell-change' | 'edit-start' | 'edit-commit' | 'dim-change' | 'dirty-change' | 'image-change' | 'struct-change' | 'permission-denied';
|
|
19
38
|
/**
|
|
20
39
|
* 权限拒绝事件 payload (Phase A, 2026-06-08):mutation 因 editable / editableTargets /
|
|
@@ -24,8 +43,8 @@ export type PluginEvent = 'cell-click' | 'cell-dblclick' | 'selection-change' |
|
|
|
24
43
|
* 一次操作只 emit 一次 (避免 N 张图 spam N 次).
|
|
25
44
|
*/
|
|
26
45
|
export interface PermissionDeniedPayload {
|
|
27
|
-
/** 触发的操作类型 */
|
|
28
|
-
reason: 'paste' | 'merge' | 'unmerge' | 'image-place' | 'image-convert' | 'dimension' | 'other';
|
|
46
|
+
/** 触发的操作类型('copy' = 复制图片超字节预算,已降级为无图复制,非真正"拒绝") */
|
|
47
|
+
reason: 'paste' | 'merge' | 'unmerge' | 'image-place' | 'image-convert' | 'dimension' | 'copy' | 'other';
|
|
29
48
|
/** 被拒的目标格 (粘贴 / 合并 / 图片转换 等场景下的具体位置;'dimension' 时可空) */
|
|
30
49
|
cells: Array<{
|
|
31
50
|
row: number;
|
|
@@ -47,6 +66,10 @@ export interface ViewerApi {
|
|
|
47
66
|
setActiveSheet(index: number): void;
|
|
48
67
|
getSelection(): MergeRange | null;
|
|
49
68
|
setSelection(range: MergeRange): void;
|
|
69
|
+
/** 滚动到指定单元格;select=true 时同步选中目标格。 */
|
|
70
|
+
scrollToCell(row: number, col: number, opts?: {
|
|
71
|
+
select?: boolean;
|
|
72
|
+
}): boolean;
|
|
50
73
|
rectOf(row: number, col: number): Rect | null;
|
|
51
74
|
rectOfRange(range: MergeRange): Rect | null;
|
|
52
75
|
redraw(): void;
|
|
@@ -61,6 +84,18 @@ export interface ViewerApi {
|
|
|
61
84
|
setEditableTargets(targets: EditableTarget | EditableTarget[] | undefined): void;
|
|
62
85
|
/** 当前生效的可编辑白名单. `undefined` 表示未启用白名单. */
|
|
63
86
|
getEditableTargets(): EditableTarget | EditableTarget[] | undefined;
|
|
87
|
+
/** 按活动单元格所在列排序;未开启自动筛选时会先按选区/已用区建立筛选范围。 */
|
|
88
|
+
sortActiveColumn(dir: 'asc' | 'desc'): boolean;
|
|
89
|
+
/** 通过 API 直接创建静态透视表,不依赖当前页面选区或对话框。需开启 `pivotTable` + `editable` 配置(默认均关)。 */
|
|
90
|
+
createPivotTable(opts: CreatePivotTableOptions): boolean;
|
|
91
|
+
/** 基于当前选区创建静态透视汇总表;未传 opts 时使用默认布局并输出到右侧。需 `pivotTable` + `editable`。 */
|
|
92
|
+
createPivotTableFromSelection(opts?: {
|
|
93
|
+
rowFieldIndex?: number;
|
|
94
|
+
valueFieldIndex?: number;
|
|
95
|
+
output?: PivotOutput;
|
|
96
|
+
}): boolean;
|
|
97
|
+
/** 打开透视表字段选择对话框,再从当前选区创建静态透视汇总表。需 `pivotTable` + `editable`。 */
|
|
98
|
+
openPivotTableDialog(): boolean;
|
|
64
99
|
/** 导出当前/指定表为图片 Blob(默认 png) */
|
|
65
100
|
exportImage(opts?: ImageExportOptions): Promise<Blob>;
|
|
66
101
|
/** 导出为图片并触发下载 */
|
|
@@ -147,11 +182,18 @@ export interface ViewerApi {
|
|
|
147
182
|
row: number;
|
|
148
183
|
col: number;
|
|
149
184
|
}): boolean;
|
|
150
|
-
/** 解析 Excel/WPS 复制的剪贴板 HTML → 富粘贴(值+字体/颜色/填充/边框/对齐+合并+data-uri图)
|
|
185
|
+
/** 解析 Excel/WPS 复制的剪贴板 HTML → 富粘贴(值+字体/颜色/填充/边框/对齐+合并+data-uri图),整体单次撤销。
|
|
186
|
+
* behaviorOverride = 逐次粘贴行为预设(右键「选择性粘贴」用;缺省走 setPasteBehavior 设的默认) */
|
|
151
187
|
pasteRichHtml(html: string, at?: {
|
|
152
188
|
row: number;
|
|
153
189
|
col: number;
|
|
154
|
-
}): boolean;
|
|
190
|
+
}, behaviorOverride?: Partial<PasteBehavior> | null): boolean;
|
|
191
|
+
/** 读当前粘贴行为配置(完整) */
|
|
192
|
+
getPasteBehavior(): PasteBehavior;
|
|
193
|
+
/** 设粘贴行为默认(缺项回落默认);影响 Ctrl+V / 右键「粘贴」 */
|
|
194
|
+
setPasteBehavior(cfg: Partial<PasteBehavior> | null): void;
|
|
195
|
+
/** 打开「粘贴行为配置」面板(框架无关 DOM,三壳共用);需 editable。返回是否打开 */
|
|
196
|
+
openPasteConfigDialog(): boolean;
|
|
155
197
|
/** 把一张图片 blob 落到活动格(转内嵌图);剪贴板单图 / 拖文件进网格用 */
|
|
156
198
|
pasteImageBlob(blob: Blob, at?: {
|
|
157
199
|
row: number;
|
|
@@ -174,6 +174,11 @@ export declare class CanvasRenderer {
|
|
|
174
174
|
};
|
|
175
175
|
/** 屏幕坐标是否落在某个自动筛选表头的下拉按钮上;是则返回列号 */
|
|
176
176
|
filterButtonAt(view: ViewState, px: number, py: number): number | null;
|
|
177
|
+
/** 点击是否落在"活动格的数据验证下拉箭头"上(箭头只画在选区左上的列表验证格);是则返回该格。 */
|
|
178
|
+
dataValidationButtonAt(view: ViewState, px: number, py: number): {
|
|
179
|
+
row: number;
|
|
180
|
+
col: number;
|
|
181
|
+
} | null;
|
|
177
182
|
/** 屏幕坐标 → 单元格(0-based)。落在表头或越界返回 null。 */
|
|
178
183
|
cellAtScreen(view: ViewState, x: number, y: number): {
|
|
179
184
|
row: number;
|
|
@@ -230,6 +235,13 @@ export declare class CanvasRenderer {
|
|
|
230
235
|
* 用 this.{canvas,ctx,metrics,freeze,selection,dpr} 当前值,flags 控制 UI 装饰是否绘制。
|
|
231
236
|
*/
|
|
232
237
|
private paint;
|
|
238
|
+
/** 画各透视表的行分组折叠/展开按钮(贴在分组表头格最左)。 */
|
|
239
|
+
private drawPivotToggles;
|
|
240
|
+
/** 屏幕坐标是否落在某透视表的折叠按钮上;是则返回 { tableIdx, key }。 */
|
|
241
|
+
pivotToggleAt(view: ViewState, px: number, py: number): {
|
|
242
|
+
tableIdx: number;
|
|
243
|
+
key: string;
|
|
244
|
+
} | null;
|
|
233
245
|
/** 查找高亮: 所有命中淡黄,当前项橙色描边 */
|
|
234
246
|
private drawFind;
|
|
235
247
|
/**
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 透视表行分组折叠/展开按钮(canvas 绘制 + 控制器命中测试),与 autofilter 下拉按钮同款套路:
|
|
3
|
+
* 画在分组表头行最左格内,点击由 ViewerController.onMouseDown 经 CanvasRenderer.pivotToggleAt 命中。
|
|
4
|
+
* 只在多行字段(外层分组可折叠)时出现,导出时不画(导出件靠真 OOXML 透视表自身的展开)。
|
|
5
|
+
*/
|
|
6
|
+
/** 折叠按钮方框:左对齐贴在分组表头格内、垂直居中;格太窄(<8px)返回 null 不画。 */
|
|
7
|
+
export declare function pivotToggleBox(cellX: number, cellY: number, cellW: number, cellH: number): {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
size: number;
|
|
11
|
+
} | null;
|
|
12
|
+
/** 画一个折叠按钮:方框 + 横杠(展开态显示 −)/ 横竖杠(折叠态显示 +)。 */
|
|
13
|
+
export declare function drawPivotToggle(ctx: CanvasRenderingContext2D, x: number, y: number, size: number, collapsed: boolean): void;
|
|
@@ -5,11 +5,14 @@ import { CellValue, SheetToJSONOptions } from '../model/data-access';
|
|
|
5
5
|
import { CellSnapshot } from '../model/snapshot';
|
|
6
6
|
import { CellInspection } from '../model/inspect';
|
|
7
7
|
import { MenuItem } from '../edit/context-menu';
|
|
8
|
+
import { PivotOutputChoice } from './pivot-dialog-host';
|
|
9
|
+
import { PasteBehavior } from '../edit/paste-behavior';
|
|
8
10
|
import { EditorCommitValue, EditorResolver } from '../edit/editor-context';
|
|
9
11
|
import { CanvasRenderer, CellImageFit, RendererOptions, ViewState } from '../render/canvas-renderer';
|
|
10
12
|
import { OverlayQuads } from './overlay-manager';
|
|
11
13
|
import { ImageExportOptions, PdfExportOptions, PrintOptions } from '../export/types';
|
|
12
14
|
import { XlsxExportOptions } from '../export/xlsx-writer';
|
|
15
|
+
import { CreatePivotTableOptions } from '../plugin';
|
|
13
16
|
export type Cell = {
|
|
14
17
|
row: number;
|
|
15
18
|
col: number;
|
|
@@ -70,6 +73,8 @@ export interface ViewerControllerHooks {
|
|
|
70
73
|
onFindChange: () => void;
|
|
71
74
|
/** 筛选状态/浮层变化(壳据此 +1 让 FilterPopup / 工具栏重算) */
|
|
72
75
|
onFilterChange: () => void;
|
|
76
|
+
/** core 里新增/切换工作表时通知壳同步 activeSheet。 */
|
|
77
|
+
onActiveSheetChange?: (index: number) => void;
|
|
73
78
|
/** 编辑事件(cell-change/edit-start/edit-commit;壳转 emit + 插件派发) */
|
|
74
79
|
onEditEvent: (event: EditEventName, payload: unknown) => void;
|
|
75
80
|
/** 右键菜单触发前(Plan C):用户可调 `preventDefault()` 阻止内置菜单弹出(然后自渲染) */
|
|
@@ -123,6 +128,12 @@ export declare class ViewerController {
|
|
|
123
128
|
/** 右键上下文菜单宿主(G3;body 级 DOM,框架无关) */
|
|
124
129
|
private menuHost;
|
|
125
130
|
private lightbox;
|
|
131
|
+
private pivotDialog;
|
|
132
|
+
private pivotPanel;
|
|
133
|
+
private pasteConfigDialog;
|
|
134
|
+
private readonlyPrompt;
|
|
135
|
+
/** 透视表"活刷新"重入兜底:recompute 内部 setCellValue 不再触发 onModelChange,此旗保险。 */
|
|
136
|
+
private pivotRefreshing;
|
|
126
137
|
private lightboxEnabled;
|
|
127
138
|
/** 用户的右键菜单 transform 回调(Plan C):`(ctx, items) => MenuItem[] | undefined` */
|
|
128
139
|
private ctxMenuTransform;
|
|
@@ -163,6 +174,8 @@ export declare class ViewerController {
|
|
|
163
174
|
private editorHost;
|
|
164
175
|
/** 按格解析编辑器(壳合并 plugin.editor + prop.editor 后注入;E2) */
|
|
165
176
|
private editorResolver?;
|
|
177
|
+
/** paste 事件处理器(绑在 scroller 上;Ctrl+V 走它拿**原始**剪贴板 HTML,避开 clipboard.read() 的净化) */
|
|
178
|
+
private readonly onPasteHandler;
|
|
166
179
|
constructor(els: ViewerControllerEls, hooks: ViewerControllerHooks);
|
|
167
180
|
/** 切表/换簿/主题变化: 清状态,重建渲染器,重置滚动,量尺寸,建叠加层,绘制,按需重跑查找 */
|
|
168
181
|
rebuild(sheet: SheetModel, workbook: WorkbookModel, zoom: number, opts: RendererOptions): void;
|
|
@@ -265,6 +278,10 @@ export declare class ViewerController {
|
|
|
265
278
|
selectAll(): void;
|
|
266
279
|
/** 选中单个单元格并滚动到视图(查找定位用);range 模式,anchor=active */
|
|
267
280
|
selectCell(row: number, col: number): void;
|
|
281
|
+
/** 滚动到指定单元格;select=true 时同步选中目标格。 */
|
|
282
|
+
scrollToCell(row: number, col: number, opts?: {
|
|
283
|
+
select?: boolean;
|
|
284
|
+
}): boolean;
|
|
268
285
|
/** 命令式设选区(anchor=左上, active=右下) */
|
|
269
286
|
setSelectionRange(range: MergeRange): void;
|
|
270
287
|
private setCell;
|
|
@@ -296,7 +313,8 @@ export declare class ViewerController {
|
|
|
296
313
|
onContextMenu(e: MouseEvent): void;
|
|
297
314
|
/** 算右键 ctx:命中格 + 选区调整;非内容区 / 无 renderer 返 null */
|
|
298
315
|
private buildContextMenuCtx;
|
|
299
|
-
/**
|
|
316
|
+
/** 内置右键菜单项(独立提取,便于 transform 回调拿到再二次加工)。
|
|
317
|
+
* 只读模式:只返回**不改数据**的项(复制) —— 复制不修改数据源,只读也该能用;编辑模式给全套。 */
|
|
300
318
|
buildBuiltinContextMenuItems(ctx: ContextMenuCtx): MenuItem[];
|
|
301
319
|
/** 设置用户 transform 回调(`(ctx, items) => MenuItem[] | undefined`);壳侧调用 */
|
|
302
320
|
setContextMenuTransform(fn: ContextMenuTransform | null | undefined): void;
|
|
@@ -309,13 +327,26 @@ export declare class ViewerController {
|
|
|
309
327
|
private pageRows;
|
|
310
328
|
onKeyDown(e: KeyboardEvent): void;
|
|
311
329
|
private scrollActiveIntoView;
|
|
330
|
+
private scrollCellIntoView;
|
|
312
331
|
copySelection(): Promise<void>;
|
|
313
332
|
/**
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
*
|
|
333
|
+
* paste 事件粘贴(Ctrl+V 主路径,绑在 scroller 上)。`e.clipboardData` 给的是**原始未净化** HTML/图片/文本 ——
|
|
334
|
+
* 关键:`navigator.clipboard.read()`(pasteFromClipboard 用)会净化 HTML、删掉 `<style>` 块和注释,而 WPS/Excel
|
|
335
|
+
* 的格式(CSS 类)、数字格式(mso-number-format)、内嵌图(VML o:gfxdata)全在那里面 → 走 read 必丢。paste 事件不净化。
|
|
336
|
+
* 我们自己复制的快照(data-ooxml-clip)也一并原样拿到,1:1 不受影响。
|
|
337
|
+
*/
|
|
338
|
+
/**
|
|
339
|
+
* 统一出口(核心层唯一只读反馈点):**任何**改数据的操作撞只读 → EditController/控制器都经 `host.emit` 走到这里,
|
|
340
|
+
* 按 `readOnlyPrompt` 配置(dialog/toast/none)弹一次内置提醒,再转壳事件。新增输入方式只要照常走 EditController
|
|
341
|
+
* 的 API(其内 `isEditable` 中央闸门已逐格拦截 + emit permission-denied),无需各自重写只读检查/提醒。
|
|
317
342
|
*/
|
|
318
|
-
|
|
343
|
+
private emitEditEvent;
|
|
344
|
+
onPaste(e: ClipboardEvent): void;
|
|
345
|
+
/**
|
|
346
|
+
* 从系统剪贴板粘贴(右键菜单"粘贴"等无 paste 事件的入口用)。`clipboard.read()` 拿 text/html —— 注意它会**净化**
|
|
347
|
+
* HTML(删 `<style>`/注释),所以从 WPS/Excel 粘的格式不如 Ctrl+V(走 onPaste 的原始 HTML)全。否则单图 / TSV 兜底。
|
|
348
|
+
*/
|
|
349
|
+
pasteFromClipboard(behaviorOverride?: Partial<PasteBehavior> | null): Promise<boolean>;
|
|
319
350
|
/**
|
|
320
351
|
* 解析 Excel/WPS 复制的剪贴板 HTML(text/html)→ 富粘贴:值 + 字体/颜色/填充/边框/对齐 + 合并 + data-uri 图,
|
|
321
352
|
* **整体单次撤销**。无 `<table>` 返 false(调用方回退 TSV)。at 缺省用活动格。
|
|
@@ -323,7 +354,13 @@ export declare class ViewerController {
|
|
|
323
354
|
pasteRichHtml(html: string, at?: {
|
|
324
355
|
row: number;
|
|
325
356
|
col: number;
|
|
326
|
-
}): boolean;
|
|
357
|
+
}, behaviorOverride?: Partial<PasteBehavior> | null): boolean;
|
|
358
|
+
/** 读当前粘贴行为配置(完整)。 */
|
|
359
|
+
getPasteBehavior(): PasteBehavior;
|
|
360
|
+
/** 设粘贴行为默认(缺项回落默认);影响 Ctrl+V / 右键「粘贴」。右键「选择性粘贴」逐次预设走 pasteRichHtml 的第 3 参。 */
|
|
361
|
+
setPasteBehavior(cfg: Partial<PasteBehavior> | null): void;
|
|
362
|
+
/** 打开「粘贴行为配置」面板(框架无关 DOM,三壳共用);应用即 setPasteBehavior。需 editable。 */
|
|
363
|
+
openPasteConfigDialog(): boolean;
|
|
327
364
|
/** 把一张图片 blob 落到活动格(转内嵌图);剪贴板单图粘贴 / 拖文件进网格用。 */
|
|
328
365
|
pasteImageBlob(blob: Blob, at?: {
|
|
329
366
|
row: number;
|
|
@@ -361,6 +398,8 @@ export declare class ViewerController {
|
|
|
361
398
|
/** 重算筛选导致的隐藏行并应用到模型(行隐藏机制 → 几何归零) */
|
|
362
399
|
private applyFilters;
|
|
363
400
|
/** 点中下拉按钮 / 命令式: 打开某列筛选浮层(算去重值 + 已选 + 屏幕位置) */
|
|
401
|
+
/** 列表型数据验证下拉:在箭头处弹可选值菜单(复用右键菜单宿主),点选 → editCell(undo 可回退)。 */
|
|
402
|
+
private openDataValidationPicker;
|
|
364
403
|
openFilterPopup(col: number): void;
|
|
365
404
|
closeFilterPopup(): void;
|
|
366
405
|
/** 浮层「确定」: 勾选值落筛选态(全选=取消该列;子集=保留;空集=全隐藏)。 */
|
|
@@ -383,6 +422,43 @@ export declare class ViewerController {
|
|
|
383
422
|
col: number;
|
|
384
423
|
dir: 'asc' | 'desc' | null;
|
|
385
424
|
};
|
|
425
|
+
/** 按活动单元格所在列排序;若当前表未开启自动筛选,先按选区/已用区建立筛选范围。 */
|
|
426
|
+
sortActiveColumn(dir: 'asc' | 'desc'): boolean;
|
|
427
|
+
/** 打开 WPS 式透视表入口:确认选区字段后生成静态透视汇总表。需 `pivotTable` + `editable` 配置。 */
|
|
428
|
+
openPivotTableDialog(): boolean;
|
|
429
|
+
/** 兼容旧 API:基于当前选区创建静态透视汇总表。 */
|
|
430
|
+
createPivotTableFromSelection(opts?: {
|
|
431
|
+
rowFieldIndex?: number;
|
|
432
|
+
valueFieldIndex?: number;
|
|
433
|
+
output?: PivotOutputChoice;
|
|
434
|
+
}): boolean;
|
|
435
|
+
/** 通过 API 直接创建静态透视表,不依赖页面选区或对话框。需 `pivotTable` + `editable` 配置。 */
|
|
436
|
+
createPivotTable(opts: CreatePivotTableOptions): boolean;
|
|
437
|
+
private showPivotPanel;
|
|
438
|
+
/**
|
|
439
|
+
* 透视表的唯一重算入口:读 pivot.source/layout/collapsed → 重建静态结果 → 清旧区写新区 →
|
|
440
|
+
* 刷新 range/buttons/rowGroups。被面板改布局、源数据"活刷新"、折叠/展开三处共用,避免逻辑分叉。
|
|
441
|
+
*/
|
|
442
|
+
private recomputePivot;
|
|
443
|
+
/**
|
|
444
|
+
* 源数据"活刷新":任何模型变更(编辑/粘贴/撤销/重做都经 onModelChange)后,把所有透视表按其源区域重算,
|
|
445
|
+
* 让结果跟着源数据走(WPS 透视表的"活"语义)。重算用 setCellValue 直接改模型(不经命令栈,不再触发
|
|
446
|
+
* onModelChange),pivotRefreshing 兜底防重入。功能开关关闭或无透视表时零开销。
|
|
447
|
+
*/
|
|
448
|
+
private refreshPivotsAfterEdit;
|
|
449
|
+
/** 折叠/展开某个外层行分组(行字段 ≥2 时由折叠按钮触发),重算并重绘。 */
|
|
450
|
+
private togglePivotGroup;
|
|
451
|
+
/**
|
|
452
|
+
* 重建透视结果为二维单元格数组(框架无关纯计算)。
|
|
453
|
+
* 行字段第 1 个为外层分组,其余为内层明细 → 多行字段时产出可折叠的"大纲"(外层分组行带小计 +
|
|
454
|
+
* 内层缩进明细);单行字段退化为扁平(每个值一行,无折叠)。列字段横向展开,值字段可多个。
|
|
455
|
+
* groups 列出可折叠的分组表头行(相对 top 的偏移 + 外层 key),供渲染折叠按钮 + 命中测试。
|
|
456
|
+
*/
|
|
457
|
+
private buildPivotRows;
|
|
458
|
+
private failPivot;
|
|
459
|
+
private pivotFieldOptions;
|
|
460
|
+
private pivotFieldOptionsForSheet;
|
|
461
|
+
private pivotCellText;
|
|
386
462
|
/**
|
|
387
463
|
* 按某列对自动筛选数据区排序(只读视图重排:移动行内容 + 行高,不改文件)。
|
|
388
464
|
* 合并区与数据区相交则拒绝(与 Excel 一致)。排序前会清除该表筛选,避免行索引快照错位。
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { PasteBehavior } from '../edit/paste-behavior';
|
|
2
|
+
export interface PasteConfigDialogOptions {
|
|
3
|
+
current: PasteBehavior;
|
|
4
|
+
onSubmit: (cfg: PasteBehavior) => void;
|
|
5
|
+
}
|
|
6
|
+
export declare class PasteConfigDialogHost {
|
|
7
|
+
private el;
|
|
8
|
+
private cleanup;
|
|
9
|
+
show(opts: PasteConfigDialogOptions): void;
|
|
10
|
+
close(): void;
|
|
11
|
+
dispose(): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { PivotTableLayout as PivotPanelLayout } from '../model/types';
|
|
2
|
+
export interface PivotFieldOption {
|
|
3
|
+
index: number;
|
|
4
|
+
label: string;
|
|
5
|
+
numeric: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface PivotDialogOptions {
|
|
8
|
+
rangeLabel: string;
|
|
9
|
+
defaultOutputCell: string;
|
|
10
|
+
onSubmit: (output: PivotOutputChoice) => void;
|
|
11
|
+
}
|
|
12
|
+
export type PivotOutputChoice = {
|
|
13
|
+
kind: 'current-sheet';
|
|
14
|
+
cell: string;
|
|
15
|
+
} | {
|
|
16
|
+
kind: 'new-sheet';
|
|
17
|
+
};
|
|
18
|
+
export interface PivotPanelOptions {
|
|
19
|
+
fields: PivotFieldOption[];
|
|
20
|
+
filterValues: Record<number, string[]>;
|
|
21
|
+
layout: PivotPanelLayout;
|
|
22
|
+
onChange: (layout: PivotPanelLayout) => void;
|
|
23
|
+
}
|
|
24
|
+
export declare class PivotDialogHost {
|
|
25
|
+
private el;
|
|
26
|
+
private cleanup;
|
|
27
|
+
show(opts: PivotDialogOptions): void;
|
|
28
|
+
close(): void;
|
|
29
|
+
dispose(): void;
|
|
30
|
+
}
|
|
31
|
+
export declare class PivotFieldPanelHost {
|
|
32
|
+
private el;
|
|
33
|
+
private opts;
|
|
34
|
+
/** 当前正在编辑筛选值的字段 index(null = 未展开筛选明细面板) */
|
|
35
|
+
private activeFilterField;
|
|
36
|
+
show(opts: PivotPanelOptions): void;
|
|
37
|
+
close(): void;
|
|
38
|
+
dispose(): void;
|
|
39
|
+
private render;
|
|
40
|
+
private fieldRow;
|
|
41
|
+
private area;
|
|
42
|
+
private updateLayout;
|
|
43
|
+
/** 筛选 chip 上的小按钮:显示当前筛选状态(全部/非空/N 项),点开底部明细面板编辑。 */
|
|
44
|
+
private filterSummaryBtn;
|
|
45
|
+
/** 底部筛选明细面板:全部/非空/多选 三模式 + 多选时的值复选框列表(WPS 风格勾选筛选)。 */
|
|
46
|
+
private filterDetail;
|
|
47
|
+
private summarySelect;
|
|
48
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 只读提醒 UI(框架无关 DOM,三壳共用)。粘贴撞只读格时,按配置:
|
|
3
|
+
* - 'dialog'(默认):弹窗列出**具体哪些格**只读(A1 引用),让用户明确知道哪部分没粘上;
|
|
4
|
+
* - 'toast':顶部气泡,简短提示 + 自动消失;
|
|
5
|
+
* - 'none':不弹内置 UI(只走 permission-denied 事件,消费方自处理)。
|
|
6
|
+
* 逐格精确:cells 是被跳过的只读格列表。
|
|
7
|
+
*/
|
|
8
|
+
export type ReadOnlyPromptMode = 'dialog' | 'toast' | 'none';
|
|
9
|
+
export declare class ReadOnlyPromptHost {
|
|
10
|
+
private el;
|
|
11
|
+
private toastEl;
|
|
12
|
+
private toastTimer;
|
|
13
|
+
private cleanup;
|
|
14
|
+
show(mode: ReadOnlyPromptMode, message: string, cells: Array<{
|
|
15
|
+
row: number;
|
|
16
|
+
col: number;
|
|
17
|
+
}>): void;
|
|
18
|
+
private showToast;
|
|
19
|
+
private closeToast;
|
|
20
|
+
private showDialog;
|
|
21
|
+
close(): void;
|
|
22
|
+
dispose(): void;
|
|
23
|
+
}
|