@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.
Files changed (211) hide show
  1. package/dist/index.d.ts +4 -26
  2. package/dist/index.js +3 -23
  3. package/dist/tools/builtin.js +279 -8
  4. package/dist/tools/context.d.ts +54 -11
  5. package/dist/tools/context.js +28 -5
  6. package/dist/tools/download.js +68 -0
  7. package/dist/tools/export.worker.d.ts +16 -0
  8. package/dist/tools/export.worker.js +29 -0
  9. package/dist/tools/registry.d.ts +7 -4
  10. package/dist/tools/registry.js +1 -3
  11. package/dist/types/index.d.ts +1 -0
  12. package/dist/types/sheet.d.ts +6 -5
  13. package/dist/vue/formula-bar.js +393 -0
  14. package/dist/vue/formula-suggest-list.js +66 -0
  15. package/dist/vue/import-file.js +140 -0
  16. package/dist/vue/insert-count-menu-item.js +68 -0
  17. package/dist/vue/insert-image.js +79 -0
  18. package/dist/vue/popup-helpers.js +73 -0
  19. package/dist/vue/popups/border-popup.js +75 -0
  20. package/dist/vue/popups/border-preset-glyph.js +106 -0
  21. package/dist/vue/popups/export-popup.js +51 -0
  22. package/dist/vue/popups/fill-color-popup.js +37 -0
  23. package/dist/vue/popups/find-popup.js +113 -0
  24. package/dist/vue/popups/font-color-popup.js +37 -0
  25. package/dist/vue/popups/font-size-popup.js +63 -0
  26. package/dist/vue/popups/import.worker.d.ts +21 -0
  27. package/dist/vue/popups/import.worker.js +41 -0
  28. package/dist/vue/popups/insert-image-popup.js +38 -0
  29. package/dist/vue/sheet-context-menu.js +200 -0
  30. package/dist/vue/sheet-tabs.js +162 -0
  31. package/dist/vue/sheet-toolbar.js +106 -0
  32. package/dist/vue/sheet.js +144 -164
  33. package/dist/vue/style.d.ts +11 -1
  34. package/dist/vue/style.js +10 -0
  35. package/dist/vue/style2.css +564 -3
  36. package/dist/vue/use-find-replace.js +161 -0
  37. package/dist/vue/use-formula-ref-select.js +37 -0
  38. package/dist/vue/use-formula-suggest.js +126 -0
  39. package/dist/vue/use-sheet-grid.js +180 -0
  40. package/dist/vue/use-sheet-state.js +122 -0
  41. package/dist/vue/use-sheet-tabs-bar.js +90 -0
  42. package/dist/vue/use-tool-groups.js +42 -0
  43. package/dist/vue/use-tool-popup.js +123 -0
  44. package/dist/vue/use-toolbar-scroll.js +72 -0
  45. package/package.json +12 -7
  46. package/src/env.d.ts +11 -0
  47. package/src/index.ts +203 -14
  48. package/src/tools/__test__/builtin.test.ts +208 -66
  49. package/src/tools/__test__/context.test.ts +62 -2
  50. package/src/tools/builtin.ts +350 -6
  51. package/src/tools/context.ts +89 -11
  52. package/src/tools/download.ts +82 -0
  53. package/src/tools/export.worker.ts +61 -0
  54. package/src/tools/registry.ts +16 -1
  55. package/src/types/index.ts +6 -0
  56. package/src/types/sheet.ts +5 -3
  57. package/src/vue/__test__/formula-bar.test.ts +455 -0
  58. package/src/vue/__test__/import-file.test.ts +183 -0
  59. package/src/vue/__test__/insert-count-menu-item.test.ts +123 -0
  60. package/src/vue/__test__/insert-image-popup.test.ts +89 -0
  61. package/src/vue/__test__/insert-image.test.ts +100 -0
  62. package/src/vue/__test__/sheet-component.test.ts +716 -27
  63. package/src/vue/__test__/sheet-context-menu.test.ts +206 -0
  64. package/src/vue/__test__/use-formula-ref-select.test.ts +35 -0
  65. package/src/vue/__test__/use-formula-suggest.test.ts +83 -0
  66. package/src/vue/formula-bar.vue +473 -0
  67. package/src/vue/formula-suggest-list.vue +64 -0
  68. package/src/vue/import-file.ts +173 -0
  69. package/src/vue/insert-count-menu-item.vue +69 -0
  70. package/src/vue/insert-image.ts +90 -0
  71. package/src/vue/parsing.ts +11 -0
  72. package/src/vue/popup-helpers.ts +50 -0
  73. package/src/vue/popups/border-popup.vue +93 -0
  74. package/src/vue/popups/border-preset-glyph.vue +111 -0
  75. package/src/vue/popups/export-popup.vue +52 -0
  76. package/src/vue/popups/fill-color-popup.vue +39 -0
  77. package/src/vue/popups/find-popup.vue +111 -0
  78. package/src/vue/popups/font-color-popup.vue +39 -0
  79. package/src/vue/popups/font-size-popup.vue +52 -0
  80. package/src/vue/popups/import.worker.ts +66 -0
  81. package/src/vue/popups/insert-image-popup.vue +39 -0
  82. package/src/vue/sheet-context-menu.ts +229 -0
  83. package/src/vue/sheet-tabs.vue +162 -0
  84. package/src/vue/sheet-toolbar.vue +91 -0
  85. package/src/vue/sheet.vue +161 -186
  86. package/src/vue/style.scss +646 -3
  87. package/src/vue/style.ts +11 -0
  88. package/src/vue/use-find-replace.ts +200 -0
  89. package/src/vue/use-formula-ref-select.ts +34 -0
  90. package/src/vue/use-formula-suggest.ts +150 -0
  91. package/src/vue/use-sheet-grid.ts +243 -0
  92. package/src/vue/use-sheet-state.ts +161 -0
  93. package/src/vue/use-sheet-tabs-bar.ts +115 -0
  94. package/src/vue/use-tool-groups.ts +61 -0
  95. package/src/vue/use-tool-popup.ts +150 -0
  96. package/src/vue/use-toolbar-scroll.ts +95 -0
  97. package/dist/core/address.d.ts +0 -60
  98. package/dist/core/address.js +0 -142
  99. package/dist/core/address.js.map +0 -1
  100. package/dist/core/cell-store.d.ts +0 -61
  101. package/dist/core/cell-store.js +0 -135
  102. package/dist/core/cell-store.js.map +0 -1
  103. package/dist/core/command/default-registry.d.ts +0 -10
  104. package/dist/core/command/default-registry.js +0 -18
  105. package/dist/core/command/default-registry.js.map +0 -1
  106. package/dist/core/command/history.d.ts +0 -64
  107. package/dist/core/command/history.js +0 -127
  108. package/dist/core/command/history.js.map +0 -1
  109. package/dist/core/command/merge-cells.d.ts +0 -21
  110. package/dist/core/command/merge-cells.js +0 -74
  111. package/dist/core/command/merge-cells.js.map +0 -1
  112. package/dist/core/command/registry.d.ts +0 -17
  113. package/dist/core/command/registry.js +0 -26
  114. package/dist/core/command/registry.js.map +0 -1
  115. package/dist/core/command/set-cell-formula.d.ts +0 -17
  116. package/dist/core/command/set-cell-formula.js +0 -29
  117. package/dist/core/command/set-cell-formula.js.map +0 -1
  118. package/dist/core/command/set-cell-value.d.ts +0 -22
  119. package/dist/core/command/set-cell-value.js +0 -35
  120. package/dist/core/command/set-cell-value.js.map +0 -1
  121. package/dist/core/command/types.d.ts +0 -68
  122. package/dist/core/events.js +0 -29
  123. package/dist/core/events.js.map +0 -1
  124. package/dist/core/fill.d.ts +0 -34
  125. package/dist/core/fill.js +0 -320
  126. package/dist/core/fill.js.map +0 -1
  127. package/dist/core/formula/ast.d.ts +0 -58
  128. package/dist/core/formula/ast.js +0 -38
  129. package/dist/core/formula/ast.js.map +0 -1
  130. package/dist/core/formula/dependency-graph.d.ts +0 -70
  131. package/dist/core/formula/dependency-graph.js +0 -269
  132. package/dist/core/formula/dependency-graph.js.map +0 -1
  133. package/dist/core/formula/errors.d.ts +0 -25
  134. package/dist/core/formula/errors.js +0 -36
  135. package/dist/core/formula/errors.js.map +0 -1
  136. package/dist/core/formula/evaluator.d.ts +0 -41
  137. package/dist/core/formula/evaluator.js +0 -154
  138. package/dist/core/formula/evaluator.js.map +0 -1
  139. package/dist/core/formula/functions.d.ts +0 -30
  140. package/dist/core/formula/functions.js +0 -209
  141. package/dist/core/formula/functions.js.map +0 -1
  142. package/dist/core/formula/parser.d.ts +0 -7
  143. package/dist/core/formula/parser.js +0 -208
  144. package/dist/core/formula/parser.js.map +0 -1
  145. package/dist/core/formula/tokenizer.d.ts +0 -37
  146. package/dist/core/formula/tokenizer.js +0 -146
  147. package/dist/core/formula/tokenizer.js.map +0 -1
  148. package/dist/core/merge-manager.d.ts +0 -64
  149. package/dist/core/merge-manager.js +0 -111
  150. package/dist/core/merge-manager.js.map +0 -1
  151. package/dist/core/selection.d.ts +0 -31
  152. package/dist/core/selection.js +0 -62
  153. package/dist/core/selection.js.map +0 -1
  154. package/dist/core/sheet.d.ts +0 -116
  155. package/dist/core/sheet.js +0 -224
  156. package/dist/core/sheet.js.map +0 -1
  157. package/dist/core/workbook.d.ts +0 -43
  158. package/dist/core/workbook.js +0 -77
  159. package/dist/core/workbook.js.map +0 -1
  160. package/dist/grid/sheet-grid.d.ts +0 -81
  161. package/dist/grid/sheet-grid.js +0 -331
  162. package/dist/grid/sheet-grid.js.map +0 -1
  163. package/dist/grid/vtable-theme.js +0 -80
  164. package/dist/grid/vtable-theme.js.map +0 -1
  165. package/dist/tools/builtin.js.map +0 -1
  166. package/dist/tools/context.js.map +0 -1
  167. package/dist/tools/registry.js.map +0 -1
  168. package/dist/vue/index.d.ts +0 -2
  169. package/dist/vue/sheet.js.map +0 -1
  170. package/dist/vue/sheet.vue.d.ts +0 -24
  171. package/src/core/__test__/address.test.ts +0 -113
  172. package/src/core/__test__/cell-store.test.ts +0 -97
  173. package/src/core/__test__/command.test.ts +0 -377
  174. package/src/core/__test__/fill.test.ts +0 -140
  175. package/src/core/__test__/formula-adversarial.test.ts +0 -265
  176. package/src/core/__test__/formula-engine.test.ts +0 -470
  177. package/src/core/__test__/formula-functions.test.ts +0 -178
  178. package/src/core/__test__/formula-parser.test.ts +0 -160
  179. package/src/core/__test__/history.test.ts +0 -225
  180. package/src/core/__test__/merge-manager.test.ts +0 -106
  181. package/src/core/__test__/sheet.test.ts +0 -142
  182. package/src/core/address.ts +0 -166
  183. package/src/core/cell-store.ts +0 -173
  184. package/src/core/command/default-registry.ts +0 -15
  185. package/src/core/command/history.ts +0 -167
  186. package/src/core/command/index.ts +0 -7
  187. package/src/core/command/merge-cells.ts +0 -74
  188. package/src/core/command/registry.ts +0 -30
  189. package/src/core/command/set-cell-formula.ts +0 -29
  190. package/src/core/command/set-cell-value.ts +0 -38
  191. package/src/core/command/types.ts +0 -73
  192. package/src/core/events.ts +0 -37
  193. package/src/core/fill.ts +0 -314
  194. package/src/core/formula/ast.ts +0 -66
  195. package/src/core/formula/dependency-graph.ts +0 -329
  196. package/src/core/formula/errors.ts +0 -41
  197. package/src/core/formula/evaluator.ts +0 -219
  198. package/src/core/formula/functions.ts +0 -266
  199. package/src/core/formula/index.ts +0 -7
  200. package/src/core/formula/parser.ts +0 -198
  201. package/src/core/formula/tokenizer.ts +0 -160
  202. package/src/core/merge-manager.ts +0 -158
  203. package/src/core/selection.ts +0 -66
  204. package/src/core/sheet.ts +0 -282
  205. package/src/core/workbook.ts +0 -99
  206. package/src/grid/__test__/canvas-mock.ts +0 -49
  207. package/src/grid/__test__/setup.ts +0 -3
  208. package/src/grid/__test__/sheet-grid-formula.test.ts +0 -140
  209. package/src/grid/__test__/sheet-grid.test.ts +0 -275
  210. package/src/grid/sheet-grid.ts +0 -407
  211. package/src/grid/vtable-theme.ts +0 -61
