@veltra/sheet 2.0.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (339) hide show
  1. package/dist/components/report/binding-badge.js +76 -0
  2. package/dist/components/report/designer/cell-coords.js +46 -0
  3. package/dist/components/report/designer/col-widths.js +15 -0
  4. package/dist/components/report/designer/conditional-rules/helpers.js +139 -0
  5. package/dist/components/report/designer/drop-highlight-overlay.js +76 -0
  6. package/dist/components/report/designer/float-panel.js +385 -0
  7. package/dist/components/report/designer/role.js +17 -0
  8. package/dist/components/report/designer/rule-preview.js +33 -0
  9. package/dist/components/report/designer/rule-row.js +269 -0
  10. package/dist/components/report/designer/rules-dialog.js +135 -0
  11. package/dist/components/report/designer/topology-overlay.js +122 -0
  12. package/dist/components/report/designer/topology.js +64 -0
  13. package/dist/components/report/designer/use-grid-overlay.js +75 -0
  14. package/dist/components/report/designer-hub.js +177 -0
  15. package/dist/components/report/field-panel-helpers.js +33 -0
  16. package/dist/components/report/field-panel.js +132 -0
  17. package/dist/components/report/filter-bar.js +74 -0
  18. package/dist/components/report/hub-connection-form.js +145 -0
  19. package/dist/components/report/hub-dataset-editor.js +394 -0
  20. package/dist/components/report/report-designer.js +343 -0
  21. package/dist/components/report/report-viewer.js +111 -0
  22. package/dist/components/report/style.d.ts +17 -0
  23. package/dist/components/report/style.js +18 -0
  24. package/dist/components/report/style2.css +869 -0
  25. package/dist/components/report/use-report-designer.js +360 -0
  26. package/dist/components/report/use-report-viewer.js +50 -0
  27. package/dist/components/sheet/formula-bar.js +393 -0
  28. package/dist/components/sheet/formula-suggest-list.js +66 -0
  29. package/dist/components/sheet/import-file.js +140 -0
  30. package/dist/components/sheet/insert-count-menu-item.js +68 -0
  31. package/dist/components/sheet/insert-image.js +79 -0
  32. package/dist/components/sheet/popup-helpers.js +73 -0
  33. package/dist/components/sheet/popups/border-popup.js +75 -0
  34. package/dist/components/sheet/popups/border-preset-glyph.js +106 -0
  35. package/dist/components/sheet/popups/export-popup.js +51 -0
  36. package/dist/components/sheet/popups/fill-color-popup.js +37 -0
  37. package/dist/components/sheet/popups/find-popup.js +113 -0
  38. package/dist/components/sheet/popups/font-color-popup.js +37 -0
  39. package/dist/components/sheet/popups/font-size-popup.js +63 -0
  40. package/dist/components/sheet/popups/import.worker.d.ts +21 -0
  41. package/dist/components/sheet/popups/import.worker.js +41 -0
  42. package/dist/components/sheet/popups/insert-image-popup.js +38 -0
  43. package/dist/components/sheet/sheet-context-menu.js +200 -0
  44. package/dist/components/sheet/sheet-tabs.js +162 -0
  45. package/dist/components/sheet/sheet-toolbar.js +106 -0
  46. package/dist/components/sheet/sheet.js +198 -0
  47. package/dist/components/sheet/style.d.ts +11 -0
  48. package/dist/components/sheet/style.js +12 -0
  49. package/dist/components/sheet/style2.css +654 -0
  50. package/dist/components/sheet/use-find-replace.js +161 -0
  51. package/dist/components/sheet/use-formula-ref-select.js +37 -0
  52. package/dist/components/sheet/use-formula-suggest.js +126 -0
  53. package/dist/components/sheet/use-sheet-grid.js +188 -0
  54. package/dist/components/sheet/use-sheet-state.js +122 -0
  55. package/dist/components/sheet/use-sheet-tabs-bar.js +90 -0
  56. package/dist/components/sheet/use-tool-groups.js +42 -0
  57. package/dist/components/sheet/use-tool-popup.js +123 -0
  58. package/dist/components/sheet/use-toolbar-scroll.js +72 -0
  59. package/dist/index.d.ts +18 -26
  60. package/dist/index.js +14 -24
  61. package/dist/report/binding.d.ts +45 -0
  62. package/dist/report/binding.js +175 -0
  63. package/dist/report/connector.d.ts +66 -0
  64. package/dist/report/connector.js +159 -0
  65. package/dist/report/export-xlsx.d.ts +19 -0
  66. package/dist/report/export-xlsx.js +95 -0
  67. package/dist/report/filter-bar.d.ts +10 -0
  68. package/dist/report/filter-bar.js +31 -0
  69. package/dist/report/index.d.ts +12 -0
  70. package/dist/report/params.d.ts +13 -0
  71. package/dist/report/params.js +61 -0
  72. package/dist/report/render/aggregate.js +157 -0
  73. package/dist/report/render/builder.d.ts +12 -0
  74. package/dist/report/render/builder.js +139 -0
  75. package/dist/report/render/coordinate.d.ts +25 -0
  76. package/dist/report/render/coordinate.js +733 -0
  77. package/dist/report/render/index.d.ts +14 -0
  78. package/dist/report/render/index.js +21 -0
  79. package/dist/report/render/style-resolver.js +50 -0
  80. package/dist/report/render/template-index.d.ts +24 -0
  81. package/dist/report/render/template-index.js +137 -0
  82. package/dist/report/rules/evaluate.d.ts +25 -0
  83. package/dist/report/rules/evaluate.js +82 -0
  84. package/dist/report/rules/index.d.ts +2 -0
  85. package/dist/report/template.d.ts +59 -0
  86. package/dist/report/template.js +80 -0
  87. package/dist/report/types.d.ts +85 -0
  88. package/dist/tools/builtin.js +279 -8
  89. package/dist/tools/context.d.ts +54 -11
  90. package/dist/tools/context.js +28 -5
  91. package/dist/tools/download.js +68 -0
  92. package/dist/tools/export.worker.d.ts +16 -0
  93. package/dist/tools/export.worker.js +29 -0
  94. package/dist/tools/registry.d.ts +7 -4
  95. package/dist/tools/registry.js +1 -3
  96. package/dist/types/index.d.ts +3 -1
  97. package/dist/types/report-designer.d.ts +36 -0
  98. package/dist/types/report-viewer.d.ts +38 -0
  99. package/dist/types/sheet.d.ts +22 -5
  100. package/package.json +10 -7
  101. package/src/components/report/__test__/conditional-rules-helpers.test.ts +87 -0
  102. package/src/components/report/__test__/field-panel-helpers.test.ts +65 -0
  103. package/src/components/report/__test__/float-panel-position.test.ts +45 -0
  104. package/src/components/report/__test__/report-designer.test.ts +388 -0
  105. package/src/components/report/__test__/report-viewer.test.ts +334 -0
  106. package/src/components/report/__test__/topology.test.ts +143 -0
  107. package/src/components/report/__test__/use-report-designer.test.ts +565 -0
  108. package/src/components/report/binding-badge.ts +73 -0
  109. package/src/components/report/designer/cell-coords.ts +94 -0
  110. package/src/components/report/designer/col-widths.ts +33 -0
  111. package/src/components/report/designer/conditional-rules/helpers.ts +186 -0
  112. package/src/components/report/designer/drop-highlight-overlay.vue +74 -0
  113. package/src/components/report/designer/float-panel.vue +387 -0
  114. package/src/components/report/designer/role.ts +32 -0
  115. package/src/components/report/designer/rule-preview.vue +40 -0
  116. package/src/components/report/designer/rule-row.vue +252 -0
  117. package/src/components/report/designer/rules-dialog.vue +126 -0
  118. package/src/components/report/designer/topology-overlay.vue +127 -0
  119. package/src/components/report/designer/topology.ts +124 -0
  120. package/src/components/report/designer/use-grid-overlay.ts +113 -0
  121. package/src/components/report/designer-hub.vue +198 -0
  122. package/src/components/report/field-panel-helpers.ts +44 -0
  123. package/src/components/report/field-panel.vue +136 -0
  124. package/src/components/report/filter-bar.vue +77 -0
  125. package/src/components/report/hub-connection-form.vue +124 -0
  126. package/src/components/report/hub-dataset-editor.vue +369 -0
  127. package/src/components/report/index.ts +2 -0
  128. package/src/components/report/report-designer.vue +356 -0
  129. package/src/components/report/report-viewer.vue +128 -0
  130. package/src/components/report/style-designer.scss +583 -0
  131. package/src/components/report/style-hub.scss +292 -0
  132. package/src/components/report/style-viewer.scss +104 -0
  133. package/src/components/report/style.scss +3 -0
  134. package/src/components/report/style.ts +20 -0
  135. package/src/components/report/use-report-designer.ts +547 -0
  136. package/src/components/report/use-report-viewer.ts +79 -0
  137. package/src/components/sheet/__test__/formula-bar.test.ts +474 -0
  138. package/src/components/sheet/__test__/import-file.test.ts +183 -0
  139. package/src/components/sheet/__test__/insert-count-menu-item.test.ts +123 -0
  140. package/src/components/sheet/__test__/insert-image-popup.test.ts +89 -0
  141. package/src/components/sheet/__test__/insert-image.test.ts +100 -0
  142. package/src/components/sheet/__test__/sheet-component.test.ts +993 -0
  143. package/src/components/sheet/__test__/sheet-context-menu.test.ts +206 -0
  144. package/src/components/sheet/__test__/use-formula-ref-select.test.ts +35 -0
  145. package/src/components/sheet/__test__/use-formula-suggest.test.ts +83 -0
  146. package/src/components/sheet/formula-bar.vue +473 -0
  147. package/src/components/sheet/formula-suggest-list.vue +64 -0
  148. package/src/components/sheet/import-file.ts +173 -0
  149. package/src/components/sheet/insert-count-menu-item.vue +69 -0
  150. package/src/components/sheet/insert-image.ts +90 -0
  151. package/src/components/sheet/parsing.ts +11 -0
  152. package/src/components/sheet/popup-helpers.ts +50 -0
  153. package/src/components/sheet/popups/border-popup.vue +93 -0
  154. package/src/components/sheet/popups/border-preset-glyph.vue +111 -0
  155. package/src/components/sheet/popups/export-popup.vue +52 -0
  156. package/src/components/sheet/popups/fill-color-popup.vue +39 -0
  157. package/src/components/sheet/popups/find-popup.vue +111 -0
  158. package/src/components/sheet/popups/font-color-popup.vue +39 -0
  159. package/src/components/sheet/popups/font-size-popup.vue +52 -0
  160. package/src/components/sheet/popups/import.worker.ts +66 -0
  161. package/src/components/sheet/popups/insert-image-popup.vue +39 -0
  162. package/src/components/sheet/sheet-context-menu.ts +229 -0
  163. package/src/components/sheet/sheet-tabs.vue +162 -0
  164. package/src/components/sheet/sheet-toolbar.vue +91 -0
  165. package/src/components/sheet/sheet.vue +211 -0
  166. package/src/components/sheet/style.scss +737 -0
  167. package/src/components/sheet/style.ts +13 -0
  168. package/src/components/sheet/use-find-replace.ts +200 -0
  169. package/src/components/sheet/use-formula-ref-select.ts +34 -0
  170. package/src/components/sheet/use-formula-suggest.ts +150 -0
  171. package/src/components/sheet/use-sheet-grid.ts +247 -0
  172. package/src/components/sheet/use-sheet-state.ts +161 -0
  173. package/src/components/sheet/use-sheet-tabs-bar.ts +115 -0
  174. package/src/components/sheet/use-tool-groups.ts +61 -0
  175. package/src/components/sheet/use-tool-popup.ts +150 -0
  176. package/src/components/sheet/use-toolbar-scroll.ts +95 -0
  177. package/src/env.d.ts +11 -0
  178. package/src/index.ts +39 -14
  179. package/src/report/__test__/binding.test.ts +218 -0
  180. package/src/report/__test__/connector.test.ts +218 -0
  181. package/src/report/__test__/export-xlsx.test.ts +118 -0
  182. package/src/report/__test__/filter-bar.test.ts +58 -0
  183. package/src/report/__test__/params.test.ts +156 -0
  184. package/src/report/__test__/render.test.ts +728 -0
  185. package/src/report/__test__/rules.test.ts +131 -0
  186. package/src/report/__test__/template.test.ts +355 -0
  187. package/src/report/binding.ts +243 -0
  188. package/src/report/connector.ts +205 -0
  189. package/src/report/export-xlsx.ts +118 -0
  190. package/src/report/filter-bar.ts +36 -0
  191. package/src/report/index.ts +13 -0
  192. package/src/report/params.ts +96 -0
  193. package/src/report/render/__test__/aggregate.test.ts +16 -0
  194. package/src/report/render/__test__/coordinate.test.ts +405 -0
  195. package/src/report/render/aggregate.ts +240 -0
  196. package/src/report/render/builder.ts +211 -0
  197. package/src/report/render/coordinate.ts +1239 -0
  198. package/src/report/render/index.ts +30 -0
  199. package/src/report/render/style-resolver.ts +68 -0
  200. package/src/report/render/template-index.ts +200 -0
  201. package/src/report/rules/evaluate.ts +113 -0
  202. package/src/report/rules/index.ts +7 -0
  203. package/src/report/template.ts +141 -0
  204. package/src/report/types.ts +96 -0
  205. package/src/tools/__test__/builtin.test.ts +208 -66
  206. package/src/tools/__test__/context.test.ts +62 -2
  207. package/src/tools/builtin.ts +350 -6
  208. package/src/tools/context.ts +89 -11
  209. package/src/tools/download.ts +82 -0
  210. package/src/tools/export.worker.ts +61 -0
  211. package/src/tools/registry.ts +16 -1
  212. package/src/types/index.ts +2 -0
  213. package/src/types/report-designer.ts +36 -0
  214. package/src/types/report-viewer.ts +37 -0
  215. package/src/types/sheet.ts +26 -3
  216. package/dist/core/address.d.ts +0 -60
  217. package/dist/core/address.js +0 -142
  218. package/dist/core/address.js.map +0 -1
  219. package/dist/core/cell-store.d.ts +0 -61
  220. package/dist/core/cell-store.js +0 -135
  221. package/dist/core/cell-store.js.map +0 -1
  222. package/dist/core/command/default-registry.d.ts +0 -10
  223. package/dist/core/command/default-registry.js +0 -18
  224. package/dist/core/command/default-registry.js.map +0 -1
  225. package/dist/core/command/history.d.ts +0 -64
  226. package/dist/core/command/history.js +0 -127
  227. package/dist/core/command/history.js.map +0 -1
  228. package/dist/core/command/merge-cells.d.ts +0 -21
  229. package/dist/core/command/merge-cells.js +0 -74
  230. package/dist/core/command/merge-cells.js.map +0 -1
  231. package/dist/core/command/registry.d.ts +0 -17
  232. package/dist/core/command/registry.js +0 -26
  233. package/dist/core/command/registry.js.map +0 -1
  234. package/dist/core/command/set-cell-formula.d.ts +0 -17
  235. package/dist/core/command/set-cell-formula.js +0 -29
  236. package/dist/core/command/set-cell-formula.js.map +0 -1
  237. package/dist/core/command/set-cell-value.d.ts +0 -22
  238. package/dist/core/command/set-cell-value.js +0 -35
  239. package/dist/core/command/set-cell-value.js.map +0 -1
  240. package/dist/core/command/types.d.ts +0 -68
  241. package/dist/core/events.js +0 -29
  242. package/dist/core/events.js.map +0 -1
  243. package/dist/core/fill.d.ts +0 -34
  244. package/dist/core/fill.js +0 -320
  245. package/dist/core/fill.js.map +0 -1
  246. package/dist/core/formula/ast.d.ts +0 -58
  247. package/dist/core/formula/ast.js +0 -38
  248. package/dist/core/formula/ast.js.map +0 -1
  249. package/dist/core/formula/dependency-graph.d.ts +0 -70
  250. package/dist/core/formula/dependency-graph.js +0 -269
  251. package/dist/core/formula/dependency-graph.js.map +0 -1
  252. package/dist/core/formula/errors.d.ts +0 -25
  253. package/dist/core/formula/errors.js +0 -36
  254. package/dist/core/formula/errors.js.map +0 -1
  255. package/dist/core/formula/evaluator.d.ts +0 -41
  256. package/dist/core/formula/evaluator.js +0 -154
  257. package/dist/core/formula/evaluator.js.map +0 -1
  258. package/dist/core/formula/functions.d.ts +0 -30
  259. package/dist/core/formula/functions.js +0 -209
  260. package/dist/core/formula/functions.js.map +0 -1
  261. package/dist/core/formula/parser.d.ts +0 -7
  262. package/dist/core/formula/parser.js +0 -208
  263. package/dist/core/formula/parser.js.map +0 -1
  264. package/dist/core/formula/tokenizer.d.ts +0 -37
  265. package/dist/core/formula/tokenizer.js +0 -146
  266. package/dist/core/formula/tokenizer.js.map +0 -1
  267. package/dist/core/merge-manager.d.ts +0 -64
  268. package/dist/core/merge-manager.js +0 -111
  269. package/dist/core/merge-manager.js.map +0 -1
  270. package/dist/core/selection.d.ts +0 -31
  271. package/dist/core/selection.js +0 -62
  272. package/dist/core/selection.js.map +0 -1
  273. package/dist/core/sheet.d.ts +0 -116
  274. package/dist/core/sheet.js +0 -224
  275. package/dist/core/sheet.js.map +0 -1
  276. package/dist/core/workbook.d.ts +0 -43
  277. package/dist/core/workbook.js +0 -77
  278. package/dist/core/workbook.js.map +0 -1
  279. package/dist/grid/sheet-grid.d.ts +0 -81
  280. package/dist/grid/sheet-grid.js +0 -331
  281. package/dist/grid/sheet-grid.js.map +0 -1
  282. package/dist/grid/vtable-theme.js +0 -80
  283. package/dist/grid/vtable-theme.js.map +0 -1
  284. package/dist/tools/builtin.js.map +0 -1
  285. package/dist/tools/context.js.map +0 -1
  286. package/dist/tools/registry.js.map +0 -1
  287. package/dist/vue/index.d.ts +0 -2
  288. package/dist/vue/sheet.js +0 -211
  289. package/dist/vue/sheet.js.map +0 -1
  290. package/dist/vue/sheet.vue.d.ts +0 -24
  291. package/dist/vue/style.d.ts +0 -1
  292. package/dist/vue/style.js +0 -2
  293. package/dist/vue/style2.css +0 -93
  294. package/src/core/__test__/address.test.ts +0 -113
  295. package/src/core/__test__/cell-store.test.ts +0 -97
  296. package/src/core/__test__/command.test.ts +0 -377
  297. package/src/core/__test__/fill.test.ts +0 -140
  298. package/src/core/__test__/formula-adversarial.test.ts +0 -265
  299. package/src/core/__test__/formula-engine.test.ts +0 -470
  300. package/src/core/__test__/formula-functions.test.ts +0 -178
  301. package/src/core/__test__/formula-parser.test.ts +0 -160
  302. package/src/core/__test__/history.test.ts +0 -225
  303. package/src/core/__test__/merge-manager.test.ts +0 -106
  304. package/src/core/__test__/sheet.test.ts +0 -142
  305. package/src/core/address.ts +0 -166
  306. package/src/core/cell-store.ts +0 -173
  307. package/src/core/command/default-registry.ts +0 -15
  308. package/src/core/command/history.ts +0 -167
  309. package/src/core/command/index.ts +0 -7
  310. package/src/core/command/merge-cells.ts +0 -74
  311. package/src/core/command/registry.ts +0 -30
  312. package/src/core/command/set-cell-formula.ts +0 -29
  313. package/src/core/command/set-cell-value.ts +0 -38
  314. package/src/core/command/types.ts +0 -73
  315. package/src/core/events.ts +0 -37
  316. package/src/core/fill.ts +0 -314
  317. package/src/core/formula/ast.ts +0 -66
  318. package/src/core/formula/dependency-graph.ts +0 -329
  319. package/src/core/formula/errors.ts +0 -41
  320. package/src/core/formula/evaluator.ts +0 -219
  321. package/src/core/formula/functions.ts +0 -266
  322. package/src/core/formula/index.ts +0 -7
  323. package/src/core/formula/parser.ts +0 -198
  324. package/src/core/formula/tokenizer.ts +0 -160
  325. package/src/core/merge-manager.ts +0 -158
  326. package/src/core/selection.ts +0 -66
  327. package/src/core/sheet.ts +0 -282
  328. package/src/core/workbook.ts +0 -99
  329. package/src/grid/__test__/canvas-mock.ts +0 -49
  330. package/src/grid/__test__/setup.ts +0 -3
  331. package/src/grid/__test__/sheet-grid-formula.test.ts +0 -140
  332. package/src/grid/__test__/sheet-grid.test.ts +0 -275
  333. package/src/grid/sheet-grid.ts +0 -407
  334. package/src/grid/vtable-theme.ts +0 -61
  335. package/src/vue/__test__/sheet-component.test.ts +0 -267
  336. package/src/vue/sheet.vue +0 -235
  337. package/src/vue/style.scss +0 -94
  338. package/src/vue/style.ts +0 -2
  339. /package/src/{vue → components/sheet}/index.ts +0 -0
