@veltra/sheet 2.0.1 → 2.1.1
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/dist/index.d.ts +4 -26
- package/dist/index.js +3 -23
- package/dist/tools/builtin.js +279 -8
- package/dist/tools/context.d.ts +54 -11
- package/dist/tools/context.js +28 -5
- package/dist/tools/download.js +68 -0
- package/dist/tools/export.worker.d.ts +16 -0
- package/dist/tools/export.worker.js +29 -0
- package/dist/tools/registry.d.ts +7 -4
- package/dist/tools/registry.js +1 -3
- package/dist/types/index.d.ts +1 -0
- package/dist/types/sheet.d.ts +6 -5
- package/dist/vue/formula-bar.js +393 -0
- package/dist/vue/formula-suggest-list.js +66 -0
- package/dist/vue/import-file.js +140 -0
- package/dist/vue/insert-count-menu-item.js +68 -0
- package/dist/vue/insert-image.js +79 -0
- package/dist/vue/popup-helpers.js +73 -0
- package/dist/vue/popups/border-popup.js +75 -0
- package/dist/vue/popups/border-preset-glyph.js +106 -0
- package/dist/vue/popups/export-popup.js +51 -0
- package/dist/vue/popups/fill-color-popup.js +37 -0
- package/dist/vue/popups/find-popup.js +113 -0
- package/dist/vue/popups/font-color-popup.js +37 -0
- package/dist/vue/popups/font-size-popup.js +63 -0
- package/dist/vue/popups/import.worker.d.ts +21 -0
- package/dist/vue/popups/import.worker.js +41 -0
- package/dist/vue/popups/insert-image-popup.js +38 -0
- package/dist/vue/sheet-context-menu.js +200 -0
- package/dist/vue/sheet-tabs.js +162 -0
- package/dist/vue/sheet-toolbar.js +106 -0
- package/dist/vue/sheet.js +144 -164
- package/dist/vue/style.d.ts +11 -1
- package/dist/vue/style.js +10 -0
- package/dist/vue/style2.css +564 -3
- package/dist/vue/use-find-replace.js +161 -0
- package/dist/vue/use-formula-ref-select.js +37 -0
- package/dist/vue/use-formula-suggest.js +126 -0
- package/dist/vue/use-sheet-grid.js +180 -0
- package/dist/vue/use-sheet-state.js +122 -0
- package/dist/vue/use-sheet-tabs-bar.js +90 -0
- package/dist/vue/use-tool-groups.js +42 -0
- package/dist/vue/use-tool-popup.js +123 -0
- package/dist/vue/use-toolbar-scroll.js +72 -0
- package/package.json +12 -7
- package/src/env.d.ts +11 -0
- package/src/index.ts +203 -14
- package/src/tools/__test__/builtin.test.ts +208 -66
- package/src/tools/__test__/context.test.ts +62 -2
- package/src/tools/builtin.ts +350 -6
- package/src/tools/context.ts +89 -11
- package/src/tools/download.ts +82 -0
- package/src/tools/export.worker.ts +61 -0
- package/src/tools/registry.ts +16 -1
- package/src/types/index.ts +6 -0
- package/src/types/sheet.ts +5 -3
- package/src/vue/__test__/formula-bar.test.ts +455 -0
- package/src/vue/__test__/import-file.test.ts +183 -0
- package/src/vue/__test__/insert-count-menu-item.test.ts +123 -0
- package/src/vue/__test__/insert-image-popup.test.ts +89 -0
- package/src/vue/__test__/insert-image.test.ts +100 -0
- package/src/vue/__test__/sheet-component.test.ts +716 -27
- package/src/vue/__test__/sheet-context-menu.test.ts +206 -0
- package/src/vue/__test__/use-formula-ref-select.test.ts +35 -0
- package/src/vue/__test__/use-formula-suggest.test.ts +83 -0
- package/src/vue/formula-bar.vue +473 -0
- package/src/vue/formula-suggest-list.vue +64 -0
- package/src/vue/import-file.ts +173 -0
- package/src/vue/insert-count-menu-item.vue +69 -0
- package/src/vue/insert-image.ts +90 -0
- package/src/vue/parsing.ts +11 -0
- package/src/vue/popup-helpers.ts +50 -0
- package/src/vue/popups/border-popup.vue +93 -0
- package/src/vue/popups/border-preset-glyph.vue +111 -0
- package/src/vue/popups/export-popup.vue +52 -0
- package/src/vue/popups/fill-color-popup.vue +39 -0
- package/src/vue/popups/find-popup.vue +111 -0
- package/src/vue/popups/font-color-popup.vue +39 -0
- package/src/vue/popups/font-size-popup.vue +52 -0
- package/src/vue/popups/import.worker.ts +66 -0
- package/src/vue/popups/insert-image-popup.vue +39 -0
- package/src/vue/sheet-context-menu.ts +229 -0
- package/src/vue/sheet-tabs.vue +162 -0
- package/src/vue/sheet-toolbar.vue +91 -0
- package/src/vue/sheet.vue +161 -186
- package/src/vue/style.scss +646 -3
- package/src/vue/style.ts +11 -0
- package/src/vue/use-find-replace.ts +200 -0
- package/src/vue/use-formula-ref-select.ts +34 -0
- package/src/vue/use-formula-suggest.ts +150 -0
- package/src/vue/use-sheet-grid.ts +243 -0
- package/src/vue/use-sheet-state.ts +161 -0
- package/src/vue/use-sheet-tabs-bar.ts +115 -0
- package/src/vue/use-tool-groups.ts +61 -0
- package/src/vue/use-tool-popup.ts +150 -0
- package/src/vue/use-toolbar-scroll.ts +95 -0
- package/dist/core/address.d.ts +0 -60
- package/dist/core/address.js +0 -142
- package/dist/core/address.js.map +0 -1
- package/dist/core/cell-store.d.ts +0 -61
- package/dist/core/cell-store.js +0 -135
- package/dist/core/cell-store.js.map +0 -1
- package/dist/core/command/default-registry.d.ts +0 -10
- package/dist/core/command/default-registry.js +0 -18
- package/dist/core/command/default-registry.js.map +0 -1
- package/dist/core/command/history.d.ts +0 -64
- package/dist/core/command/history.js +0 -127
- package/dist/core/command/history.js.map +0 -1
- package/dist/core/command/merge-cells.d.ts +0 -21
- package/dist/core/command/merge-cells.js +0 -74
- package/dist/core/command/merge-cells.js.map +0 -1
- package/dist/core/command/registry.d.ts +0 -17
- package/dist/core/command/registry.js +0 -26
- package/dist/core/command/registry.js.map +0 -1
- package/dist/core/command/set-cell-formula.d.ts +0 -17
- package/dist/core/command/set-cell-formula.js +0 -29
- package/dist/core/command/set-cell-formula.js.map +0 -1
- package/dist/core/command/set-cell-value.d.ts +0 -22
- package/dist/core/command/set-cell-value.js +0 -35
- package/dist/core/command/set-cell-value.js.map +0 -1
- package/dist/core/command/types.d.ts +0 -68
- package/dist/core/events.js +0 -29
- package/dist/core/events.js.map +0 -1
- package/dist/core/fill.d.ts +0 -34
- package/dist/core/fill.js +0 -320
- package/dist/core/fill.js.map +0 -1
- package/dist/core/formula/ast.d.ts +0 -58
- package/dist/core/formula/ast.js +0 -38
- package/dist/core/formula/ast.js.map +0 -1
- package/dist/core/formula/dependency-graph.d.ts +0 -70
- package/dist/core/formula/dependency-graph.js +0 -269
- package/dist/core/formula/dependency-graph.js.map +0 -1
- package/dist/core/formula/errors.d.ts +0 -25
- package/dist/core/formula/errors.js +0 -36
- package/dist/core/formula/errors.js.map +0 -1
- package/dist/core/formula/evaluator.d.ts +0 -41
- package/dist/core/formula/evaluator.js +0 -154
- package/dist/core/formula/evaluator.js.map +0 -1
- package/dist/core/formula/functions.d.ts +0 -30
- package/dist/core/formula/functions.js +0 -209
- package/dist/core/formula/functions.js.map +0 -1
- package/dist/core/formula/parser.d.ts +0 -7
- package/dist/core/formula/parser.js +0 -208
- package/dist/core/formula/parser.js.map +0 -1
- package/dist/core/formula/tokenizer.d.ts +0 -37
- package/dist/core/formula/tokenizer.js +0 -146
- package/dist/core/formula/tokenizer.js.map +0 -1
- package/dist/core/merge-manager.d.ts +0 -64
- package/dist/core/merge-manager.js +0 -111
- package/dist/core/merge-manager.js.map +0 -1
- package/dist/core/selection.d.ts +0 -31
- package/dist/core/selection.js +0 -62
- package/dist/core/selection.js.map +0 -1
- package/dist/core/sheet.d.ts +0 -116
- package/dist/core/sheet.js +0 -224
- package/dist/core/sheet.js.map +0 -1
- package/dist/core/workbook.d.ts +0 -43
- package/dist/core/workbook.js +0 -77
- package/dist/core/workbook.js.map +0 -1
- package/dist/grid/sheet-grid.d.ts +0 -81
- package/dist/grid/sheet-grid.js +0 -331
- package/dist/grid/sheet-grid.js.map +0 -1
- package/dist/grid/vtable-theme.js +0 -80
- package/dist/grid/vtable-theme.js.map +0 -1
- package/dist/tools/builtin.js.map +0 -1
- package/dist/tools/context.js.map +0 -1
- package/dist/tools/registry.js.map +0 -1
- package/dist/vue/index.d.ts +0 -2
- package/dist/vue/sheet.js.map +0 -1
- package/dist/vue/sheet.vue.d.ts +0 -24
- package/src/core/__test__/address.test.ts +0 -113
- package/src/core/__test__/cell-store.test.ts +0 -97
- package/src/core/__test__/command.test.ts +0 -377
- package/src/core/__test__/fill.test.ts +0 -140
- package/src/core/__test__/formula-adversarial.test.ts +0 -265
- package/src/core/__test__/formula-engine.test.ts +0 -470
- package/src/core/__test__/formula-functions.test.ts +0 -178
- package/src/core/__test__/formula-parser.test.ts +0 -160
- package/src/core/__test__/history.test.ts +0 -225
- package/src/core/__test__/merge-manager.test.ts +0 -106
- package/src/core/__test__/sheet.test.ts +0 -142
- package/src/core/address.ts +0 -166
- package/src/core/cell-store.ts +0 -173
- package/src/core/command/default-registry.ts +0 -15
- package/src/core/command/history.ts +0 -167
- package/src/core/command/index.ts +0 -7
- package/src/core/command/merge-cells.ts +0 -74
- package/src/core/command/registry.ts +0 -30
- package/src/core/command/set-cell-formula.ts +0 -29
- package/src/core/command/set-cell-value.ts +0 -38
- package/src/core/command/types.ts +0 -73
- package/src/core/events.ts +0 -37
- package/src/core/fill.ts +0 -314
- package/src/core/formula/ast.ts +0 -66
- package/src/core/formula/dependency-graph.ts +0 -329
- package/src/core/formula/errors.ts +0 -41
- package/src/core/formula/evaluator.ts +0 -219
- package/src/core/formula/functions.ts +0 -266
- package/src/core/formula/index.ts +0 -7
- package/src/core/formula/parser.ts +0 -198
- package/src/core/formula/tokenizer.ts +0 -160
- package/src/core/merge-manager.ts +0 -158
- package/src/core/selection.ts +0 -66
- package/src/core/sheet.ts +0 -282
- package/src/core/workbook.ts +0 -99
- package/src/grid/__test__/canvas-mock.ts +0 -49
- package/src/grid/__test__/setup.ts +0 -3
- package/src/grid/__test__/sheet-grid-formula.test.ts +0 -140
- package/src/grid/__test__/sheet-grid.test.ts +0 -275
- package/src/grid/sheet-grid.ts +0 -407
- package/src/grid/vtable-theme.ts +0 -61
package/dist/core/workbook.d.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { DependencyGraph } from "./formula/dependency-graph.js";
|
|
2
|
-
import { Sheet } from "./sheet.js";
|
|
3
|
-
//#region src/core/workbook.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* Workbook:多 Sheet 管理。
|
|
6
|
-
* 所有 sheet 共享一个公式依赖图(跨表引用与增量重算的中枢)。
|
|
7
|
-
*/
|
|
8
|
-
type WorkbookEvents = {
|
|
9
|
-
/** 激活 sheet 切换 */
|
|
10
|
-
'active-sheet-change': {
|
|
11
|
-
sheet: Sheet;
|
|
12
|
-
index: number;
|
|
13
|
-
};
|
|
14
|
-
/** sheet 增删 */
|
|
15
|
-
'sheets-change': {
|
|
16
|
-
sheets: Sheet[];
|
|
17
|
-
};
|
|
18
|
-
};
|
|
19
|
-
declare class Workbook {
|
|
20
|
-
private sheets;
|
|
21
|
-
private activeIndex;
|
|
22
|
-
private emitter;
|
|
23
|
-
/** 工作簿级公式依赖图(全部 sheet 共享) */
|
|
24
|
-
readonly formulaGraph: DependencyGraph;
|
|
25
|
-
constructor();
|
|
26
|
-
get sheetCount(): number;
|
|
27
|
-
get activeSheet(): Sheet;
|
|
28
|
-
get activeSheetIndex(): number;
|
|
29
|
-
getSheets(): Sheet[];
|
|
30
|
-
getSheet(name: string): Sheet | undefined;
|
|
31
|
-
/** 新增 sheet,名称缺省为 Sheet{n}(保证唯一) */
|
|
32
|
-
addSheet(name?: string): Sheet;
|
|
33
|
-
/** 删除 sheet;至少保留一个。删除激活项时激活相邻 sheet */
|
|
34
|
-
removeSheet(name: string): boolean;
|
|
35
|
-
/** 激活指定 sheet */
|
|
36
|
-
activateSheet(name: string): boolean;
|
|
37
|
-
on<K extends keyof WorkbookEvents>(type: K, handler: (payload: WorkbookEvents[K]) => void): () => void;
|
|
38
|
-
off<K extends keyof WorkbookEvents>(type: K, handler: (payload: WorkbookEvents[K]) => void): void;
|
|
39
|
-
private nextDefaultName;
|
|
40
|
-
}
|
|
41
|
-
//#endregion
|
|
42
|
-
export { Workbook, WorkbookEvents };
|
|
43
|
-
//# sourceMappingURL=workbook.d.ts.map
|
package/dist/core/workbook.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { TypedEventEmitter } from "./events.js";
|
|
2
|
-
import { DependencyGraph } from "./formula/dependency-graph.js";
|
|
3
|
-
import { Sheet } from "./sheet.js";
|
|
4
|
-
//#region src/core/workbook.ts
|
|
5
|
-
var Workbook = class {
|
|
6
|
-
sheets = [];
|
|
7
|
-
activeIndex = 0;
|
|
8
|
-
emitter = new TypedEventEmitter();
|
|
9
|
-
/** 工作簿级公式依赖图(全部 sheet 共享) */
|
|
10
|
-
formulaGraph = new DependencyGraph();
|
|
11
|
-
constructor() {
|
|
12
|
-
this.addSheet();
|
|
13
|
-
}
|
|
14
|
-
get sheetCount() {
|
|
15
|
-
return this.sheets.length;
|
|
16
|
-
}
|
|
17
|
-
get activeSheet() {
|
|
18
|
-
return this.sheets[this.activeIndex];
|
|
19
|
-
}
|
|
20
|
-
get activeSheetIndex() {
|
|
21
|
-
return this.activeIndex;
|
|
22
|
-
}
|
|
23
|
-
getSheets() {
|
|
24
|
-
return [...this.sheets];
|
|
25
|
-
}
|
|
26
|
-
getSheet(name) {
|
|
27
|
-
return this.sheets.find((sheet) => sheet.name === name);
|
|
28
|
-
}
|
|
29
|
-
/** 新增 sheet,名称缺省为 Sheet{n}(保证唯一) */
|
|
30
|
-
addSheet(name) {
|
|
31
|
-
const sheet = new Sheet(name ?? this.nextDefaultName(), this.formulaGraph);
|
|
32
|
-
this.sheets.push(sheet);
|
|
33
|
-
this.emitter.emit("sheets-change", { sheets: this.getSheets() });
|
|
34
|
-
return sheet;
|
|
35
|
-
}
|
|
36
|
-
/** 删除 sheet;至少保留一个。删除激活项时激活相邻 sheet */
|
|
37
|
-
removeSheet(name) {
|
|
38
|
-
if (this.sheets.length <= 1) return false;
|
|
39
|
-
const index = this.sheets.findIndex((sheet) => sheet.name === name);
|
|
40
|
-
if (index < 0) return false;
|
|
41
|
-
const [removed] = this.sheets.splice(index, 1);
|
|
42
|
-
this.formulaGraph.unregisterSheet(removed);
|
|
43
|
-
if (this.activeIndex >= this.sheets.length) this.activeIndex = this.sheets.length - 1;
|
|
44
|
-
this.emitter.emit("sheets-change", { sheets: this.getSheets() });
|
|
45
|
-
this.emitter.emit("active-sheet-change", {
|
|
46
|
-
sheet: this.activeSheet,
|
|
47
|
-
index: this.activeIndex
|
|
48
|
-
});
|
|
49
|
-
return true;
|
|
50
|
-
}
|
|
51
|
-
/** 激活指定 sheet */
|
|
52
|
-
activateSheet(name) {
|
|
53
|
-
const index = this.sheets.findIndex((sheet) => sheet.name === name);
|
|
54
|
-
if (index < 0 || index === this.activeIndex) return false;
|
|
55
|
-
this.activeIndex = index;
|
|
56
|
-
this.emitter.emit("active-sheet-change", {
|
|
57
|
-
sheet: this.activeSheet,
|
|
58
|
-
index
|
|
59
|
-
});
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
on(type, handler) {
|
|
63
|
-
return this.emitter.on(type, handler);
|
|
64
|
-
}
|
|
65
|
-
off(type, handler) {
|
|
66
|
-
this.emitter.off(type, handler);
|
|
67
|
-
}
|
|
68
|
-
nextDefaultName() {
|
|
69
|
-
let n = this.sheets.length + 1;
|
|
70
|
-
while (this.getSheet(`Sheet${n}`)) n++;
|
|
71
|
-
return `Sheet${n}`;
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
//#endregion
|
|
75
|
-
export { Workbook };
|
|
76
|
-
|
|
77
|
-
//# sourceMappingURL=workbook.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"workbook.js","names":[],"sources":["../../src/core/workbook.ts"],"sourcesContent":["import { TypedEventEmitter } from './events'\nimport { DependencyGraph } from './formula/dependency-graph'\nimport { Sheet } from './sheet'\n\n/**\n * Workbook:多 Sheet 管理。\n * 所有 sheet 共享一个公式依赖图(跨表引用与增量重算的中枢)。\n */\n\nexport type WorkbookEvents = {\n /** 激活 sheet 切换 */\n 'active-sheet-change': { sheet: Sheet; index: number }\n /** sheet 增删 */\n 'sheets-change': { sheets: Sheet[] }\n}\n\nexport class Workbook {\n private sheets: Sheet[] = []\n private activeIndex = 0\n private emitter = new TypedEventEmitter<WorkbookEvents>()\n /** 工作簿级公式依赖图(全部 sheet 共享) */\n readonly formulaGraph = new DependencyGraph()\n\n constructor() {\n this.addSheet()\n }\n\n get sheetCount(): number {\n return this.sheets.length\n }\n\n get activeSheet(): Sheet {\n return this.sheets[this.activeIndex]!\n }\n\n get activeSheetIndex(): number {\n return this.activeIndex\n }\n\n getSheets(): Sheet[] {\n return [...this.sheets]\n }\n\n getSheet(name: string): Sheet | undefined {\n return this.sheets.find((sheet) => sheet.name === name)\n }\n\n /** 新增 sheet,名称缺省为 Sheet{n}(保证唯一) */\n addSheet(name?: string): Sheet {\n const sheet = new Sheet(name ?? this.nextDefaultName(), this.formulaGraph)\n this.sheets.push(sheet)\n this.emitter.emit('sheets-change', { sheets: this.getSheets() })\n return sheet\n }\n\n /** 删除 sheet;至少保留一个。删除激活项时激活相邻 sheet */\n removeSheet(name: string): boolean {\n if (this.sheets.length <= 1) return false\n const index = this.sheets.findIndex((sheet) => sheet.name === name)\n if (index < 0) return false\n const [removed] = this.sheets.splice(index, 1)\n this.formulaGraph.unregisterSheet(removed!)\n if (this.activeIndex >= this.sheets.length) {\n this.activeIndex = this.sheets.length - 1\n }\n this.emitter.emit('sheets-change', { sheets: this.getSheets() })\n this.emitter.emit('active-sheet-change', { sheet: this.activeSheet, index: this.activeIndex })\n return true\n }\n\n /** 激活指定 sheet */\n activateSheet(name: string): boolean {\n const index = this.sheets.findIndex((sheet) => sheet.name === name)\n if (index < 0 || index === this.activeIndex) return false\n this.activeIndex = index\n this.emitter.emit('active-sheet-change', { sheet: this.activeSheet, index })\n return true\n }\n\n on<K extends keyof WorkbookEvents>(\n type: K,\n handler: (payload: WorkbookEvents[K]) => void\n ): () => void {\n return this.emitter.on(type, handler)\n }\n\n off<K extends keyof WorkbookEvents>(\n type: K,\n handler: (payload: WorkbookEvents[K]) => void\n ): void {\n this.emitter.off(type, handler)\n }\n\n private nextDefaultName(): string {\n let n = this.sheets.length + 1\n while (this.getSheet(`Sheet${n}`)) n++\n return `Sheet${n}`\n }\n}\n"],"mappings":";;;;AAgBA,IAAa,WAAb,MAAsB;CACpB,SAA0B,CAAC;CAC3B,cAAsB;CACtB,UAAkB,IAAI,kBAAkC;;CAExD,eAAwB,IAAI,gBAAgB;CAE5C,cAAc;EACZ,KAAK,SAAS;CAChB;CAEA,IAAI,aAAqB;EACvB,OAAO,KAAK,OAAO;CACrB;CAEA,IAAI,cAAqB;EACvB,OAAO,KAAK,OAAO,KAAK;CAC1B;CAEA,IAAI,mBAA2B;EAC7B,OAAO,KAAK;CACd;CAEA,YAAqB;EACnB,OAAO,CAAC,GAAG,KAAK,MAAM;CACxB;CAEA,SAAS,MAAiC;EACxC,OAAO,KAAK,OAAO,MAAM,UAAU,MAAM,SAAS,IAAI;CACxD;;CAGA,SAAS,MAAsB;EAC7B,MAAM,QAAQ,IAAI,MAAM,QAAQ,KAAK,gBAAgB,GAAG,KAAK,YAAY;EACzE,KAAK,OAAO,KAAK,KAAK;EACtB,KAAK,QAAQ,KAAK,iBAAiB,EAAE,QAAQ,KAAK,UAAU,EAAE,CAAC;EAC/D,OAAO;CACT;;CAGA,YAAY,MAAuB;EACjC,IAAI,KAAK,OAAO,UAAU,GAAG,OAAO;EACpC,MAAM,QAAQ,KAAK,OAAO,WAAW,UAAU,MAAM,SAAS,IAAI;EAClE,IAAI,QAAQ,GAAG,OAAO;EACtB,MAAM,CAAC,WAAW,KAAK,OAAO,OAAO,OAAO,CAAC;EAC7C,KAAK,aAAa,gBAAgB,OAAQ;EAC1C,IAAI,KAAK,eAAe,KAAK,OAAO,QAClC,KAAK,cAAc,KAAK,OAAO,SAAS;EAE1C,KAAK,QAAQ,KAAK,iBAAiB,EAAE,QAAQ,KAAK,UAAU,EAAE,CAAC;EAC/D,KAAK,QAAQ,KAAK,uBAAuB;GAAE,OAAO,KAAK;GAAa,OAAO,KAAK;EAAY,CAAC;EAC7F,OAAO;CACT;;CAGA,cAAc,MAAuB;EACnC,MAAM,QAAQ,KAAK,OAAO,WAAW,UAAU,MAAM,SAAS,IAAI;EAClE,IAAI,QAAQ,KAAK,UAAU,KAAK,aAAa,OAAO;EACpD,KAAK,cAAc;EACnB,KAAK,QAAQ,KAAK,uBAAuB;GAAE,OAAO,KAAK;GAAa;EAAM,CAAC;EAC3E,OAAO;CACT;CAEA,GACE,MACA,SACY;EACZ,OAAO,KAAK,QAAQ,GAAG,MAAM,OAAO;CACtC;CAEA,IACE,MACA,SACM;EACN,KAAK,QAAQ,IAAI,MAAM,OAAO;CAChC;CAEA,kBAAkC;EAChC,IAAI,IAAI,KAAK,OAAO,SAAS;EAC7B,OAAO,KAAK,SAAS,QAAQ,GAAG,GAAG;EACnC,OAAO,QAAQ;CACjB;AACF"}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import { CellAddress } from "../core/address.js";
|
|
2
|
-
import { Sheet } from "../core/sheet.js";
|
|
3
|
-
import { ListTable } from "@visactor/vtable";
|
|
4
|
-
//#region src/grid/sheet-grid.d.ts
|
|
5
|
-
/** 右键菜单回调参数(vue 层弹 UContextmenu;grid 不依赖 desktop) */
|
|
6
|
-
interface SheetGridContextMenuInfo {
|
|
7
|
-
x: number;
|
|
8
|
-
y: number;
|
|
9
|
-
/** body 格地址;行号/列头为 null */
|
|
10
|
-
addr: CellAddress | null;
|
|
11
|
-
}
|
|
12
|
-
interface SheetGridOptions {
|
|
13
|
-
container: HTMLElement;
|
|
14
|
-
sheet: Sheet;
|
|
15
|
-
/** 渲染行数,默认 100 */
|
|
16
|
-
rows?: number;
|
|
17
|
-
/** 渲染列数,默认 26(A..Z) */
|
|
18
|
-
cols?: number;
|
|
19
|
-
/** 单元格右键(已 preventDefault);由 vue 层弹出菜单 */
|
|
20
|
-
onContextMenu?: (info: SheetGridContextMenuInfo) => void;
|
|
21
|
-
}
|
|
22
|
-
declare class SheetGrid {
|
|
23
|
-
private readonly sheet;
|
|
24
|
-
private readonly table;
|
|
25
|
-
private readonly container;
|
|
26
|
-
private readonly rows;
|
|
27
|
-
private readonly cols;
|
|
28
|
-
private readonly editorName;
|
|
29
|
-
private readonly onContextMenu?;
|
|
30
|
-
private readonly disposers;
|
|
31
|
-
/** 编辑提交期间累积的模型变更(提交结束统一回推表格,覆盖公式派生格) */
|
|
32
|
-
private pendingTableSync;
|
|
33
|
-
/** 实测坐标偏移(行号列数 / 列头行数),首次使用时测量 */
|
|
34
|
-
private offsets?;
|
|
35
|
-
/** 填充柄:mousedown 时的源选区(模型坐标) */
|
|
36
|
-
private fillSourceRange;
|
|
37
|
-
constructor(options: SheetGridOptions);
|
|
38
|
-
/** 底层 ListTable 实例(调试与测试用) */
|
|
39
|
-
getTable(): ListTable;
|
|
40
|
-
/** 全量刷新(合并结构变化、批量数据变更后调用) */
|
|
41
|
-
refresh(): void;
|
|
42
|
-
/** 撤销一步(模型命令历史) */
|
|
43
|
-
undo(): boolean;
|
|
44
|
-
/** 重做一步(模型命令历史) */
|
|
45
|
-
redo(): boolean;
|
|
46
|
-
release(): void;
|
|
47
|
-
/**
|
|
48
|
-
* 实测偏移:列头行数取 columnHeaderLevelCount;
|
|
49
|
-
* 行号列不被计入 rowHeaderLevelCount,用 isSeriesNumber 逐列探测。
|
|
50
|
-
* 结果缓存(表格实例不变,布局不变)。
|
|
51
|
-
*/
|
|
52
|
-
private getOffsets;
|
|
53
|
-
/** VTable 坐标 → 模型地址;行号列/列头返回 null */
|
|
54
|
-
private toSheetAddr;
|
|
55
|
-
/** 模型地址 → VTable 坐标 */
|
|
56
|
-
private toTableCoord;
|
|
57
|
-
private buildColumns;
|
|
58
|
-
private buildRecords;
|
|
59
|
-
private buildOptions;
|
|
60
|
-
/**
|
|
61
|
-
* 行高只允许在行号列拖拽(Excel 语义)。
|
|
62
|
-
* VTable 无 canResizeRow,且 'header' 不含 rowSeriesNumber body,故包装 _canResizeRow。
|
|
63
|
-
*/
|
|
64
|
-
private restrictRowResizeToSeriesNumber;
|
|
65
|
-
/** 按 Sheet 稀疏行高还原到 VTable(tab 切换重建后保留) */
|
|
66
|
-
private applyStoredRowHeights;
|
|
67
|
-
private bindTableEvents;
|
|
68
|
-
/** 当前 VTable 选区 → 规范化模型区域;无有效 body 选区返回 null */
|
|
69
|
-
private readSelectedModelRange;
|
|
70
|
-
private bindSheetEvents;
|
|
71
|
-
/** 模型格 → 表格 record(显示值;公式格为计算缓存) */
|
|
72
|
-
private pushCellToTable;
|
|
73
|
-
/**
|
|
74
|
-
* 键盘绑定:Cmd/Ctrl+Z undo,Cmd/Ctrl+Shift+Z 与 Ctrl+Y redo。
|
|
75
|
-
* 编辑器打开时(事件来自编辑器 input)不拦截,保留文本编辑自身的撤销行为。
|
|
76
|
-
*/
|
|
77
|
-
private bindKeyboard;
|
|
78
|
-
}
|
|
79
|
-
//#endregion
|
|
80
|
-
export { SheetGrid, SheetGridContextMenuInfo, SheetGridOptions };
|
|
81
|
-
//# sourceMappingURL=sheet-grid.d.ts.map
|
package/dist/grid/sheet-grid.js
DELETED
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
import { cellKey, colIndexToName, createRange } from "../core/address.js";
|
|
2
|
-
import { computeFillTargetRange, generateFill } from "../core/fill.js";
|
|
3
|
-
import { sheetRowSeriesNumberStyle, sheetVTableTheme } from "./vtable-theme.js";
|
|
4
|
-
import { ListTable, register } from "@visactor/vtable";
|
|
5
|
-
import { InputEditor } from "@visactor/vtable-editors";
|
|
6
|
-
//#region src/grid/sheet-grid.ts
|
|
7
|
-
/**
|
|
8
|
-
* VTable 适配层:数据模型完全自持有,ListTable 只做渲染与输入。
|
|
9
|
-
*
|
|
10
|
-
* - 模型 → VTable:records 由 store 行视图桥接;customMergeCell 闭包直读 MergeManager
|
|
11
|
-
* (VTable 逐格动态求值、无缓存,合并变更后 setRecords 重建场景树即生效)
|
|
12
|
-
* - VTable → 模型:change_cell_value 回写 store;selected_cell 经 resolveAnchor 更新选区
|
|
13
|
-
* - 公式:公式格 record 存计算缓存(显示值);进入编辑时编辑器显示公式原文('=f')。
|
|
14
|
-
* 编辑提交期间模型变更(含公式重算派生格)先入待同步队列,提交结束统一回推表格——
|
|
15
|
-
* VTable 自己只更新了被编辑格的 record(还是输入文本),派生格它不知道
|
|
16
|
-
* - 键盘:容器 keydown 绑定 undo/redo(Cmd/Ctrl+Z、Cmd/Ctrl+Shift+Z、Ctrl+Y),
|
|
17
|
-
* 编辑器 input 打开时不拦截;编辑态方向键不换格(moveEditCellOnArrowKeys: false)
|
|
18
|
-
* - 填充柄:excelOptions.fillHandle + mousedown/drag_end → core/fill → setCells
|
|
19
|
-
* - 行列尺寸:列宽仅列头;行高仅行号列(包装 _canResizeRow)。稀疏存 Sheet.rowHeights,
|
|
20
|
-
* RESIZE_ROW_END 同步,重建时还原
|
|
21
|
-
* - 坐标换算:行号列不计入 rowHeaderLevelCount,偏移量在首个表格实例上
|
|
22
|
-
* 用 columnHeaderLevelCount + isSeriesNumber 实测并缓存(见 getOffsets)
|
|
23
|
-
*/
|
|
24
|
-
/** 公式感知编辑器:进入编辑时公式格显示原文(同 Excel),其余格显示当前值 */
|
|
25
|
-
var FormulaAwareInputEditor = class extends InputEditor {
|
|
26
|
-
/** 由 SheetGrid 注入:返回进入编辑时应显示的文本;undefined = 用 VTable 默认值 */
|
|
27
|
-
resolveEditText;
|
|
28
|
-
onStart(context) {
|
|
29
|
-
const text = this.resolveEditText?.(context.col, context.row);
|
|
30
|
-
super.onStart(text === void 0 ? context : {
|
|
31
|
-
...context,
|
|
32
|
-
value: text
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
/** 编辑器按 grid 实例注册(hook 闭包各自 sheet),名称递增防冲突 */
|
|
37
|
-
let editorSeq = 0;
|
|
38
|
-
/** 从 VTable 事件载荷提取 viewport 坐标(兼容 nativeEvent 嵌套) */
|
|
39
|
-
function clientPointFromEvent(event) {
|
|
40
|
-
let current = event;
|
|
41
|
-
for (let i = 0; i < 3 && current && typeof current === "object"; i++) {
|
|
42
|
-
if ("clientX" in current && typeof current.clientX === "number") {
|
|
43
|
-
const { clientX, clientY } = current;
|
|
44
|
-
return {
|
|
45
|
-
x: clientX,
|
|
46
|
-
y: clientY
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
current = "nativeEvent" in current ? current.nativeEvent : null;
|
|
50
|
-
}
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
var SheetGrid = class {
|
|
54
|
-
sheet;
|
|
55
|
-
table;
|
|
56
|
-
container;
|
|
57
|
-
rows;
|
|
58
|
-
cols;
|
|
59
|
-
editorName;
|
|
60
|
-
onContextMenu;
|
|
61
|
-
disposers = [];
|
|
62
|
-
/** 编辑提交期间累积的模型变更(提交结束统一回推表格,覆盖公式派生格) */
|
|
63
|
-
pendingTableSync = null;
|
|
64
|
-
/** 实测坐标偏移(行号列数 / 列头行数),首次使用时测量 */
|
|
65
|
-
offsets;
|
|
66
|
-
/** 填充柄:mousedown 时的源选区(模型坐标) */
|
|
67
|
-
fillSourceRange = null;
|
|
68
|
-
constructor(options) {
|
|
69
|
-
this.sheet = options.sheet;
|
|
70
|
-
this.container = options.container;
|
|
71
|
-
this.rows = options.rows ?? 100;
|
|
72
|
-
this.cols = options.cols ?? 26;
|
|
73
|
-
this.onContextMenu = options.onContextMenu;
|
|
74
|
-
this.editorName = `veltra-sheet-input-${editorSeq++}`;
|
|
75
|
-
const editor = new FormulaAwareInputEditor();
|
|
76
|
-
editor.resolveEditText = (col, row) => {
|
|
77
|
-
const addr = this.toSheetAddr(this.table, col, row);
|
|
78
|
-
if (!addr) return void 0;
|
|
79
|
-
const data = this.sheet.getCellData(this.sheet.merges.resolveAnchor(addr));
|
|
80
|
-
return data?.f ? `=${data.f}` : void 0;
|
|
81
|
-
};
|
|
82
|
-
register.editor(this.editorName, editor);
|
|
83
|
-
this.table = new ListTable(options.container, this.buildOptions());
|
|
84
|
-
this.restrictRowResizeToSeriesNumber();
|
|
85
|
-
this.applyStoredRowHeights();
|
|
86
|
-
this.bindTableEvents();
|
|
87
|
-
this.bindSheetEvents();
|
|
88
|
-
this.bindKeyboard();
|
|
89
|
-
}
|
|
90
|
-
/** 底层 ListTable 实例(调试与测试用) */
|
|
91
|
-
getTable() {
|
|
92
|
-
return this.table;
|
|
93
|
-
}
|
|
94
|
-
/** 全量刷新(合并结构变化、批量数据变更后调用) */
|
|
95
|
-
refresh() {
|
|
96
|
-
this.table.setRecords(this.buildRecords());
|
|
97
|
-
}
|
|
98
|
-
/** 撤销一步(模型命令历史) */
|
|
99
|
-
undo() {
|
|
100
|
-
return this.sheet.undo();
|
|
101
|
-
}
|
|
102
|
-
/** 重做一步(模型命令历史) */
|
|
103
|
-
redo() {
|
|
104
|
-
return this.sheet.redo();
|
|
105
|
-
}
|
|
106
|
-
release() {
|
|
107
|
-
for (const dispose of this.disposers) dispose();
|
|
108
|
-
this.disposers.length = 0;
|
|
109
|
-
this.table.release();
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* 实测偏移:列头行数取 columnHeaderLevelCount;
|
|
113
|
-
* 行号列不被计入 rowHeaderLevelCount,用 isSeriesNumber 逐列探测。
|
|
114
|
-
* 结果缓存(表格实例不变,布局不变)。
|
|
115
|
-
*/
|
|
116
|
-
getOffsets(table) {
|
|
117
|
-
if (!this.offsets) {
|
|
118
|
-
const rowOffset = table.columnHeaderLevelCount;
|
|
119
|
-
let colOffset = 0;
|
|
120
|
-
while (colOffset < table.colCount && table.isSeriesNumber(colOffset, rowOffset)) colOffset++;
|
|
121
|
-
this.offsets = {
|
|
122
|
-
colOffset,
|
|
123
|
-
rowOffset
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
return this.offsets;
|
|
127
|
-
}
|
|
128
|
-
/** VTable 坐标 → 模型地址;行号列/列头返回 null */
|
|
129
|
-
toSheetAddr(table, col, row) {
|
|
130
|
-
const { colOffset, rowOffset } = this.getOffsets(table);
|
|
131
|
-
const addr = {
|
|
132
|
-
row: row - rowOffset,
|
|
133
|
-
col: col - colOffset
|
|
134
|
-
};
|
|
135
|
-
if (addr.row < 0 || addr.col < 0) return null;
|
|
136
|
-
return addr;
|
|
137
|
-
}
|
|
138
|
-
/** 模型地址 → VTable 坐标 */
|
|
139
|
-
toTableCoord(table, addr) {
|
|
140
|
-
const { colOffset, rowOffset } = this.getOffsets(table);
|
|
141
|
-
return {
|
|
142
|
-
col: addr.col + colOffset,
|
|
143
|
-
row: addr.row + rowOffset
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
buildColumns() {
|
|
147
|
-
return Array.from({ length: this.cols }, (_, col) => ({
|
|
148
|
-
field: String(col),
|
|
149
|
-
title: colIndexToName(col)
|
|
150
|
-
}));
|
|
151
|
-
}
|
|
152
|
-
buildRecords() {
|
|
153
|
-
const records = Array.from({ length: this.rows }, () => ({}));
|
|
154
|
-
for (const [addr, data] of this.sheet.store.entries()) if (addr.row < this.rows && addr.col < this.cols && data.v != null) records[addr.row][String(addr.col)] = data.v;
|
|
155
|
-
return records;
|
|
156
|
-
}
|
|
157
|
-
buildOptions() {
|
|
158
|
-
return {
|
|
159
|
-
records: this.buildRecords(),
|
|
160
|
-
columns: this.buildColumns(),
|
|
161
|
-
widthMode: "standard",
|
|
162
|
-
defaultRowHeight: 28,
|
|
163
|
-
resize: {
|
|
164
|
-
columnResizeMode: "header",
|
|
165
|
-
rowResizeMode: "all"
|
|
166
|
-
},
|
|
167
|
-
theme: sheetVTableTheme,
|
|
168
|
-
rowSeriesNumber: {
|
|
169
|
-
width: 46,
|
|
170
|
-
style: sheetRowSeriesNumberStyle
|
|
171
|
-
},
|
|
172
|
-
excelOptions: { fillHandle: true },
|
|
173
|
-
eventOptions: { preventDefaultContextMenu: true },
|
|
174
|
-
editor: this.editorName,
|
|
175
|
-
editCellTrigger: "doubleclick",
|
|
176
|
-
keyboardOptions: {
|
|
177
|
-
moveFocusCellOnTab: true,
|
|
178
|
-
editCellOnEnter: true,
|
|
179
|
-
moveFocusCellOnEnter: true,
|
|
180
|
-
moveEditCellOnArrowKeys: false,
|
|
181
|
-
selectAllOnCtrlA: true
|
|
182
|
-
},
|
|
183
|
-
customMergeCell: (col, row, table) => {
|
|
184
|
-
const addr = this.toSheetAddr(table, col, row);
|
|
185
|
-
if (!addr) return void 0;
|
|
186
|
-
const merge = this.sheet.merges.getMergeAt(addr);
|
|
187
|
-
if (!merge) return void 0;
|
|
188
|
-
const anchorCoord = this.toTableCoord(table, merge.start);
|
|
189
|
-
const recordValue = table.getCellOriginValue(anchorCoord.col, anchorCoord.row);
|
|
190
|
-
return {
|
|
191
|
-
range: {
|
|
192
|
-
start: anchorCoord,
|
|
193
|
-
end: this.toTableCoord(table, merge.end)
|
|
194
|
-
},
|
|
195
|
-
text: recordValue == null ? "" : String(recordValue)
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* 行高只允许在行号列拖拽(Excel 语义)。
|
|
202
|
-
* VTable 无 canResizeRow,且 'header' 不含 rowSeriesNumber body,故包装 _canResizeRow。
|
|
203
|
-
*/
|
|
204
|
-
restrictRowResizeToSeriesNumber() {
|
|
205
|
-
const table = this.table;
|
|
206
|
-
const base = table._canResizeRow.bind(table);
|
|
207
|
-
table._canResizeRow = (col, row) => table.isSeriesNumber(col, row) && base(col, row);
|
|
208
|
-
}
|
|
209
|
-
/** 按 Sheet 稀疏行高还原到 VTable(tab 切换重建后保留) */
|
|
210
|
-
applyStoredRowHeights() {
|
|
211
|
-
for (const [row, height] of this.sheet.getRowHeights()) {
|
|
212
|
-
const tableRow = this.toTableCoord(this.table, {
|
|
213
|
-
row,
|
|
214
|
-
col: 0
|
|
215
|
-
}).row;
|
|
216
|
-
this.table.setRowHeight(tableRow, height);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
bindTableEvents() {
|
|
220
|
-
this.table.on(ListTable.EVENT_TYPE.CHANGE_CELL_VALUE, (args) => {
|
|
221
|
-
const addr = this.toSheetAddr(this.table, args.col, args.row);
|
|
222
|
-
if (addr == null) return;
|
|
223
|
-
this.pendingTableSync = /* @__PURE__ */ new Map([[cellKey(addr), addr]]);
|
|
224
|
-
try {
|
|
225
|
-
this.sheet.setCellValue(addr, args.changedValue ?? null);
|
|
226
|
-
} finally {
|
|
227
|
-
const pending = this.pendingTableSync;
|
|
228
|
-
this.pendingTableSync = null;
|
|
229
|
-
if (pending) for (const pendingAddr of pending.values()) this.pushCellToTable(pendingAddr);
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
this.table.on(ListTable.EVENT_TYPE.SELECTED_CELL, (args) => {
|
|
233
|
-
const addr = this.toSheetAddr(this.table, args.col, args.row);
|
|
234
|
-
if (addr == null) return;
|
|
235
|
-
this.sheet.selectCell(addr);
|
|
236
|
-
});
|
|
237
|
-
this.table.on(ListTable.EVENT_TYPE.DRAG_SELECT_END, () => {
|
|
238
|
-
const range = this.readSelectedModelRange();
|
|
239
|
-
if (!range) return;
|
|
240
|
-
this.sheet.selectRange(range);
|
|
241
|
-
});
|
|
242
|
-
this.table.on(ListTable.EVENT_TYPE.RESIZE_ROW_END, (args) => {
|
|
243
|
-
const addr = this.toSheetAddr(this.table, this.getOffsets(this.table).colOffset, args.row);
|
|
244
|
-
if (!addr) return;
|
|
245
|
-
this.sheet.setRowHeight(addr.row, args.rowHeight);
|
|
246
|
-
});
|
|
247
|
-
this.table.on(ListTable.EVENT_TYPE.MOUSEDOWN_FILL_HANDLE, () => {
|
|
248
|
-
this.fillSourceRange = this.readSelectedModelRange();
|
|
249
|
-
});
|
|
250
|
-
this.table.on(ListTable.EVENT_TYPE.DRAG_FILL_HANDLE_END, (args) => {
|
|
251
|
-
const source = this.fillSourceRange;
|
|
252
|
-
this.fillSourceRange = null;
|
|
253
|
-
const direction = args.direction;
|
|
254
|
-
if (!source || !direction) return;
|
|
255
|
-
const expanded = this.readSelectedModelRange();
|
|
256
|
-
if (!expanded) return;
|
|
257
|
-
const target = computeFillTargetRange(source, direction, expanded);
|
|
258
|
-
if (!target) return;
|
|
259
|
-
const items = generateFill({
|
|
260
|
-
source,
|
|
261
|
-
target,
|
|
262
|
-
direction,
|
|
263
|
-
getCellData: (addr) => this.sheet.getCellData(addr)
|
|
264
|
-
});
|
|
265
|
-
if (items.length === 0) return;
|
|
266
|
-
this.sheet.setCells(items);
|
|
267
|
-
this.sheet.selectRange(createRange(source.start, expanded.end));
|
|
268
|
-
});
|
|
269
|
-
this.table.on(ListTable.EVENT_TYPE.CONTEXTMENU_CELL, (args) => {
|
|
270
|
-
const event = args.event;
|
|
271
|
-
if (event && typeof event === "object" && "preventDefault" in event) event.preventDefault();
|
|
272
|
-
if (!this.onContextMenu) return;
|
|
273
|
-
const point = clientPointFromEvent(event);
|
|
274
|
-
const info = {
|
|
275
|
-
x: point?.x ?? 0,
|
|
276
|
-
y: point?.y ?? 0,
|
|
277
|
-
addr: this.toSheetAddr(this.table, args.col, args.row)
|
|
278
|
-
};
|
|
279
|
-
queueMicrotask(() => this.onContextMenu?.(info));
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
/** 当前 VTable 选区 → 规范化模型区域;无有效 body 选区返回 null */
|
|
283
|
-
readSelectedModelRange() {
|
|
284
|
-
const range = this.table.getSelectedCellRanges()[0];
|
|
285
|
-
if (!range) return null;
|
|
286
|
-
const start = this.toSheetAddr(this.table, range.start.col, range.start.row);
|
|
287
|
-
const end = this.toSheetAddr(this.table, range.end.col, range.end.row);
|
|
288
|
-
if (!start || !end) return null;
|
|
289
|
-
return createRange(start, end);
|
|
290
|
-
}
|
|
291
|
-
bindSheetEvents() {
|
|
292
|
-
this.disposers.push(this.sheet.on("cell-change", ({ addr }) => {
|
|
293
|
-
if (this.pendingTableSync) {
|
|
294
|
-
this.pendingTableSync.set(cellKey(addr), addr);
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
this.pushCellToTable(addr);
|
|
298
|
-
}));
|
|
299
|
-
this.disposers.push(this.sheet.on("merge-change", () => {
|
|
300
|
-
this.refresh();
|
|
301
|
-
}));
|
|
302
|
-
}
|
|
303
|
-
/** 模型格 → 表格 record(显示值;公式格为计算缓存) */
|
|
304
|
-
pushCellToTable(addr) {
|
|
305
|
-
const { col, row } = this.toTableCoord(this.table, addr);
|
|
306
|
-
const value = this.sheet.getDisplayValue(addr);
|
|
307
|
-
this.table.changeCellValue(col, row, value, false, false);
|
|
308
|
-
}
|
|
309
|
-
/**
|
|
310
|
-
* 键盘绑定:Cmd/Ctrl+Z undo,Cmd/Ctrl+Shift+Z 与 Ctrl+Y redo。
|
|
311
|
-
* 编辑器打开时(事件来自编辑器 input)不拦截,保留文本编辑自身的撤销行为。
|
|
312
|
-
*/
|
|
313
|
-
bindKeyboard() {
|
|
314
|
-
const onKeyDown = (event) => {
|
|
315
|
-
if (event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement) return;
|
|
316
|
-
if (!(event.metaKey || event.ctrlKey)) return;
|
|
317
|
-
const key = event.key.toLowerCase();
|
|
318
|
-
if (key === "z" && !event.shiftKey) {
|
|
319
|
-
if (this.undo()) event.preventDefault();
|
|
320
|
-
} else if (key === "z" && event.shiftKey || key === "y" && event.ctrlKey) {
|
|
321
|
-
if (this.redo()) event.preventDefault();
|
|
322
|
-
}
|
|
323
|
-
};
|
|
324
|
-
this.container.addEventListener("keydown", onKeyDown);
|
|
325
|
-
this.disposers.push(() => this.container.removeEventListener("keydown", onKeyDown));
|
|
326
|
-
}
|
|
327
|
-
};
|
|
328
|
-
//#endregion
|
|
329
|
-
export { SheetGrid };
|
|
330
|
-
|
|
331
|
-
//# sourceMappingURL=sheet-grid.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sheet-grid.js","names":[],"sources":["../../src/grid/sheet-grid.ts"],"sourcesContent":["import { ListTable, register } from '@visactor/vtable'\nimport type { ListTableConstructorOptions } from '@visactor/vtable'\nimport { InputEditor } from '@visactor/vtable-editors'\nimport type { EditContext } from '@visactor/vtable-editors'\n\nimport type { CellAddress, CellRange } from '../core/address'\nimport { cellKey, colIndexToName, createRange } from '../core/address'\nimport type { CellValue } from '../core/cell-store'\nimport { computeFillTargetRange, generateFill, type FillDirection } from '../core/fill'\nimport type { Sheet } from '../core/sheet'\nimport {\n SHEET_DEFAULT_ROW_HEIGHT,\n sheetRowSeriesNumberStyle,\n sheetVTableTheme\n} from './vtable-theme'\n\n/**\n * VTable 适配层:数据模型完全自持有,ListTable 只做渲染与输入。\n *\n * - 模型 → VTable:records 由 store 行视图桥接;customMergeCell 闭包直读 MergeManager\n * (VTable 逐格动态求值、无缓存,合并变更后 setRecords 重建场景树即生效)\n * - VTable → 模型:change_cell_value 回写 store;selected_cell 经 resolveAnchor 更新选区\n * - 公式:公式格 record 存计算缓存(显示值);进入编辑时编辑器显示公式原文('=f')。\n * 编辑提交期间模型变更(含公式重算派生格)先入待同步队列,提交结束统一回推表格——\n * VTable 自己只更新了被编辑格的 record(还是输入文本),派生格它不知道\n * - 键盘:容器 keydown 绑定 undo/redo(Cmd/Ctrl+Z、Cmd/Ctrl+Shift+Z、Ctrl+Y),\n * 编辑器 input 打开时不拦截;编辑态方向键不换格(moveEditCellOnArrowKeys: false)\n * - 填充柄:excelOptions.fillHandle + mousedown/drag_end → core/fill → setCells\n * - 行列尺寸:列宽仅列头;行高仅行号列(包装 _canResizeRow)。稀疏存 Sheet.rowHeights,\n * RESIZE_ROW_END 同步,重建时还原\n * - 坐标换算:行号列不计入 rowHeaderLevelCount,偏移量在首个表格实例上\n * 用 columnHeaderLevelCount + isSeriesNumber 实测并缓存(见 getOffsets)\n */\n\n/** 公式感知编辑器:进入编辑时公式格显示原文(同 Excel),其余格显示当前值 */\nclass FormulaAwareInputEditor extends InputEditor {\n /** 由 SheetGrid 注入:返回进入编辑时应显示的文本;undefined = 用 VTable 默认值 */\n resolveEditText?: (col: number, row: number) => string | undefined\n\n override onStart(context: EditContext<string>): void {\n const text = this.resolveEditText?.(context.col, context.row)\n super.onStart(text === undefined ? context : { ...context, value: text })\n }\n}\n\n/** 编辑器按 grid 实例注册(hook 闭包各自 sheet),名称递增防冲突 */\nlet editorSeq = 0\n\n/** 右键菜单回调参数(vue 层弹 UContextmenu;grid 不依赖 desktop) */\nexport interface SheetGridContextMenuInfo {\n x: number\n y: number\n /** body 格地址;行号/列头为 null */\n addr: CellAddress | null\n}\n\n/** 从 VTable 事件载荷提取 viewport 坐标(兼容 nativeEvent 嵌套) */\nfunction clientPointFromEvent(event: unknown): { x: number; y: number } | null {\n let current: unknown = event\n for (let i = 0; i < 3 && current && typeof current === 'object'; i++) {\n if ('clientX' in current && typeof (current as { clientX: unknown }).clientX === 'number') {\n const { clientX, clientY } = current as { clientX: number; clientY: number }\n return { x: clientX, y: clientY }\n }\n current = 'nativeEvent' in current ? (current as { nativeEvent: unknown }).nativeEvent : null\n }\n return null\n}\n\nexport interface SheetGridOptions {\n container: HTMLElement\n sheet: Sheet\n /** 渲染行数,默认 100 */\n rows?: number\n /** 渲染列数,默认 26(A..Z) */\n cols?: number\n /** 单元格右键(已 preventDefault);由 vue 层弹出菜单 */\n onContextMenu?: (info: SheetGridContextMenuInfo) => void\n}\n\nexport class SheetGrid {\n private readonly sheet: Sheet\n private readonly table: ListTable\n private readonly container: HTMLElement\n private readonly rows: number\n private readonly cols: number\n private readonly editorName: string\n private readonly onContextMenu?: (info: SheetGridContextMenuInfo) => void\n private readonly disposers: (() => void)[] = []\n /** 编辑提交期间累积的模型变更(提交结束统一回推表格,覆盖公式派生格) */\n private pendingTableSync: Map<number, CellAddress> | null = null\n /** 实测坐标偏移(行号列数 / 列头行数),首次使用时测量 */\n private offsets?: { colOffset: number; rowOffset: number }\n /** 填充柄:mousedown 时的源选区(模型坐标) */\n private fillSourceRange: CellRange | null = null\n\n constructor(options: SheetGridOptions) {\n this.sheet = options.sheet\n this.container = options.container\n this.rows = options.rows ?? 100\n this.cols = options.cols ?? 26\n this.onContextMenu = options.onContextMenu\n\n // 每个 grid 实例注册自己的编辑器(hook 闭包本实例的 sheet 与坐标换算)\n this.editorName = `veltra-sheet-input-${editorSeq++}`\n const editor = new FormulaAwareInputEditor()\n editor.resolveEditText = (col, row) => {\n const addr = this.toSheetAddr(this.table, col, row)\n if (!addr) return undefined\n const data = this.sheet.getCellData(this.sheet.merges.resolveAnchor(addr))\n return data?.f ? `=${data.f}` : undefined\n }\n register.editor(this.editorName, editor)\n\n this.table = new ListTable(options.container, this.buildOptions())\n this.restrictRowResizeToSeriesNumber()\n this.applyStoredRowHeights()\n this.bindTableEvents()\n this.bindSheetEvents()\n this.bindKeyboard()\n }\n\n /** 底层 ListTable 实例(调试与测试用) */\n getTable(): ListTable {\n return this.table\n }\n\n /** 全量刷新(合并结构变化、批量数据变更后调用) */\n refresh(): void {\n this.table.setRecords(this.buildRecords())\n }\n\n /** 撤销一步(模型命令历史) */\n undo(): boolean {\n return this.sheet.undo()\n }\n\n /** 重做一步(模型命令历史) */\n redo(): boolean {\n return this.sheet.redo()\n }\n\n release(): void {\n for (const dispose of this.disposers) dispose()\n this.disposers.length = 0\n this.table.release()\n }\n\n // ─── 坐标换算 ─────────────────────────────────────────────\n\n /**\n * 实测偏移:列头行数取 columnHeaderLevelCount;\n * 行号列不被计入 rowHeaderLevelCount,用 isSeriesNumber 逐列探测。\n * 结果缓存(表格实例不变,布局不变)。\n */\n private getOffsets(table: ListTable): { colOffset: number; rowOffset: number } {\n if (!this.offsets) {\n const rowOffset = table.columnHeaderLevelCount\n let colOffset = 0\n while (colOffset < table.colCount && table.isSeriesNumber(colOffset, rowOffset)) colOffset++\n this.offsets = { colOffset, rowOffset }\n }\n return this.offsets\n }\n\n /** VTable 坐标 → 模型地址;行号列/列头返回 null */\n private toSheetAddr(table: ListTable, col: number, row: number): CellAddress | null {\n const { colOffset, rowOffset } = this.getOffsets(table)\n const addr = { row: row - rowOffset, col: col - colOffset }\n if (addr.row < 0 || addr.col < 0) return null\n return addr\n }\n\n /** 模型地址 → VTable 坐标 */\n private toTableCoord(table: ListTable, addr: CellAddress): { col: number; row: number } {\n const { colOffset, rowOffset } = this.getOffsets(table)\n return { col: addr.col + colOffset, row: addr.row + rowOffset }\n }\n\n // ─── 模型 → VTable ────────────────────────────────────────\n\n private buildColumns() {\n return Array.from({ length: this.cols }, (_, col) => ({\n field: String(col),\n title: colIndexToName(col)\n }))\n }\n\n private buildRecords(): Record<string, CellValue>[] {\n const records: Record<string, CellValue>[] = Array.from({ length: this.rows }, () => ({}))\n for (const [addr, data] of this.sheet.store.entries()) {\n if (addr.row < this.rows && addr.col < this.cols && data.v != null) {\n records[addr.row]![String(addr.col)] = data.v\n }\n }\n return records\n }\n\n private buildOptions(): ListTableConstructorOptions {\n return {\n records: this.buildRecords(),\n columns: this.buildColumns(),\n widthMode: 'standard',\n defaultRowHeight: SHEET_DEFAULT_ROW_HEIGHT,\n // 列宽只在列头(A/B/C…)。行高:VTable rowResizeMode:'header' 以 isHeader()\n // 判定,而行号列 body 格不是 header——设 'header' 会禁用行号列调行高。\n // 因此 row 用 'all',构造后限制到行号列(见 restrictRowResizeToSeriesNumber)。\n resize: { columnResizeMode: 'header', rowResizeMode: 'all' },\n theme: sheetVTableTheme,\n rowSeriesNumber: { width: 46, style: sheetRowSeriesNumberStyle },\n excelOptions: { fillHandle: true },\n // 禁止浏览器默认右键菜单,改由 CONTEXTMENU_CELL → UContextmenu\n eventOptions: { preventDefaultContextMenu: true },\n editor: this.editorName,\n editCellTrigger: 'doubleclick',\n keyboardOptions: {\n moveFocusCellOnTab: true,\n editCellOnEnter: true,\n moveFocusCellOnEnter: true,\n // 编辑中方向键只移输入光标;未编辑时选区导航不受影响\n moveEditCellOnArrowKeys: false,\n selectAllOnCtrlA: true\n },\n customMergeCell: (col, row, table) => {\n const addr = this.toSheetAddr(table as ListTable, col, row)\n if (!addr) return undefined\n const merge = this.sheet.merges.getMergeAt(addr)\n if (!merge) return undefined\n const anchorCoord = this.toTableCoord(table as ListTable, merge.start)\n const recordValue = (table as ListTable).getCellOriginValue(\n anchorCoord.col,\n anchorCoord.row\n )\n return {\n range: { start: anchorCoord, end: this.toTableCoord(table as ListTable, merge.end) },\n // 关键 1:必须携带 text。VTable 的 getCellRange 仅在 text/customLayout/\n // customRender 有效时才认这个自定义合并——没有 text 时选区与编辑不会\n // 扩展为整个合并区域,且合并格渲染为空。\n // 关键 2:text 必须读 VTable records 而非模型。编辑提交的顺序是\n // 先更新 record → 重绘 → 最后才发 change_cell_value 回写模型;\n // 若此时读模型,拿到的还是回写前的旧值(合并格显示旧文本)。\n text: recordValue == null ? '' : String(recordValue)\n }\n }\n }\n }\n\n /**\n * 行高只允许在行号列拖拽(Excel 语义)。\n * VTable 无 canResizeRow,且 'header' 不含 rowSeriesNumber body,故包装 _canResizeRow。\n */\n private restrictRowResizeToSeriesNumber(): void {\n const table = this.table\n const base = table._canResizeRow.bind(table)\n table._canResizeRow = (col, row) => table.isSeriesNumber(col, row) && base(col, row)\n }\n\n /** 按 Sheet 稀疏行高还原到 VTable(tab 切换重建后保留) */\n private applyStoredRowHeights(): void {\n for (const [row, height] of this.sheet.getRowHeights()) {\n const tableRow = this.toTableCoord(this.table, { row, col: 0 }).row\n this.table.setRowHeight(tableRow, height)\n }\n }\n\n // ─── 事件桥接 ─────────────────────────────────────────────\n\n private bindTableEvents(): void {\n this.table.on(ListTable.EVENT_TYPE.CHANGE_CELL_VALUE, (args) => {\n const addr = this.toSheetAddr(this.table, args.col, args.row)\n if (addr == null) return\n // 编辑提交期间模型变更(含公式重算派生格)先入队列,提交结束统一回推。\n // 被编辑格自身也入队:VTable 已把输入文本写进 record,公式格需回推计算值\n this.pendingTableSync = new Map([[cellKey(addr), addr]])\n try {\n this.sheet.setCellValue(addr, args.changedValue ?? null)\n } finally {\n const pending = this.pendingTableSync\n this.pendingTableSync = null\n if (pending) {\n for (const pendingAddr of pending.values()) this.pushCellToTable(pendingAddr)\n }\n }\n })\n\n this.table.on(ListTable.EVENT_TYPE.SELECTED_CELL, (args) => {\n const addr = this.toSheetAddr(this.table, args.col, args.row)\n if (addr == null) return\n this.sheet.selectCell(addr)\n })\n\n // 拖选结束 → 选区同步为区域(合并等区域操作的前提)\n this.table.on(ListTable.EVENT_TYPE.DRAG_SELECT_END, () => {\n const range = this.readSelectedModelRange()\n if (!range) return\n this.sheet.selectRange(range)\n })\n\n // 行高拖拽结束 → 写入模型稀疏表(不进 undo)\n this.table.on(ListTable.EVENT_TYPE.RESIZE_ROW_END, (args) => {\n const addr = this.toSheetAddr(this.table, this.getOffsets(this.table).colOffset, args.row)\n if (!addr) return\n this.sheet.setRowHeight(addr.row, args.rowHeight)\n })\n\n // 填充柄:记下源选区\n this.table.on(ListTable.EVENT_TYPE.MOUSEDOWN_FILL_HANDLE, () => {\n this.fillSourceRange = this.readSelectedModelRange()\n })\n\n // 填充柄拖拽结束 → generateFill → setCells\n this.table.on(ListTable.EVENT_TYPE.DRAG_FILL_HANDLE_END, (args) => {\n const source = this.fillSourceRange\n this.fillSourceRange = null\n const direction = args.direction as FillDirection | undefined\n if (!source || !direction) return\n const expanded = this.readSelectedModelRange()\n if (!expanded) return\n const target = computeFillTargetRange(source, direction, expanded)\n if (!target) return\n const items = generateFill({\n source,\n target,\n direction,\n getCellData: (addr) => this.sheet.getCellData(addr)\n })\n if (items.length === 0) return\n this.sheet.setCells(items)\n this.sheet.selectRange(createRange(source.start, expanded.end))\n })\n\n // 右键 → vue 层 UContextmenu(grid 不依赖 desktop)\n // VTable 在 rightdown 上派发 CONTEXTMENU_CELL(非原生 contextmenu)\n this.table.on(ListTable.EVENT_TYPE.CONTEXTMENU_CELL, (args) => {\n const event = args.event\n if (event && typeof event === 'object' && 'preventDefault' in event) {\n ;(event as { preventDefault: () => void }).preventDefault()\n }\n if (!this.onContextMenu) return\n const point = clientPointFromEvent(event)\n // 延后一帧:避开 VTable rightdown 同步阶段,保证菜单挂载后不被同轮指针事件干扰\n const info: SheetGridContextMenuInfo = {\n x: point?.x ?? 0,\n y: point?.y ?? 0,\n addr: this.toSheetAddr(this.table, args.col, args.row)\n }\n queueMicrotask(() => this.onContextMenu?.(info))\n })\n }\n\n /** 当前 VTable 选区 → 规范化模型区域;无有效 body 选区返回 null */\n private readSelectedModelRange(): CellRange | null {\n const range = this.table.getSelectedCellRanges()[0]\n if (!range) return null\n const start = this.toSheetAddr(this.table, range.start.col, range.start.row)\n const end = this.toSheetAddr(this.table, range.end.col, range.end.row)\n if (!start || !end) return null\n return createRange(start, end)\n }\n\n private bindSheetEvents(): void {\n this.disposers.push(\n this.sheet.on('cell-change', ({ addr }) => {\n if (this.pendingTableSync) {\n this.pendingTableSync.set(cellKey(addr), addr)\n return\n }\n this.pushCellToTable(addr)\n })\n )\n\n this.disposers.push(\n this.sheet.on('merge-change', () => {\n this.refresh()\n })\n )\n }\n\n /** 模型格 → 表格 record(显示值;公式格为计算缓存) */\n private pushCellToTable(addr: CellAddress): void {\n const { col, row } = this.toTableCoord(this.table, addr)\n const value = this.sheet.getDisplayValue(addr)\n this.table.changeCellValue(col, row, value as string | number | null, false, false)\n }\n\n /**\n * 键盘绑定:Cmd/Ctrl+Z undo,Cmd/Ctrl+Shift+Z 与 Ctrl+Y redo。\n * 编辑器打开时(事件来自编辑器 input)不拦截,保留文本编辑自身的撤销行为。\n */\n private bindKeyboard(): void {\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement) {\n return\n }\n const mod = event.metaKey || event.ctrlKey\n if (!mod) return\n const key = event.key.toLowerCase()\n if (key === 'z' && !event.shiftKey) {\n if (this.undo()) event.preventDefault()\n } else if ((key === 'z' && event.shiftKey) || (key === 'y' && event.ctrlKey)) {\n if (this.redo()) event.preventDefault()\n }\n }\n this.container.addEventListener('keydown', onKeyDown)\n this.disposers.push(() => this.container.removeEventListener('keydown', onKeyDown))\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAmCA,IAAM,0BAAN,cAAsC,YAAY;;CAEhD;CAEA,QAAiB,SAAoC;EACnD,MAAM,OAAO,KAAK,kBAAkB,QAAQ,KAAK,QAAQ,GAAG;EAC5D,MAAM,QAAQ,SAAS,KAAA,IAAY,UAAU;GAAE,GAAG;GAAS,OAAO;EAAK,CAAC;CAC1E;AACF;;AAGA,IAAI,YAAY;;AAWhB,SAAS,qBAAqB,OAAiD;CAC7E,IAAI,UAAmB;CACvB,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,WAAW,OAAO,YAAY,UAAU,KAAK;EACpE,IAAI,aAAa,WAAW,OAAQ,QAAiC,YAAY,UAAU;GACzF,MAAM,EAAE,SAAS,YAAY;GAC7B,OAAO;IAAE,GAAG;IAAS,GAAG;GAAQ;EAClC;EACA,UAAU,iBAAiB,UAAW,QAAqC,cAAc;CAC3F;CACA,OAAO;AACT;AAaA,IAAa,YAAb,MAAuB;CACrB;CACA;CACA;CACA;CACA;CACA;CACA;CACA,YAA6C,CAAC;;CAE9C,mBAA4D;;CAE5D;;CAEA,kBAA4C;CAE5C,YAAY,SAA2B;EACrC,KAAK,QAAQ,QAAQ;EACrB,KAAK,YAAY,QAAQ;EACzB,KAAK,OAAO,QAAQ,QAAQ;EAC5B,KAAK,OAAO,QAAQ,QAAQ;EAC5B,KAAK,gBAAgB,QAAQ;EAG7B,KAAK,aAAa,sBAAsB;EACxC,MAAM,SAAS,IAAI,wBAAwB;EAC3C,OAAO,mBAAmB,KAAK,QAAQ;GACrC,MAAM,OAAO,KAAK,YAAY,KAAK,OAAO,KAAK,GAAG;GAClD,IAAI,CAAC,MAAM,OAAO,KAAA;GAClB,MAAM,OAAO,KAAK,MAAM,YAAY,KAAK,MAAM,OAAO,cAAc,IAAI,CAAC;GACzE,OAAO,MAAM,IAAI,IAAI,KAAK,MAAM,KAAA;EAClC;EACA,SAAS,OAAO,KAAK,YAAY,MAAM;EAEvC,KAAK,QAAQ,IAAI,UAAU,QAAQ,WAAW,KAAK,aAAa,CAAC;EACjE,KAAK,gCAAgC;EACrC,KAAK,sBAAsB;EAC3B,KAAK,gBAAgB;EACrB,KAAK,gBAAgB;EACrB,KAAK,aAAa;CACpB;;CAGA,WAAsB;EACpB,OAAO,KAAK;CACd;;CAGA,UAAgB;EACd,KAAK,MAAM,WAAW,KAAK,aAAa,CAAC;CAC3C;;CAGA,OAAgB;EACd,OAAO,KAAK,MAAM,KAAK;CACzB;;CAGA,OAAgB;EACd,OAAO,KAAK,MAAM,KAAK;CACzB;CAEA,UAAgB;EACd,KAAK,MAAM,WAAW,KAAK,WAAW,QAAQ;EAC9C,KAAK,UAAU,SAAS;EACxB,KAAK,MAAM,QAAQ;CACrB;;;;;;CASA,WAAmB,OAA4D;EAC7E,IAAI,CAAC,KAAK,SAAS;GACjB,MAAM,YAAY,MAAM;GACxB,IAAI,YAAY;GAChB,OAAO,YAAY,MAAM,YAAY,MAAM,eAAe,WAAW,SAAS,GAAG;GACjF,KAAK,UAAU;IAAE;IAAW;GAAU;EACxC;EACA,OAAO,KAAK;CACd;;CAGA,YAAoB,OAAkB,KAAa,KAAiC;EAClF,MAAM,EAAE,WAAW,cAAc,KAAK,WAAW,KAAK;EACtD,MAAM,OAAO;GAAE,KAAK,MAAM;GAAW,KAAK,MAAM;EAAU;EAC1D,IAAI,KAAK,MAAM,KAAK,KAAK,MAAM,GAAG,OAAO;EACzC,OAAO;CACT;;CAGA,aAAqB,OAAkB,MAAiD;EACtF,MAAM,EAAE,WAAW,cAAc,KAAK,WAAW,KAAK;EACtD,OAAO;GAAE,KAAK,KAAK,MAAM;GAAW,KAAK,KAAK,MAAM;EAAU;CAChE;CAIA,eAAuB;EACrB,OAAO,MAAM,KAAK,EAAE,QAAQ,KAAK,KAAK,IAAI,GAAG,SAAS;GACpD,OAAO,OAAO,GAAG;GACjB,OAAO,eAAe,GAAG;EAC3B,EAAE;CACJ;CAEA,eAAoD;EAClD,MAAM,UAAuC,MAAM,KAAK,EAAE,QAAQ,KAAK,KAAK,UAAU,CAAC,EAAE;EACzF,KAAK,MAAM,CAAC,MAAM,SAAS,KAAK,MAAM,MAAM,QAAQ,GAClD,IAAI,KAAK,MAAM,KAAK,QAAQ,KAAK,MAAM,KAAK,QAAQ,KAAK,KAAK,MAC5D,QAAQ,KAAK,IAAI,CAAE,OAAO,KAAK,GAAG,KAAK,KAAK;EAGhD,OAAO;CACT;CAEA,eAAoD;EAClD,OAAO;GACL,SAAS,KAAK,aAAa;GAC3B,SAAS,KAAK,aAAa;GAC3B,WAAW;GACX,kBAAA;GAIA,QAAQ;IAAE,kBAAkB;IAAU,eAAe;GAAM;GAC3D,OAAO;GACP,iBAAiB;IAAE,OAAO;IAAI,OAAO;GAA0B;GAC/D,cAAc,EAAE,YAAY,KAAK;GAEjC,cAAc,EAAE,2BAA2B,KAAK;GAChD,QAAQ,KAAK;GACb,iBAAiB;GACjB,iBAAiB;IACf,oBAAoB;IACpB,iBAAiB;IACjB,sBAAsB;IAEtB,yBAAyB;IACzB,kBAAkB;GACpB;GACA,kBAAkB,KAAK,KAAK,UAAU;IACpC,MAAM,OAAO,KAAK,YAAY,OAAoB,KAAK,GAAG;IAC1D,IAAI,CAAC,MAAM,OAAO,KAAA;IAClB,MAAM,QAAQ,KAAK,MAAM,OAAO,WAAW,IAAI;IAC/C,IAAI,CAAC,OAAO,OAAO,KAAA;IACnB,MAAM,cAAc,KAAK,aAAa,OAAoB,MAAM,KAAK;IACrE,MAAM,cAAe,MAAoB,mBACvC,YAAY,KACZ,YAAY,GACd;IACA,OAAO;KACL,OAAO;MAAE,OAAO;MAAa,KAAK,KAAK,aAAa,OAAoB,MAAM,GAAG;KAAE;KAOnF,MAAM,eAAe,OAAO,KAAK,OAAO,WAAW;IACrD;GACF;EACF;CACF;;;;;CAMA,kCAAgD;EAC9C,MAAM,QAAQ,KAAK;EACnB,MAAM,OAAO,MAAM,cAAc,KAAK,KAAK;EAC3C,MAAM,iBAAiB,KAAK,QAAQ,MAAM,eAAe,KAAK,GAAG,KAAK,KAAK,KAAK,GAAG;CACrF;;CAGA,wBAAsC;EACpC,KAAK,MAAM,CAAC,KAAK,WAAW,KAAK,MAAM,cAAc,GAAG;GACtD,MAAM,WAAW,KAAK,aAAa,KAAK,OAAO;IAAE;IAAK,KAAK;GAAE,CAAC,CAAC,CAAC;GAChE,KAAK,MAAM,aAAa,UAAU,MAAM;EAC1C;CACF;CAIA,kBAAgC;EAC9B,KAAK,MAAM,GAAG,UAAU,WAAW,oBAAoB,SAAS;GAC9D,MAAM,OAAO,KAAK,YAAY,KAAK,OAAO,KAAK,KAAK,KAAK,GAAG;GAC5D,IAAI,QAAQ,MAAM;GAGlB,KAAK,mCAAmB,IAAI,IAAI,CAAC,CAAC,QAAQ,IAAI,GAAG,IAAI,CAAC,CAAC;GACvD,IAAI;IACF,KAAK,MAAM,aAAa,MAAM,KAAK,gBAAgB,IAAI;GACzD,UAAU;IACR,MAAM,UAAU,KAAK;IACrB,KAAK,mBAAmB;IACxB,IAAI,SACF,KAAK,MAAM,eAAe,QAAQ,OAAO,GAAG,KAAK,gBAAgB,WAAW;GAEhF;EACF,CAAC;EAED,KAAK,MAAM,GAAG,UAAU,WAAW,gBAAgB,SAAS;GAC1D,MAAM,OAAO,KAAK,YAAY,KAAK,OAAO,KAAK,KAAK,KAAK,GAAG;GAC5D,IAAI,QAAQ,MAAM;GAClB,KAAK,MAAM,WAAW,IAAI;EAC5B,CAAC;EAGD,KAAK,MAAM,GAAG,UAAU,WAAW,uBAAuB;GACxD,MAAM,QAAQ,KAAK,uBAAuB;GAC1C,IAAI,CAAC,OAAO;GACZ,KAAK,MAAM,YAAY,KAAK;EAC9B,CAAC;EAGD,KAAK,MAAM,GAAG,UAAU,WAAW,iBAAiB,SAAS;GAC3D,MAAM,OAAO,KAAK,YAAY,KAAK,OAAO,KAAK,WAAW,KAAK,KAAK,CAAC,CAAC,WAAW,KAAK,GAAG;GACzF,IAAI,CAAC,MAAM;GACX,KAAK,MAAM,aAAa,KAAK,KAAK,KAAK,SAAS;EAClD,CAAC;EAGD,KAAK,MAAM,GAAG,UAAU,WAAW,6BAA6B;GAC9D,KAAK,kBAAkB,KAAK,uBAAuB;EACrD,CAAC;EAGD,KAAK,MAAM,GAAG,UAAU,WAAW,uBAAuB,SAAS;GACjE,MAAM,SAAS,KAAK;GACpB,KAAK,kBAAkB;GACvB,MAAM,YAAY,KAAK;GACvB,IAAI,CAAC,UAAU,CAAC,WAAW;GAC3B,MAAM,WAAW,KAAK,uBAAuB;GAC7C,IAAI,CAAC,UAAU;GACf,MAAM,SAAS,uBAAuB,QAAQ,WAAW,QAAQ;GACjE,IAAI,CAAC,QAAQ;GACb,MAAM,QAAQ,aAAa;IACzB;IACA;IACA;IACA,cAAc,SAAS,KAAK,MAAM,YAAY,IAAI;GACpD,CAAC;GACD,IAAI,MAAM,WAAW,GAAG;GACxB,KAAK,MAAM,SAAS,KAAK;GACzB,KAAK,MAAM,YAAY,YAAY,OAAO,OAAO,SAAS,GAAG,CAAC;EAChE,CAAC;EAID,KAAK,MAAM,GAAG,UAAU,WAAW,mBAAmB,SAAS;GAC7D,MAAM,QAAQ,KAAK;GACnB,IAAI,SAAS,OAAO,UAAU,YAAY,oBAAoB,OAC3D,MAA0C,eAAe;GAE5D,IAAI,CAAC,KAAK,eAAe;GACzB,MAAM,QAAQ,qBAAqB,KAAK;GAExC,MAAM,OAAiC;IACrC,GAAG,OAAO,KAAK;IACf,GAAG,OAAO,KAAK;IACf,MAAM,KAAK,YAAY,KAAK,OAAO,KAAK,KAAK,KAAK,GAAG;GACvD;GACA,qBAAqB,KAAK,gBAAgB,IAAI,CAAC;EACjD,CAAC;CACH;;CAGA,yBAAmD;EACjD,MAAM,QAAQ,KAAK,MAAM,sBAAsB,CAAC,CAAC;EACjD,IAAI,CAAC,OAAO,OAAO;EACnB,MAAM,QAAQ,KAAK,YAAY,KAAK,OAAO,MAAM,MAAM,KAAK,MAAM,MAAM,GAAG;EAC3E,MAAM,MAAM,KAAK,YAAY,KAAK,OAAO,MAAM,IAAI,KAAK,MAAM,IAAI,GAAG;EACrE,IAAI,CAAC,SAAS,CAAC,KAAK,OAAO;EAC3B,OAAO,YAAY,OAAO,GAAG;CAC/B;CAEA,kBAAgC;EAC9B,KAAK,UAAU,KACb,KAAK,MAAM,GAAG,gBAAgB,EAAE,WAAW;GACzC,IAAI,KAAK,kBAAkB;IACzB,KAAK,iBAAiB,IAAI,QAAQ,IAAI,GAAG,IAAI;IAC7C;GACF;GACA,KAAK,gBAAgB,IAAI;EAC3B,CAAC,CACH;EAEA,KAAK,UAAU,KACb,KAAK,MAAM,GAAG,sBAAsB;GAClC,KAAK,QAAQ;EACf,CAAC,CACH;CACF;;CAGA,gBAAwB,MAAyB;EAC/C,MAAM,EAAE,KAAK,QAAQ,KAAK,aAAa,KAAK,OAAO,IAAI;EACvD,MAAM,QAAQ,KAAK,MAAM,gBAAgB,IAAI;EAC7C,KAAK,MAAM,gBAAgB,KAAK,KAAK,OAAiC,OAAO,KAAK;CACpF;;;;;CAMA,eAA6B;EAC3B,MAAM,aAAa,UAA+B;GAChD,IAAI,MAAM,kBAAkB,oBAAoB,MAAM,kBAAkB,qBACtE;GAGF,IAAI,EADQ,MAAM,WAAW,MAAM,UACzB;GACV,MAAM,MAAM,MAAM,IAAI,YAAY;GAClC,IAAI,QAAQ,OAAO,CAAC,MAAM;QACpB,KAAK,KAAK,GAAG,MAAM,eAAe;GAAA,OACjC,IAAK,QAAQ,OAAO,MAAM,YAAc,QAAQ,OAAO,MAAM;QAC9D,KAAK,KAAK,GAAG,MAAM,eAAe;GAAA;EAE1C;EACA,KAAK,UAAU,iBAAiB,WAAW,SAAS;EACpD,KAAK,UAAU,WAAW,KAAK,UAAU,oBAAoB,WAAW,SAAS,CAAC;CACpF;AACF"}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { themes } from "@visactor/vtable";
|
|
2
|
-
//#region src/grid/vtable-theme.ts
|
|
3
|
-
/** 行号 / 列头浅底(canvas 主题无法读 CSS 变量,固定色贴近 Excel) */
|
|
4
|
-
const CHROME_BG = "#F5F5F5";
|
|
5
|
-
/** body 纯白,覆盖 DEFAULT 斑马底色 */
|
|
6
|
-
const BODY_BG = "#FFF";
|
|
7
|
-
/** 网格线 / 外框:浅灰(勿用 DEFAULTBORDERCOLOR #000) */
|
|
8
|
-
const GRID_BORDER = "#E1E4E8";
|
|
9
|
-
/** 选区边框:清晰蓝(覆盖 DEFAULT 的 #0000ff) */
|
|
10
|
-
const SELECTION_BORDER = "#2170E7";
|
|
11
|
-
/** 选区填充 */
|
|
12
|
-
const SELECTION_BG = "rgba(33, 112, 231, 0.12)";
|
|
13
|
-
/**
|
|
14
|
-
* 单元格内边距 [上, 右, 下, 左]。
|
|
15
|
-
* VTable DEFAULT 为 `[10, 16, 10, 16]`,配合 `defaultRowHeight: 28` 会挤占文字区;
|
|
16
|
-
* 收紧到贴近 Excel 的密度(仍留少量呼吸空间)。
|
|
17
|
-
*/
|
|
18
|
-
const SHEET_CELL_PADDING = [
|
|
19
|
-
2,
|
|
20
|
-
6,
|
|
21
|
-
2,
|
|
22
|
-
6
|
|
23
|
-
];
|
|
24
|
-
/**
|
|
25
|
-
* Sheet 默认 VTable 主题。
|
|
26
|
-
*
|
|
27
|
-
* 必须基于 `themes.DEFAULT.extends`:传入裸对象时 VTable 不会继承 DEFAULT,
|
|
28
|
-
* 缺省 `borderColor` 会回落到内部 `DEFAULTBORDERCOLOR = '#000'`,出现刺眼黑线。
|
|
29
|
-
*/
|
|
30
|
-
const sheetVTableTheme = themes.DEFAULT.extends({
|
|
31
|
-
underlayBackgroundColor: BODY_BG,
|
|
32
|
-
defaultStyle: {
|
|
33
|
-
bgColor: CHROME_BG,
|
|
34
|
-
borderColor: GRID_BORDER,
|
|
35
|
-
padding: [...SHEET_CELL_PADDING],
|
|
36
|
-
textOverflow: "clip"
|
|
37
|
-
},
|
|
38
|
-
headerStyle: {
|
|
39
|
-
bgColor: CHROME_BG,
|
|
40
|
-
borderColor: GRID_BORDER,
|
|
41
|
-
textOverflow: "clip"
|
|
42
|
-
},
|
|
43
|
-
cornerHeaderStyle: {
|
|
44
|
-
bgColor: CHROME_BG,
|
|
45
|
-
borderColor: GRID_BORDER,
|
|
46
|
-
textOverflow: "clip"
|
|
47
|
-
},
|
|
48
|
-
rowHeaderStyle: {
|
|
49
|
-
bgColor: CHROME_BG,
|
|
50
|
-
borderColor: GRID_BORDER,
|
|
51
|
-
textOverflow: "clip"
|
|
52
|
-
},
|
|
53
|
-
bodyStyle: {
|
|
54
|
-
bgColor: BODY_BG,
|
|
55
|
-
borderColor: GRID_BORDER,
|
|
56
|
-
textOverflow: "clip"
|
|
57
|
-
},
|
|
58
|
-
frameStyle: {
|
|
59
|
-
borderColor: GRID_BORDER,
|
|
60
|
-
borderLineWidth: 1,
|
|
61
|
-
shadowBlur: 0,
|
|
62
|
-
shadowColor: "transparent"
|
|
63
|
-
},
|
|
64
|
-
selectionStyle: {
|
|
65
|
-
cellBgColor: SELECTION_BG,
|
|
66
|
-
cellBorderColor: SELECTION_BORDER,
|
|
67
|
-
cellBorderLineWidth: 2
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
/** 行号列默认样式(与主题 chrome 对齐) */
|
|
71
|
-
const sheetRowSeriesNumberStyle = {
|
|
72
|
-
bgColor: CHROME_BG,
|
|
73
|
-
borderColor: GRID_BORDER,
|
|
74
|
-
padding: [...SHEET_CELL_PADDING],
|
|
75
|
-
textOverflow: "clip"
|
|
76
|
-
};
|
|
77
|
-
//#endregion
|
|
78
|
-
export { SHEET_CELL_PADDING, sheetRowSeriesNumberStyle, sheetVTableTheme };
|
|
79
|
-
|
|
80
|
-
//# sourceMappingURL=vtable-theme.js.map
|