@@ -1,74 +0,0 @@
1
- import { iterateRange, rangesIntersect } from "../address.js";
2
- import { cellDataEqual, isEmptyCellData } from "../cell-store.js";
3
- //#region src/core/command/merge-cells.ts
4
- /**
5
- * 合并命令。Patch 捕获完整 before 状态:
6
- * - 被解除的既有合并记录(undo 时逐一恢复)
7
- * - 包围盒内每一格的原数据(undo 时连被清空的值一起还原)
8
- * 值保留规则同 Excel/univer:行主序第一个有值格的值写入新锚点,其余清空。
9
- */
10
- const MergeCellsCommand = {
11
- id: "sheet.command.merge-cells",
12
- handler(ctx, params) {
13
- const { sheet } = ctx;
14
- const { range: finalRange, removed } = sheet.merges.computeMerge(params.range);
15
- const cellPatches = [];
16
- let retained;
17
- let anchorPatch;
18
- for (const addr of iterateRange(finalRange)) {
19
- const before = sheet.store.getCell(addr);
20
- if (before && !retained && !isEmptyCellData(before)) retained = before;
21
- const patch = {
22
- kind: "cell",
23
- addr,
24
- before,
25
- after: void 0
26
- };
27
- if (addr.row === finalRange.start.row && addr.col === finalRange.start.col) anchorPatch = patch;
28
- cellPatches.push(patch);
29
- }
30
- if (retained && anchorPatch) anchorPatch.after = { ...retained };
31
- const patches = [...[...removed.map((range) => ({
32
- kind: "merge",
33
- range,
34
- before: true,
35
- after: false
36
- })), {
37
- kind: "merge",
38
- range: finalRange,
39
- before: false,
40
- after: true
41
- }], ...cellPatches.filter((patch) => !cellDataEqual(patch.before, patch.after))];
42
- for (const patch of patches) ctx.applyPatch(patch, "redo");
43
- return {
44
- mutations: [{
45
- redo: patches,
46
- undo: [...patches].reverse()
47
- }],
48
- result: finalRange
49
- };
50
- }
51
- };
52
- /** 取消合并命令:解除与 range 相交的所有合并;undo 恢复合并记录 */
53
- const UnmergeCellsCommand = {
54
- id: "sheet.command.unmerge-cells",
55
- handler(ctx, params) {
56
- const removed = [];
57
- for (const range of ctx.sheet.merges.getMerges()) if (rangesIntersect(range, params.range)) removed.push({
58
- kind: "merge",
59
- range,
60
- before: true,
61
- after: false
62
- });
63
- if (removed.length === 0) return { mutations: [] };
64
- for (const patch of removed) ctx.applyPatch(patch, "redo");
65
- return { mutations: [{
66
- redo: removed,
67
- undo: [...removed].reverse()
68
- }] };
69
- }
70
- };
71
- //#endregion
72
- export { MergeCellsCommand, UnmergeCellsCommand };
73
-
74
- //# sourceMappingURL=merge-cells.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"merge-cells.js","names":[],"sources":["../../../src/core/command/merge-cells.ts"],"sourcesContent":["import { iterateRange, rangesIntersect, type CellRange } from '../address'\nimport { cellDataEqual, isEmptyCellData, type CellData } from '../cell-store'\nimport type { CellPatch, Command, CommandResult, MergePatch, Patch } from './types'\n\nexport interface MergeCellsParams {\n range: CellRange\n}\n\n/**\n * 合并命令。Patch 捕获完整 before 状态:\n * - 被解除的既有合并记录(undo 时逐一恢复)\n * - 包围盒内每一格的原数据(undo 时连被清空的值一起还原)\n * 值保留规则同 Excel/univer:行主序第一个有值格的值写入新锚点,其余清空。\n */\nexport const MergeCellsCommand: Command<MergeCellsParams, CellRange> = {\n id: 'sheet.command.merge-cells',\n\n handler(ctx, params): CommandResult<CellRange> {\n const { sheet } = ctx\n const { range: finalRange, removed } = sheet.merges.computeMerge(params.range)\n\n // 捕获包围盒内各格 before;同时按行主序找出第一个有值格\n const cellPatches: CellPatch[] = []\n let retained: CellData | undefined\n let anchorPatch: CellPatch | undefined\n for (const addr of iterateRange(finalRange)) {\n const before = sheet.store.getCell(addr)\n if (before && !retained && !isEmptyCellData(before)) retained = before\n const patch: CellPatch = { kind: 'cell', addr, before, after: undefined }\n if (addr.row === finalRange.start.row && addr.col === finalRange.start.col) {\n anchorPatch = patch\n }\n cellPatches.push(patch)\n }\n if (retained && anchorPatch) {\n anchorPatch.after = { ...retained }\n }\n\n const mergePatches: MergePatch[] = [\n ...removed.map((range): MergePatch => ({ kind: 'merge', range, before: true, after: false })),\n { kind: 'merge', range: finalRange, before: false, after: true }\n ]\n\n // 过滤无实际变化的 cell 补丁(如被覆盖格本就为空)\n const patches: Patch[] = [\n ...mergePatches,\n ...cellPatches.filter((patch) => !cellDataEqual(patch.before, patch.after))\n ]\n for (const patch of patches) ctx.applyPatch(patch, 'redo')\n\n return { mutations: [{ redo: patches, undo: [...patches].reverse() }], result: finalRange }\n }\n}\n\nexport interface UnmergeCellsParams {\n range: CellRange\n}\n\n/** 取消合并命令:解除与 range 相交的所有合并;undo 恢复合并记录 */\nexport const UnmergeCellsCommand: Command<UnmergeCellsParams> = {\n id: 'sheet.command.unmerge-cells',\n\n handler(ctx, params): CommandResult {\n const removed: MergePatch[] = []\n for (const range of ctx.sheet.merges.getMerges()) {\n if (rangesIntersect(range, params.range)) {\n removed.push({ kind: 'merge', range, before: true, after: false })\n }\n }\n if (removed.length === 0) return { mutations: [] }\n for (const patch of removed) ctx.applyPatch(patch, 'redo')\n return { mutations: [{ redo: removed, undo: [...removed].reverse() }] }\n }\n}\n"],"mappings":";;;;;;;;;AAcA,MAAa,oBAA0D;CACrE,IAAI;CAEJ,QAAQ,KAAK,QAAkC;EAC7C,MAAM,EAAE,UAAU;EAClB,MAAM,EAAE,OAAO,YAAY,YAAY,MAAM,OAAO,aAAa,OAAO,KAAK;EAG7E,MAAM,cAA2B,CAAC;EAClC,IAAI;EACJ,IAAI;EACJ,KAAK,MAAM,QAAQ,aAAa,UAAU,GAAG;GAC3C,MAAM,SAAS,MAAM,MAAM,QAAQ,IAAI;GACvC,IAAI,UAAU,CAAC,YAAY,CAAC,gBAAgB,MAAM,GAAG,WAAW;GAChE,MAAM,QAAmB;IAAE,MAAM;IAAQ;IAAM;IAAQ,OAAO,KAAA;GAAU;GACxE,IAAI,KAAK,QAAQ,WAAW,MAAM,OAAO,KAAK,QAAQ,WAAW,MAAM,KACrE,cAAc;GAEhB,YAAY,KAAK,KAAK;EACxB;EACA,IAAI,YAAY,aACd,YAAY,QAAQ,EAAE,GAAG,SAAS;EASpC,MAAM,UAAmB,CACvB,GAAG,CANH,GAAG,QAAQ,KAAK,WAAuB;GAAE,MAAM;GAAS;GAAO,QAAQ;GAAM,OAAO;EAAM,EAAE,GAC5F;GAAE,MAAM;GAAS,OAAO;GAAY,QAAQ;GAAO,OAAO;EAAK,CAKjD,GACd,GAAG,YAAY,QAAQ,UAAU,CAAC,cAAc,MAAM,QAAQ,MAAM,KAAK,CAAC,CAC5E;EACA,KAAK,MAAM,SAAS,SAAS,IAAI,WAAW,OAAO,MAAM;EAEzD,OAAO;GAAE,WAAW,CAAC;IAAE,MAAM;IAAS,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,QAAQ;GAAE,CAAC;GAAG,QAAQ;EAAW;CAC5F;AACF;;AAOA,MAAa,sBAAmD;CAC9D,IAAI;CAEJ,QAAQ,KAAK,QAAuB;EAClC,MAAM,UAAwB,CAAC;EAC/B,KAAK,MAAM,SAAS,IAAI,MAAM,OAAO,UAAU,GAC7C,IAAI,gBAAgB,OAAO,OAAO,KAAK,GACrC,QAAQ,KAAK;GAAE,MAAM;GAAS;GAAO,QAAQ;GAAM,OAAO;EAAM,CAAC;EAGrE,IAAI,QAAQ,WAAW,GAAG,OAAO,EAAE,WAAW,CAAC,EAAE;EACjD,KAAK,MAAM,SAAS,SAAS,IAAI,WAAW,OAAO,MAAM;EACzD,OAAO,EAAE,WAAW,CAAC;GAAE,MAAM;GAAS,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,QAAQ;EAAE,CAAC,EAAE;CACxE;AACF"}
@@ -1,17 +0,0 @@
1
- import { Command, CommandContext, CommandResult } from "./types.js";
2
- //#region src/core/command/registry.d.ts
3
- /**
4
- * 命令注册表:register / execute。
5
- * 命令无状态,可全局共享(见 default-registry);阶段 4 工具扩展可注册自定义命令。
6
- */
7
- declare class CommandRegistry {
8
- private commands;
9
- /** 注册命令;同 id 重复注册视为错误 */
10
- register(command: Command): void;
11
- get(id: string): Command | undefined;
12
- /** 执行命令;未注册的 id 抛错 */
13
- execute<R>(ctx: CommandContext, id: string, params: unknown): CommandResult<R> | undefined;
14
- }
15
- //#endregion
16
- export { CommandRegistry };
17
- //# sourceMappingURL=registry.d.ts.map
@@ -1,26 +0,0 @@
1
- //#region src/core/command/registry.ts
2
- /**
3
- * 命令注册表:register / execute。
4
- * 命令无状态,可全局共享(见 default-registry);阶段 4 工具扩展可注册自定义命令。
5
- */
6
- var CommandRegistry = class {
7
- commands = /* @__PURE__ */ new Map();
8
- /** 注册命令;同 id 重复注册视为错误 */
9
- register(command) {
10
- if (this.commands.has(command.id)) throw new Error(`命令重复注册: ${command.id}`);
11
- this.commands.set(command.id, command);
12
- }
13
- get(id) {
14
- return this.commands.get(id);
15
- }
16
- /** 执行命令;未注册的 id 抛错 */
17
- execute(ctx, id, params) {
18
- const command = this.commands.get(id);
19
- if (!command) throw new Error(`命令未注册: ${id}`);
20
- return command.handler(ctx, params);
21
- }
22
- };
23
- //#endregion
24
- export { CommandRegistry };
25
-
26
- //# sourceMappingURL=registry.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"registry.js","names":[],"sources":["../../../src/core/command/registry.ts"],"sourcesContent":["import type { Command, CommandContext, CommandResult } from './types'\n\n/**\n * 命令注册表:register / execute。\n * 命令无状态,可全局共享(见 default-registry);阶段 4 工具扩展可注册自定义命令。\n */\nexport class CommandRegistry {\n private commands = new Map<string, Command>()\n\n /** 注册命令;同 id 重复注册视为错误 */\n register(command: Command): void {\n if (this.commands.has(command.id)) {\n throw new Error(`命令重复注册: ${command.id}`)\n }\n this.commands.set(command.id, command)\n }\n\n get(id: string): Command | undefined {\n return this.commands.get(id)\n }\n\n /** 执行命令;未注册的 id 抛错 */\n execute<R>(ctx: CommandContext, id: string, params: unknown): CommandResult<R> | undefined {\n const command = this.commands.get(id)\n if (!command) {\n throw new Error(`命令未注册: ${id}`)\n }\n return command.handler(ctx, params) as CommandResult<R> | undefined\n }\n}\n"],"mappings":";;;;;AAMA,IAAa,kBAAb,MAA6B;CAC3B,2BAAmB,IAAI,IAAqB;;CAG5C,SAAS,SAAwB;EAC/B,IAAI,KAAK,SAAS,IAAI,QAAQ,EAAE,GAC9B,MAAM,IAAI,MAAM,WAAW,QAAQ,IAAI;EAEzC,KAAK,SAAS,IAAI,QAAQ,IAAI,OAAO;CACvC;CAEA,IAAI,IAAiC;EACnC,OAAO,KAAK,SAAS,IAAI,EAAE;CAC7B;;CAGA,QAAW,KAAqB,IAAY,QAA+C;EACzF,MAAM,UAAU,KAAK,SAAS,IAAI,EAAE;EACpC,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,UAAU,IAAI;EAEhC,OAAO,QAAQ,QAAQ,KAAK,MAAM;CACpC;AACF"}
@@ -1,17 +0,0 @@
1
- import { CellAddress } from "../address.js";
2
- import { Command } from "./types.js";
3
- //#region src/core/command/set-cell-formula.d.ts
4
- interface SetCellFormulaParams {
5
- addr: CellAddress;
6
- /** 公式文本(不含 '=') */
7
- formula: string;
8
- }
9
- /**
10
- * 公式写入命令:只登记公式原文(f);计算缓存(v/t)由命令执行后的
11
- * 增量重算以派生补丁填充(见 Sheet.executeCommand),重算波及的所有变更
12
- * 与源补丁并入同一 undo 单元。
13
- */
14
- declare const SetCellFormulaCommand: Command<SetCellFormulaParams>;
15
- //#endregion
16
- export { SetCellFormulaCommand, SetCellFormulaParams };
17
- //# sourceMappingURL=set-cell-formula.d.ts.map
@@ -1,29 +0,0 @@
1
- //#region src/core/command/set-cell-formula.ts
2
- /**
3
- * 公式写入命令:只登记公式原文(f);计算缓存(v/t)由命令执行后的
4
- * 增量重算以派生补丁填充(见 Sheet.executeCommand),重算波及的所有变更
5
- * 与源补丁并入同一 undo 单元。
6
- */
7
- const SetCellFormulaCommand = {
8
- id: "sheet.command.set-cell-formula",
9
- handler(ctx, params) {
10
- const anchor = ctx.sheet.merges.resolveAnchor(params.addr);
11
- const before = ctx.sheet.store.getCell(anchor);
12
- if (before?.f === params.formula) return { mutations: [] };
13
- const patch = {
14
- kind: "cell",
15
- addr: anchor,
16
- before,
17
- after: { f: params.formula }
18
- };
19
- ctx.applyPatch(patch, "redo");
20
- return { mutations: [{
21
- redo: [patch],
22
- undo: [patch]
23
- }] };
24
- }
25
- };
26
- //#endregion
27
- export { SetCellFormulaCommand };
28
-
29
- //# sourceMappingURL=set-cell-formula.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"set-cell-formula.js","names":[],"sources":["../../../src/core/command/set-cell-formula.ts"],"sourcesContent":["import type { CellAddress } from '../address'\nimport type { CellData } from '../cell-store'\nimport type { CellPatch, Command, CommandResult } from './types'\n\nexport interface SetCellFormulaParams {\n addr: CellAddress\n /** 公式文本(不含 '=') */\n formula: string\n}\n\n/**\n * 公式写入命令:只登记公式原文(f);计算缓存(v/t)由命令执行后的\n * 增量重算以派生补丁填充(见 Sheet.executeCommand),重算波及的所有变更\n * 与源补丁并入同一 undo 单元。\n */\nexport const SetCellFormulaCommand: Command<SetCellFormulaParams> = {\n id: 'sheet.command.set-cell-formula',\n\n handler(ctx, params): CommandResult {\n const anchor = ctx.sheet.merges.resolveAnchor(params.addr)\n const before = ctx.sheet.store.getCell(anchor)\n // 同公式重复输入 = 无实际变更,不入历史\n if (before?.f === params.formula) return { mutations: [] }\n const after: CellData = { f: params.formula }\n const patch: CellPatch = { kind: 'cell', addr: anchor, before, after }\n ctx.applyPatch(patch, 'redo')\n return { mutations: [{ redo: [patch], undo: [patch] }] }\n }\n}\n"],"mappings":";;;;;;AAeA,MAAa,wBAAuD;CAClE,IAAI;CAEJ,QAAQ,KAAK,QAAuB;EAClC,MAAM,SAAS,IAAI,MAAM,OAAO,cAAc,OAAO,IAAI;EACzD,MAAM,SAAS,IAAI,MAAM,MAAM,QAAQ,MAAM;EAE7C,IAAI,QAAQ,MAAM,OAAO,SAAS,OAAO,EAAE,WAAW,CAAC,EAAE;EAEzD,MAAM,QAAmB;GAAE,MAAM;GAAQ,MAAM;GAAQ;GAAQ,OAAA,EADrC,GAAG,OAAO,QAC+B;EAAE;EACrE,IAAI,WAAW,OAAO,MAAM;EAC5B,OAAO,EAAE,WAAW,CAAC;GAAE,MAAM,CAAC,KAAK;GAAG,MAAM,CAAC,KAAK;EAAE,CAAC,EAAE;CACzD;AACF"}
@@ -1,22 +0,0 @@
1
- import { CellAddress } from "../address.js";
2
- import { CellData } from "../cell-store.js";
3
- import { Command } from "./types.js";
4
- //#region src/core/command/set-cell-value.d.ts
5
- /** SetCellValueCommand 的批量写入项 */
6
- interface SetCellValueItem {
7
- addr: CellAddress;
8
- /** 目标数据;空数据(无公式且 v 为 null/undefined/'')= 清除 */
9
- data?: CellData;
10
- }
11
- interface SetCellValueParams {
12
- /** 批量写入(供粘贴/填充复用);一次调用 = 一个 undo 单元 */
13
- items: SetCellValueItem[];
14
- }
15
- /**
16
- * 单元格写入命令:逐项解析锚点、捕获 before/after 差量并立即应用。
17
- * 与 before 相等的项跳过(不产生补丁);全部无变化时不入历史。
18
- */
19
- declare const SetCellValueCommand: Command<SetCellValueParams>;
20
- //#endregion
21
- export { SetCellValueCommand, SetCellValueItem, SetCellValueParams };
22
- //# sourceMappingURL=set-cell-value.d.ts.map
@@ -1,35 +0,0 @@
1
- import { cellDataEqual, isEmptyCellData } from "../cell-store.js";
2
- //#region src/core/command/set-cell-value.ts
3
- /**
4
- * 单元格写入命令:逐项解析锚点、捕获 before/after 差量并立即应用。
5
- * 与 before 相等的项跳过(不产生补丁);全部无变化时不入历史。
6
- */
7
- const SetCellValueCommand = {
8
- id: "sheet.command.set-cell-value",
9
- handler(ctx, params) {
10
- const patches = [];
11
- for (const item of params.items) {
12
- const anchor = ctx.sheet.merges.resolveAnchor(item.addr);
13
- const before = ctx.sheet.store.getCell(anchor);
14
- const after = isEmptyCellData(item.data) ? void 0 : item.data;
15
- if (cellDataEqual(before, after)) continue;
16
- const patch = {
17
- kind: "cell",
18
- addr: anchor,
19
- before,
20
- after
21
- };
22
- ctx.applyPatch(patch, "redo");
23
- patches.push(patch);
24
- }
25
- if (patches.length === 0) return { mutations: [] };
26
- return { mutations: [{
27
- redo: patches,
28
- undo: [...patches].reverse()
29
- }] };
30
- }
31
- };
32
- //#endregion
33
- export { SetCellValueCommand };
34
-
35
- //# sourceMappingURL=set-cell-value.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"set-cell-value.js","names":[],"sources":["../../../src/core/command/set-cell-value.ts"],"sourcesContent":["import type { CellAddress } from '../address'\nimport { cellDataEqual, isEmptyCellData, type CellData } from '../cell-store'\nimport type { CellPatch, Command, CommandResult } from './types'\n\n/** SetCellValueCommand 的批量写入项 */\nexport interface SetCellValueItem {\n addr: CellAddress\n /** 目标数据;空数据(无公式且 v 为 null/undefined/'')= 清除 */\n data?: CellData\n}\n\nexport interface SetCellValueParams {\n /** 批量写入(供粘贴/填充复用);一次调用 = 一个 undo 单元 */\n items: SetCellValueItem[]\n}\n\n/**\n * 单元格写入命令:逐项解析锚点、捕获 before/after 差量并立即应用。\n * 与 before 相等的项跳过(不产生补丁);全部无变化时不入历史。\n */\nexport const SetCellValueCommand: Command<SetCellValueParams> = {\n id: 'sheet.command.set-cell-value',\n\n handler(ctx, params): CommandResult {\n const patches: CellPatch[] = []\n for (const item of params.items) {\n const anchor = ctx.sheet.merges.resolveAnchor(item.addr)\n const before = ctx.sheet.store.getCell(anchor)\n const after = isEmptyCellData(item.data) ? undefined : item.data\n if (cellDataEqual(before, after)) continue\n const patch: CellPatch = { kind: 'cell', addr: anchor, before, after }\n ctx.applyPatch(patch, 'redo')\n patches.push(patch)\n }\n if (patches.length === 0) return { mutations: [] }\n return { mutations: [{ redo: patches, undo: [...patches].reverse() }] }\n }\n}\n"],"mappings":";;;;;;AAoBA,MAAa,sBAAmD;CAC9D,IAAI;CAEJ,QAAQ,KAAK,QAAuB;EAClC,MAAM,UAAuB,CAAC;EAC9B,KAAK,MAAM,QAAQ,OAAO,OAAO;GAC/B,MAAM,SAAS,IAAI,MAAM,OAAO,cAAc,KAAK,IAAI;GACvD,MAAM,SAAS,IAAI,MAAM,MAAM,QAAQ,MAAM;GAC7C,MAAM,QAAQ,gBAAgB,KAAK,IAAI,IAAI,KAAA,IAAY,KAAK;GAC5D,IAAI,cAAc,QAAQ,KAAK,GAAG;GAClC,MAAM,QAAmB;IAAE,MAAM;IAAQ,MAAM;IAAQ;IAAQ;GAAM;GACrE,IAAI,WAAW,OAAO,MAAM;GAC5B,QAAQ,KAAK,KAAK;EACpB;EACA,IAAI,QAAQ,WAAW,GAAG,OAAO,EAAE,WAAW,CAAC,EAAE;EACjD,OAAO,EAAE,WAAW,CAAC;GAAE,MAAM;GAAS,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,QAAQ;EAAE,CAAC,EAAE;CACxE;AACF"}
@@ -1,68 +0,0 @@
1
- import { CellAddress, CellRange } from "../address.js";
2
- import { CellData } from "../cell-store.js";
3
- import { Sheet } from "../sheet.js";
4
- //#region src/core/command/types.d.ts
5
- /**
6
- * 命令系统类型定义(决策 5:命令 + 逆操作补丁)。
7
- *
8
- * - 一切模型变更都是 Command,执行时产出 Mutation
9
- * - Patch 是受影响单元格 / 合并记录的 before/after 差量,不是全量快照
10
- * - 同一批 Patch 双向回放:redo 方向应用 after,undo 方向应用 before
11
- */
12
- /** 补丁回放方向 */
13
- type PatchDirection = 'undo' | 'redo';
14
- /** 单元格数据差量补丁(原始存储语义;undefined = 该侧无此格) */
15
- interface CellPatch {
16
- kind: 'cell';
17
- addr: CellAddress;
18
- /**
19
- * 目标 sheet(跨表公式重算的派生补丁会落在其它 sheet 上);
20
- * 缺省 = 命令所在 sheet。回放时按此字段路由到目标 sheet 的变更通道。
21
- */
22
- sheet?: Sheet;
23
- /** 变更前的数据(undefined = 原本为空格) */
24
- before?: CellData;
25
- /** 变更后的数据(undefined = 变更后为空格) */
26
- after?: CellData;
27
- }
28
- /** 合并记录差量补丁(before/after = 该侧是否存在此合并) */
29
- interface MergePatch {
30
- kind: 'merge';
31
- range: CellRange;
32
- before: boolean;
33
- after: boolean;
34
- }
35
- type Patch = CellPatch | MergePatch;
36
- /**
37
- * 一次命令执行产生的变更单元。
38
- * `redo` 按列表顺序应用;`undo` 取同一批补丁的逆序(命令实现负责构造,
39
- * 保证 undo 先撤销后登记的副作用,例如先移除新合并再恢复旧合并)。
40
- */
41
- interface Mutation {
42
- redo: Patch[];
43
- undo: Patch[];
44
- }
45
- /** 命令执行结果 */
46
- interface CommandResult<R = unknown> {
47
- /** 产生的 mutation 列表(空数组 = 无实际变更,不入历史) */
48
- mutations: Mutation[];
49
- /** 命令附带返回值(如 MergeCellsCommand 返回最终生效区域) */
50
- result?: R;
51
- }
52
- /** 命令执行上下文 */
53
- interface CommandContext {
54
- sheet: Sheet;
55
- /**
56
- * 应用单个补丁。命令 handler 执行时对 redo 补丁逐项调用;
57
- * HistoryManager 回放 undo/redo 亦走此路径,保证只有一条变更通道。
58
- */
59
- applyPatch(patch: Patch, direction: PatchDirection): void;
60
- }
61
- /** 命令:id + handler */
62
- interface Command<P = unknown, R = unknown> {
63
- readonly id: string;
64
- handler(ctx: CommandContext, params: P): CommandResult<R> | undefined;
65
- }
66
- //#endregion
67
- export { CellPatch, Command, CommandContext, CommandResult, MergePatch, Mutation, Patch, PatchDirection };
68
- //# sourceMappingURL=types.d.ts.map
@@ -1,29 +0,0 @@
1
- //#region src/core/events.ts
2
- var TypedEventEmitter = class {
3
- handlers = /* @__PURE__ */ new Map();
4
- /** 订阅事件,返回取消订阅函数 */
5
- on(type, handler) {
6
- let set = this.handlers.get(type);
7
- if (!set) {
8
- set = /* @__PURE__ */ new Set();
9
- this.handlers.set(type, set);
10
- }
11
- set.add(handler);
12
- return () => this.off(type, handler);
13
- }
14
- off(type, handler) {
15
- this.handlers.get(type)?.delete(handler);
16
- }
17
- emit(type, payload) {
18
- const set = this.handlers.get(type);
19
- if (!set) return;
20
- for (const handler of set) handler(payload);
21
- }
22
- clear() {
23
- this.handlers.clear();
24
- }
25
- };
26
- //#endregion
27
- export { TypedEventEmitter };
28
-
29
- //# sourceMappingURL=events.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"events.js","names":[],"sources":["../../src/core/events.ts"],"sourcesContent":["/**\n * 包内轻量类型化事件发射器(core 内部基建,不对外导出实现细节)。\n */\n\nexport type EventHandler<T> = (payload: T) => void\n\nexport class TypedEventEmitter<EventMap extends Record<string, unknown>> {\n private handlers = new Map<keyof EventMap, Set<EventHandler<EventMap[keyof EventMap]>>>()\n\n /** 订阅事件,返回取消订阅函数 */\n on<K extends keyof EventMap>(type: K, handler: EventHandler<EventMap[K]>): () => void {\n let set = this.handlers.get(type)\n if (!set) {\n set = new Set()\n this.handlers.set(type, set)\n }\n set.add(handler as EventHandler<EventMap[keyof EventMap]>)\n return () => this.off(type, handler)\n }\n\n off<K extends keyof EventMap>(type: K, handler: EventHandler<EventMap[K]>): void {\n this.handlers.get(type)?.delete(handler as EventHandler<EventMap[keyof EventMap]>)\n }\n\n emit<K extends keyof EventMap>(type: K, payload: EventMap[K]): void {\n const set = this.handlers.get(type)\n if (!set) return\n // Set 迭代天然容忍遍历中取消订阅\n for (const handler of set) {\n ;(handler as EventHandler<EventMap[K]>)(payload)\n }\n }\n\n clear(): void {\n this.handlers.clear()\n }\n}\n"],"mappings":";AAMA,IAAa,oBAAb,MAAyE;CACvE,2BAAmB,IAAI,IAAiE;;CAGxF,GAA6B,MAAS,SAAgD;EACpF,IAAI,MAAM,KAAK,SAAS,IAAI,IAAI;EAChC,IAAI,CAAC,KAAK;GACR,sBAAM,IAAI,IAAI;GACd,KAAK,SAAS,IAAI,MAAM,GAAG;EAC7B;EACA,IAAI,IAAI,OAAiD;EACzD,aAAa,KAAK,IAAI,MAAM,OAAO;CACrC;CAEA,IAA8B,MAAS,SAA0C;EAC/E,KAAK,SAAS,IAAI,IAAI,CAAC,EAAE,OAAO,OAAiD;CACnF;CAEA,KAA+B,MAAS,SAA4B;EAClE,MAAM,MAAM,KAAK,SAAS,IAAI,IAAI;EAClC,IAAI,CAAC,KAAK;EAEV,KAAK,MAAM,WAAW,KACnB,QAAuC,OAAO;CAEnD;CAEA,QAAc;EACZ,KAAK,SAAS,MAAM;CACtB;AACF"}
@@ -1,34 +0,0 @@
1
- import { CellAddress, CellRange } from "./address.js";
2
- import { CellData } from "./cell-store.js";
3
- import { SetCellValueItem } from "./command/set-cell-value.js";
4
- //#region src/core/fill.d.ts
5
- /** 填充柄拖拽方向(与 VTable drag_fill_handle_end 一致) */
6
- type FillDirection = 'top' | 'bottom' | 'left' | 'right';
7
- interface GenerateFillOptions {
8
- /** 拖拽前的源选区(模型坐标) */
9
- source: CellRange;
10
- /** 需要写入的目标区(不含源区,模型坐标) */
11
- target: CellRange;
12
- /** 填充方向 */
13
- direction: FillDirection;
14
- /** 读取源区单元格(原始存储语义) */
15
- getCellData: (addr: CellAddress) => CellData | undefined;
16
- }
17
- /**
18
- * 由源选区 + 拖拽后扩展选区 + 方向,计算需要填充的目标区(模型坐标)。
19
- * 算法对齐 VTable 官方 fill-handle 示例(扩展选区含源区,目标为扩展部分)。
20
- */
21
- declare function computeFillTargetRange(source: CellRange, direction: FillDirection, expanded: CellRange): CellRange | null;
22
- /**
23
- * 生成填充写入项(tile / 数字日期等差 / 公式相对引用位移)。
24
- * 调用方一次 `sheet.setCells(items)` 即可(单 undo 单元)。
25
- */
26
- declare function generateFill(options: GenerateFillOptions): SetCellValueItem[];
27
- /**
28
- * 公式引用字符串级位移:尊重 `$` 绝对行列;出界 → `#REF!`。
29
- * 跳过双引号字符串字面量,避免改写文本中的 A1 片段。
30
- */
31
- declare function shiftFormulaRefs(formula: string, deltaRow: number, deltaCol: number): string;
32
- //#endregion
33
- export { FillDirection, GenerateFillOptions, computeFillTargetRange, generateFill, shiftFormulaRefs };
34
- //# sourceMappingURL=fill.d.ts.map