@@ -1,38 +0,0 @@
1
- import type { CellAddress } from '../address'
2
- import { cellDataEqual, isEmptyCellData, type CellData } from '../cell-store'
3
- import type { CellPatch, Command, CommandResult } from './types'
4
-
5
- /** SetCellValueCommand 的批量写入项 */
6
- export interface SetCellValueItem {
7
- addr: CellAddress
8
- /** 目标数据;空数据(无公式且 v 为 null/undefined/'')= 清除 */
9
- data?: CellData
10
- }
11
-
12
- export interface SetCellValueParams {
13
- /** 批量写入(供粘贴/填充复用);一次调用 = 一个 undo 单元 */
14
- items: SetCellValueItem[]
15
- }
16
-
17
- /**
18
- * 单元格写入命令:逐项解析锚点、捕获 before/after 差量并立即应用。
19
- * 与 before 相等的项跳过(不产生补丁);全部无变化时不入历史。
20
- */
21
- export const SetCellValueCommand: Command<SetCellValueParams> = {
22
- id: 'sheet.command.set-cell-value',
23
-
24
- handler(ctx, params): CommandResult {
25
- const patches: CellPatch[] = []
26
- for (const item of params.items) {
27
- const anchor = ctx.sheet.merges.resolveAnchor(item.addr)
28
- const before = ctx.sheet.store.getCell(anchor)
29
- const after = isEmptyCellData(item.data) ? undefined : item.data
30
- if (cellDataEqual(before, after)) continue
31
- const patch: CellPatch = { kind: 'cell', addr: anchor, before, after }
32
- ctx.applyPatch(patch, 'redo')
33
- patches.push(patch)
34
- }
35
- if (patches.length === 0) return { mutations: [] }
36
- return { mutations: [{ redo: patches, undo: [...patches].reverse() }] }
37
- }
38
- }
@@ -1,73 +0,0 @@
1
- import type { CellAddress, CellRange } from '../address'
2
- import type { CellData } from '../cell-store'
3
- import type { Sheet } from '../sheet'
4
-
5
- /**
6
- * 命令系统类型定义(决策 5:命令 + 逆操作补丁)。
7
- *
8
- * - 一切模型变更都是 Command,执行时产出 Mutation
9
- * - Patch 是受影响单元格 / 合并记录的 before/after 差量,不是全量快照
10
- * - 同一批 Patch 双向回放:redo 方向应用 after,undo 方向应用 before
11
- */
12
-
13
- /** 补丁回放方向 */
14
- export type PatchDirection = 'undo' | 'redo'
15
-
16
- /** 单元格数据差量补丁(原始存储语义;undefined = 该侧无此格) */
17
- export interface CellPatch {
18
- kind: 'cell'
19
- addr: CellAddress
20
- /**
21
- * 目标 sheet(跨表公式重算的派生补丁会落在其它 sheet 上);
22
- * 缺省 = 命令所在 sheet。回放时按此字段路由到目标 sheet 的变更通道。
23
- */
24
- sheet?: Sheet
25
- /** 变更前的数据(undefined = 原本为空格) */
26
- before?: CellData
27
- /** 变更后的数据(undefined = 变更后为空格) */
28
- after?: CellData
29
- }
30
-
31
- /** 合并记录差量补丁(before/after = 该侧是否存在此合并) */
32
- export interface MergePatch {
33
- kind: 'merge'
34
- range: CellRange
35
- before: boolean
36
- after: boolean
37
- }
38
-
39
- export type Patch = CellPatch | MergePatch
40
-
41
- /**
42
- * 一次命令执行产生的变更单元。
43
- * `redo` 按列表顺序应用;`undo` 取同一批补丁的逆序(命令实现负责构造,
44
- * 保证 undo 先撤销后登记的副作用,例如先移除新合并再恢复旧合并)。
45
- */
46
- export interface Mutation {
47
- redo: Patch[]
48
- undo: Patch[]
49
- }
50
-
51
- /** 命令执行结果 */
52
- export interface CommandResult<R = unknown> {
53
- /** 产生的 mutation 列表(空数组 = 无实际变更,不入历史) */
54
- mutations: Mutation[]
55
- /** 命令附带返回值(如 MergeCellsCommand 返回最终生效区域) */
56
- result?: R
57
- }
58
-
59
- /** 命令执行上下文 */
60
- export interface CommandContext {
61
- sheet: Sheet
62
- /**
63
- * 应用单个补丁。命令 handler 执行时对 redo 补丁逐项调用;
64
- * HistoryManager 回放 undo/redo 亦走此路径,保证只有一条变更通道。
65
- */
66
- applyPatch(patch: Patch, direction: PatchDirection): void
67
- }
68
-
69
- /** 命令:id + handler */
70
- export interface Command<P = unknown, R = unknown> {
71
- readonly id: string
72
- handler(ctx: CommandContext, params: P): CommandResult<R> | undefined
73
- }
@@ -1,37 +0,0 @@
1
- /**
2
- * 包内轻量类型化事件发射器(core 内部基建,不对外导出实现细节)。
3
- */
4
-
5
- export type EventHandler<T> = (payload: T) => void
6
-
7
- export class TypedEventEmitter<EventMap extends Record<string, unknown>> {
8
- private handlers = new Map<keyof EventMap, Set<EventHandler<EventMap[keyof EventMap]>>>()
9
-
10
- /** 订阅事件,返回取消订阅函数 */
11
- on<K extends keyof EventMap>(type: K, handler: EventHandler<EventMap[K]>): () => void {
12
- let set = this.handlers.get(type)
13
- if (!set) {
14
- set = new Set()
15
- this.handlers.set(type, set)
16
- }
17
- set.add(handler as EventHandler<EventMap[keyof EventMap]>)
18
- return () => this.off(type, handler)
19
- }
20
-
21
- off<K extends keyof EventMap>(type: K, handler: EventHandler<EventMap[K]>): void {
22
- this.handlers.get(type)?.delete(handler as EventHandler<EventMap[keyof EventMap]>)
23
- }
24
-
25
- emit<K extends keyof EventMap>(type: K, payload: EventMap[K]): void {
26
- const set = this.handlers.get(type)
27
- if (!set) return
28
- // Set 迭代天然容忍遍历中取消订阅
29
- for (const handler of set) {
30
- ;(handler as EventHandler<EventMap[K]>)(payload)
31
- }
32
- }
33
-
34
- clear(): void {
35
- this.handlers.clear()
36
- }
37
- }
package/src/core/fill.ts DELETED
@@ -1,314 +0,0 @@
1
- import type { CellAddress, CellRange } from './address'
2
- import { colIndexToName, colNameToIndex, createRange, iterateRange } from './address'
3
- import type { CellData, CellType } from './cell-store'
4
- import type { SetCellValueItem } from './command/set-cell-value'
5
-
6
- /** 填充柄拖拽方向(与 VTable drag_fill_handle_end 一致) */
7
- export type FillDirection = 'top' | 'bottom' | 'left' | 'right'
8
-
9
- export interface GenerateFillOptions {
10
- /** 拖拽前的源选区(模型坐标) */
11
- source: CellRange
12
- /** 需要写入的目标区(不含源区,模型坐标) */
13
- target: CellRange
14
- /** 填充方向 */
15
- direction: FillDirection
16
- /** 读取源区单元格(原始存储语义) */
17
- getCellData: (addr: CellAddress) => CellData | undefined
18
- }
19
-
20
- /**
21
- * 由源选区 + 拖拽后扩展选区 + 方向,计算需要填充的目标区(模型坐标)。
22
- * 算法对齐 VTable 官方 fill-handle 示例(扩展选区含源区,目标为扩展部分)。
23
- */
24
- export function computeFillTargetRange(
25
- source: CellRange,
26
- direction: FillDirection,
27
- expanded: CellRange
28
- ): CellRange | null {
29
- const src = createRange(source.start, source.end)
30
- const exp = createRange(expanded.start, expanded.end)
31
-
32
- if (direction === 'bottom') {
33
- if (exp.end.row <= src.end.row) return null
34
- return {
35
- start: { row: src.end.row + 1, col: src.start.col },
36
- end: { row: exp.end.row, col: src.end.col }
37
- }
38
- }
39
- if (direction === 'top') {
40
- if (exp.start.row >= src.start.row) return null
41
- return {
42
- start: { row: exp.start.row, col: src.start.col },
43
- end: { row: src.start.row - 1, col: src.end.col }
44
- }
45
- }
46
- if (direction === 'right') {
47
- if (exp.end.col <= src.end.col) return null
48
- return {
49
- start: { row: src.start.row, col: src.end.col + 1 },
50
- end: { row: src.end.row, col: exp.end.col }
51
- }
52
- }
53
- // left
54
- if (exp.start.col >= src.start.col) return null
55
- return {
56
- start: { row: src.start.row, col: exp.start.col },
57
- end: { row: src.end.row, col: src.start.col - 1 }
58
- }
59
- }
60
-
61
- /**
62
- * 生成填充写入项(tile / 数字日期等差 / 公式相对引用位移)。
63
- * 调用方一次 `sheet.setCells(items)` 即可(单 undo 单元)。
64
- */
65
- export function generateFill(options: GenerateFillOptions): SetCellValueItem[] {
66
- const { source, target, direction, getCellData } = options
67
- const src = createRange(source.start, source.end)
68
- const tgt = createRange(target.start, target.end)
69
- const srcRows = src.end.row - src.start.row + 1
70
- const srcCols = src.end.col - src.start.col + 1
71
- const vertical = direction === 'top' || direction === 'bottom'
72
-
73
- const seriesByLane = new Map<number, SeriesInfo | null>()
74
- if (vertical) {
75
- for (let col = src.start.col; col <= src.end.col; col++) {
76
- const values: number[] = []
77
- let cellType: CellType | undefined
78
- let ok = true
79
- for (let row = src.start.row; row <= src.end.row; row++) {
80
- const data = getCellData({ row, col })
81
- const num = readSeriesNumber(data)
82
- if (num == null) {
83
- ok = false
84
- break
85
- }
86
- values.push(num.value)
87
- cellType = num.t
88
- }
89
- seriesByLane.set(col, ok ? makeSeriesInfo(values, cellType) : null)
90
- }
91
- } else {
92
- for (let row = src.start.row; row <= src.end.row; row++) {
93
- const values: number[] = []
94
- let cellType: CellType | undefined
95
- let ok = true
96
- for (let col = src.start.col; col <= src.end.col; col++) {
97
- const data = getCellData({ row, col })
98
- const num = readSeriesNumber(data)
99
- if (num == null) {
100
- ok = false
101
- break
102
- }
103
- values.push(num.value)
104
- cellType = num.t
105
- }
106
- seriesByLane.set(row, ok ? makeSeriesInfo(values, cellType) : null)
107
- }
108
- }
109
-
110
- const items: SetCellValueItem[] = []
111
- for (const addr of iterateRange(tgt)) {
112
- const rowOffset = positiveMod(addr.row - src.start.row, srcRows)
113
- const colOffset = positiveMod(addr.col - src.start.col, srcCols)
114
- const srcAddr: CellAddress = { row: src.start.row + rowOffset, col: src.start.col + colOffset }
115
- const srcData = getCellData(srcAddr)
116
-
117
- if (srcData?.f != null && srcData.f !== '') {
118
- const deltaRow = addr.row - srcAddr.row
119
- const deltaCol = addr.col - srcAddr.col
120
- items.push({ addr, data: { f: shiftFormulaRefs(srcData.f, deltaRow, deltaCol) } })
121
- continue
122
- }
123
-
124
- const lane = vertical ? srcAddr.col : srcAddr.row
125
- const series = seriesByLane.get(lane)
126
- if (series) {
127
- const index = vertical ? addr.row - src.start.row : addr.col - src.start.col
128
- const value = series.first + index * series.delta
129
- items.push({ addr, data: { v: value, t: series.t ?? 'n' } })
130
- continue
131
- }
132
-
133
- // tile 复制(含空格 → 清除)
134
- items.push({ addr, data: cloneCellData(srcData) })
135
- }
136
- return items
137
- }
138
-
139
- interface SeriesInfo {
140
- first: number
141
- delta: number
142
- t?: CellType
143
- }
144
-
145
- function makeSeriesInfo(values: number[], t?: CellType): SeriesInfo {
146
- const first = values[0]!
147
- if (values.length === 1) {
148
- return { first, delta: 1, t }
149
- }
150
- const delta = (values[values.length - 1]! - first) / (values.length - 1)
151
- return { first, delta, t }
152
- }
153
-
154
- /** 可参与等差序列的数字/日期格;公式格与其它类型返回 null */
155
- function readSeriesNumber(data: CellData | undefined): { value: number; t?: CellType } | null {
156
- if (!data) return null
157
- if (data.f != null && data.f !== '') return null
158
- if (typeof data.v !== 'number' || !Number.isFinite(data.v)) return null
159
- if (data.t != null && data.t !== 'n' && data.t !== 'd') return null
160
- return { value: data.v, t: data.t }
161
- }
162
-
163
- function cloneCellData(data: CellData | undefined): CellData | undefined {
164
- if (!data) return undefined
165
- const cloned: CellData = {}
166
- if (data.v !== undefined) cloned.v = data.v
167
- if (data.t !== undefined) cloned.t = data.t
168
- if (data.f !== undefined) cloned.f = data.f
169
- return cloned
170
- }
171
-
172
- function positiveMod(n: number, mod: number): number {
173
- return ((n % mod) + mod) % mod
174
- }
175
-
176
- /**
177
- * 公式引用字符串级位移:尊重 `$` 绝对行列;出界 → `#REF!`。
178
- * 跳过双引号字符串字面量,避免改写文本中的 A1 片段。
179
- */
180
- export function shiftFormulaRefs(formula: string, deltaRow: number, deltaCol: number): string {
181
- if (deltaRow === 0 && deltaCol === 0) return formula
182
-
183
- let result = ''
184
- let i = 0
185
- while (i < formula.length) {
186
- const ch = formula[i]!
187
- if (ch === '"') {
188
- const end = skipExcelString(formula, i)
189
- result += formula.slice(i, end)
190
- i = end
191
- continue
192
- }
193
-
194
- const sheetMatch = matchSheetPrefix(formula, i)
195
- const addrStart = sheetMatch ? sheetMatch.end : i
196
- const addrMatch = matchCellOrRange(formula, addrStart)
197
- if (addrMatch && (sheetMatch || isRefBoundary(formula, i - 1))) {
198
- const sheetPrefix = sheetMatch ? formula.slice(sheetMatch.start, sheetMatch.end) : ''
199
- // 有 sheet 前缀时,前缀前也需是边界
200
- if (sheetMatch && !isRefBoundary(formula, sheetMatch.start - 1)) {
201
- result += ch
202
- i++
203
- continue
204
- }
205
- const shifted = shiftAddrPart(addrMatch.text, deltaRow, deltaCol)
206
- result += sheetPrefix + shifted
207
- i = addrMatch.end
208
- continue
209
- }
210
-
211
- result += ch
212
- i++
213
- }
214
- return result
215
- }
216
-
217
- function skipExcelString(text: string, start: number): number {
218
- // start 指向开引号;Excel 字符串内 "" 为转义
219
- let i = start + 1
220
- while (i < text.length) {
221
- if (text[i] === '"') {
222
- if (text[i + 1] === '"') {
223
- i += 2
224
- continue
225
- }
226
- return i + 1
227
- }
228
- i++
229
- }
230
- return text.length
231
- }
232
-
233
- function matchSheetPrefix(text: string, start: number): { start: number; end: number } | null {
234
- if (text[start] === "'") {
235
- let i = start + 1
236
- while (i < text.length) {
237
- if (text[i] === "'") {
238
- if (text[i + 1] === "'") {
239
- i += 2
240
- continue
241
- }
242
- if (text[i + 1] === '!') {
243
- return { start, end: i + 2 }
244
- }
245
- return null
246
- }
247
- i++
248
- }
249
- return null
250
- }
251
-
252
- // 简单表名:字母/下划线开头
253
- if (!/[A-Za-z_]/.test(text[start] ?? '')) return null
254
- let i = start + 1
255
- while (i < text.length && /[\w.]/.test(text[i]!)) i++
256
- if (text[i] === '!') return { start, end: i + 1 }
257
- return null
258
- }
259
-
260
- const CELL_REF_RE = /^(\$?)([A-Za-z]+)(\$?)([1-9]\d*)/
261
-
262
- function matchCellOrRange(text: string, start: number): { text: string; end: number } | null {
263
- const first = matchOneCell(text, start)
264
- if (!first) return null
265
- if (text[first.end] === ':') {
266
- const second = matchOneCell(text, first.end + 1)
267
- if (!second) return { text: first.text, end: first.end }
268
- return { text: text.slice(start, second.end), end: second.end }
269
- }
270
- return first
271
- }
272
-
273
- function matchOneCell(text: string, start: number): { text: string; end: number } | null {
274
- const slice = text.slice(start)
275
- const m = CELL_REF_RE.exec(slice)
276
- if (!m) return null
277
- const end = start + m[0].length
278
- const next = text[end]
279
- // 行号后紧跟字母 → 不是 A1;紧跟 `(` → 函数名(如 LOG10()
280
- if (next && (/[A-Za-z]/.test(next) || next === '(')) return null
281
- return { text: m[0], end }
282
- }
283
-
284
- function isRefBoundary(text: string, index: number): boolean {
285
- if (index < 0) return true
286
- const ch = text[index]!
287
- // 引用前不能是字母/数字(避免 FOOA1);`!` 已由 sheet 前缀消费
288
- return !/[A-Za-z0-9_$]/.test(ch)
289
- }
290
-
291
- function shiftAddrPart(part: string, deltaRow: number, deltaCol: number): string {
292
- if (part.includes(':')) {
293
- const [a, b] = part.split(':')
294
- const left = shiftOneRef(a!, deltaRow, deltaCol)
295
- const right = shiftOneRef(b!, deltaRow, deltaCol)
296
- if (left === '#REF!' || right === '#REF!') return '#REF!'
297
- return `${left}:${right}`
298
- }
299
- return shiftOneRef(part, deltaRow, deltaCol)
300
- }
301
-
302
- function shiftOneRef(ref: string, deltaRow: number, deltaCol: number): string {
303
- const m = CELL_REF_RE.exec(ref)
304
- if (!m) return ref
305
- const colAbs = m[1] === '$'
306
- const rowAbs = m[3] === '$'
307
- let col = colNameToIndex(m[2]!)
308
- let row = Number.parseInt(m[4]!, 10) - 1
309
- if (col < 0 || row < 0) return '#REF!'
310
- if (!colAbs) col += deltaCol
311
- if (!rowAbs) row += deltaRow
312
- if (col < 0 || row < 0) return '#REF!'
313
- return `${colAbs ? '$' : ''}${colIndexToName(col)}${rowAbs ? '$' : ''}${row + 1}`
314
- }
@@ -1,66 +0,0 @@
1
- import type { CellAddress, CellRange } from '../address'
2
-
3
- /**
4
- * 公式 AST 节点。
5
- * 引用节点携带可选 sheet 名(跨表引用);缺省 = 公式所在 sheet。
6
- */
7
-
8
- export type BinaryOperator =
9
- | '+'
10
- | '-'
11
- | '*'
12
- | '/'
13
- | '^'
14
- | '&'
15
- | '='
16
- | '<>'
17
- | '<'
18
- | '<='
19
- | '>'
20
- | '>='
21
-
22
- export type AstNode =
23
- | { kind: 'number'; value: number }
24
- | { kind: 'string'; value: string }
25
- | { kind: 'boolean'; value: boolean }
26
- /** 未知名称(如裸写的 Sheet2 / 未定义命名);求值为 #NAME? */
27
- | { kind: 'name'; name: string }
28
- | { kind: 'cell'; sheet?: string; addr: CellAddress }
29
- | { kind: 'range'; sheet?: string; range: CellRange }
30
- | { kind: 'unary'; op: '-' | '+'; operand: AstNode }
31
- /** 百分号后缀运算(除以 100) */
32
- | { kind: 'percent'; operand: AstNode }
33
- | { kind: 'binary'; op: BinaryOperator; left: AstNode; right: AstNode }
34
- | { kind: 'call'; name: string; args: AstNode[] }
35
-
36
- /** 公式中的引用(依赖图提取用):sheet 缺省由所属公式节点补齐 */
37
- export interface AstReference {
38
- sheet?: string
39
- range: CellRange
40
- }
41
-
42
- /** 遍历 AST,收集全部引用(单格视为 1×1 区域) */
43
- export function collectReferences(node: AstNode, out: AstReference[] = []): AstReference[] {
44
- switch (node.kind) {
45
- case 'cell':
46
- out.push({ sheet: node.sheet, range: { start: node.addr, end: node.addr } })
47
- break
48
- case 'range':
49
- out.push({ sheet: node.sheet, range: node.range })
50
- break
51
- case 'unary':
52
- case 'percent':
53
- collectReferences(node.operand, out)
54
- break
55
- case 'binary':
56
- collectReferences(node.left, out)
57
- collectReferences(node.right, out)
58
- break
59
- case 'call':
60
- for (const arg of node.args) collectReferences(arg, out)
61
- break
62
- default:
63
- break
64
- }
65
- return out
66
- }