@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,267 +0,0 @@
1
- import { afterEach, describe, expect, it } from 'vitest'
2
- import { createApp, h, nextTick, ref, type App } from 'vue'
3
-
4
- import { Workbook } from '../../core/workbook'
5
- import { USheet } from '../../index'
6
- import { registerTool, unregisterTool } from '../../tools/registry'
7
- import type { SheetExposed } from '../../types'
8
-
9
- const apps: App[] = []
10
- const containers: HTMLElement[] = []
11
-
12
- function mount(
13
- props: () => Record<string, unknown> = () => ({}),
14
- exposedRef?: { value: SheetExposed | undefined }
15
- ) {
16
- const el = document.createElement('div')
17
- el.style.width = '800px'
18
- el.style.height = '600px'
19
- document.body.appendChild(el)
20
- containers.push(el)
21
- const app = createApp({
22
- render: () =>
23
- h(USheet, {
24
- ...props(),
25
- ref: (value: unknown) => {
26
- if (exposedRef) exposedRef.value = value as SheetExposed | undefined
27
- }
28
- })
29
- })
30
- app.mount(el)
31
- apps.push(app)
32
- return { app, el }
33
- }
34
-
35
- function createWorkbook() {
36
- const workbook = new Workbook()
37
- workbook.addSheet('Sheet2')
38
- return workbook
39
- }
40
-
41
- function toolButton(el: HTMLElement, title: string): HTMLButtonElement | undefined {
42
- return [...el.querySelectorAll<HTMLButtonElement>('.u-sheet__tool')].find((button) =>
43
- button.textContent?.includes(title)
44
- )
45
- }
46
-
47
- function tabs(el: HTMLElement): HTMLButtonElement[] {
48
- return [...el.querySelectorAll<HTMLButtonElement>('.u-sheet__tab')]
49
- }
50
-
51
- afterEach(() => {
52
- while (apps.length) apps.pop()!.unmount()
53
- while (containers.length) containers.pop()!.remove()
54
- })
55
-
56
- describe('USheet 组件', () => {
57
- it('挂载:工具栏渲染内置工具(分组 + 分隔符),tabs 显示 sheet 列表,grid 挂载', async () => {
58
- const { el } = mount(() => ({ workbook: createWorkbook(), rows: 10, cols: 6 }))
59
- await nextTick()
60
-
61
- const tools = [...el.querySelectorAll('.u-sheet__tool')].map((button) =>
62
- button.textContent?.trim()
63
- )
64
- expect(tools).toEqual(['撤销', '重做', '合并', '取消合并'])
65
- // history 与 cell 两组之间一个分隔符
66
- expect(el.querySelectorAll('.u-sheet__toolbar-divider')).toHaveLength(1)
67
-
68
- expect(tabs(el).map((tab) => tab.textContent?.trim())).toEqual(['Sheet1', 'Sheet2'])
69
- expect(tabs(el)[0]!.classList.contains('is-active')).toBe(true)
70
-
71
- // VTable 已挂载到 grid 容器
72
- expect(el.querySelector('.u-sheet__grid canvas')).not.toBeNull()
73
- })
74
-
75
- it('内置 undo/redo 按钮随 history-change 置灰,点击等效快捷键', async () => {
76
- const workbook = createWorkbook()
77
- const sheet = workbook.activeSheet
78
- const { el } = mount(() => ({ workbook, rows: 10, cols: 6 }))
79
- await nextTick()
80
-
81
- const undoButton = toolButton(el, '撤销')!
82
- const redoButton = toolButton(el, '重做')!
83
- expect(undoButton.disabled).toBe(true)
84
- expect(redoButton.disabled).toBe(true)
85
-
86
- sheet.setCellValue({ row: 0, col: 0 }, 'x')
87
- await nextTick()
88
- expect(undoButton.disabled).toBe(false)
89
- expect(redoButton.disabled).toBe(true)
90
-
91
- undoButton.click()
92
- await nextTick()
93
- expect(sheet.getCellData({ row: 0, col: 0 })).toBeUndefined()
94
- expect(undoButton.disabled).toBe(true)
95
- expect(redoButton.disabled).toBe(false)
96
-
97
- redoButton.click()
98
- await nextTick()
99
- expect(sheet.getCellData({ row: 0, col: 0 })).toEqual({ v: 'x', t: 's' })
100
- })
101
-
102
- it('tab 切换:active 样式移动,工具上下文指向当前 sheet', async () => {
103
- const workbook = createWorkbook()
104
- const exposed: { value: SheetExposed | undefined } = { value: undefined }
105
- const { el } = mount(() => ({ workbook, rows: 10, cols: 6 }), exposed)
106
- await nextTick()
107
-
108
- expect(exposed.value?.getActiveSheet().name).toBe('Sheet1')
109
- expect(exposed.value?.getContext().sheetName).toBe('Sheet1')
110
-
111
- tabs(el)[1]!.click()
112
- await nextTick()
113
-
114
- expect(tabs(el)[1]!.classList.contains('is-active')).toBe(true)
115
- // grid 重建:旧 VTable 已 release,容器内只有一个 canvas
116
- expect(el.querySelectorAll('.u-sheet__grid canvas')).toHaveLength(1)
117
- expect(exposed.value?.getActiveSheet().name).toBe('Sheet2')
118
- // 工具上下文(与工具按钮同一门面)指向切换后的 sheet
119
- expect(exposed.value?.getContext().sheetName).toBe('Sheet2')
120
-
121
- // grid 已重建到 Sheet2:写入 Sheet2 应在表格可见
122
- workbook.getSheet('Sheet2')!.setCellValue({ row: 0, col: 0 }, 's2')
123
- await nextTick()
124
- expect(exposed.value?.getGrid()?.getTable().getCellValue(1, 1)).toBe('s2')
125
- })
126
-
127
- it('props 变更响应:showToolbar/showTabs 显隐,rows 变化重建 grid', async () => {
128
- const workbook = createWorkbook()
129
- const state = ref({ rows: 10, showToolbar: true, showTabs: true })
130
- const exposed: { value: SheetExposed | undefined } = { value: undefined }
131
- const { el } = mount(
132
- () => ({
133
- workbook,
134
- rows: state.value.rows,
135
- cols: 6,
136
- showToolbar: state.value.showToolbar,
137
- showTabs: state.value.showTabs
138
- }),
139
- exposed
140
- )
141
- await nextTick()
142
-
143
- const gridBefore = exposed.value?.getGrid()
144
- expect(gridBefore).toBeDefined()
145
-
146
- state.value = { ...state.value, showToolbar: false, showTabs: false }
147
- await nextTick()
148
- expect(el.querySelector('.u-sheet__toolbar')).toBeNull()
149
- expect(el.querySelector('.u-sheet__tabs')).toBeNull()
150
-
151
- state.value = { ...state.value, rows: 20 }
152
- await nextTick()
153
- const gridAfter = exposed.value?.getGrid()
154
- expect(gridAfter).toBeDefined()
155
- expect(gridAfter).not.toBe(gridBefore)
156
- })
157
-
158
- it('workbook prop 变更:tabs 与 grid 切到新工作簿', async () => {
159
- const workbook1 = createWorkbook()
160
- const workbook2 = new Workbook()
161
- workbook2.addSheet('数据表')
162
- const current = ref(workbook1)
163
- const { el } = mount(() => ({ workbook: current.value, rows: 10, cols: 6 }))
164
- await nextTick()
165
- expect(tabs(el).map((tab) => tab.textContent?.trim())).toEqual(['Sheet1', 'Sheet2'])
166
-
167
- current.value = workbook2
168
- await nextTick()
169
- expect(tabs(el).map((tab) => tab.textContent?.trim())).toEqual(['Sheet1', '数据表'])
170
- expect(el.querySelector('.u-sheet__grid canvas')).not.toBeNull()
171
- })
172
-
173
- it('注册表联动:运行时 register/unregister 工具即时增删按钮', async () => {
174
- const { el } = mount(() => ({ workbook: createWorkbook(), rows: 10, cols: 6 }))
175
- await nextTick()
176
- expect(toolButton(el, '临时工具')).toBeUndefined()
177
-
178
- registerTool({ id: 'temp-tool', title: '临时工具', onClick: () => {} })
179
- await nextTick()
180
- expect(toolButton(el, '临时工具')).toBeDefined()
181
-
182
- expect(unregisterTool('temp-tool')).toBe(true)
183
- await nextTick()
184
- expect(toolButton(el, '临时工具')).toBeUndefined()
185
- })
186
-
187
- it('无 props 默认挂载:内部自建工作簿(单 sheet),工具栏/tabs 正常', async () => {
188
- const { el } = mount()
189
- await nextTick()
190
- expect(tabs(el).map((tab) => tab.textContent?.trim())).toEqual(['Sheet1'])
191
- expect(el.querySelectorAll('.u-sheet__tool').length).toBeGreaterThan(0)
192
- expect(el.querySelector('.u-sheet__grid canvas')).not.toBeNull()
193
- })
194
-
195
- it('多实例并存:共享注册表,工具点击只作用于各自实例的活动 sheet', async () => {
196
- const workbook1 = new Workbook()
197
- const workbook2 = new Workbook()
198
- const first = mount(() => ({ workbook: workbook1, rows: 10, cols: 6 }))
199
- const second = mount(() => ({ workbook: workbook2, rows: 10, cols: 6 }))
200
- await nextTick()
201
-
202
- registerTool({
203
- id: 'mark-active',
204
- title: '标记当前格',
205
- onClick: (ctx) => {
206
- const active = ctx.getSelection().activeCell ?? { row: 0, col: 0 }
207
- ctx.setCellValue(active, 'marked')
208
- }
209
- })
210
- await nextTick()
211
-
212
- // 两个实例都渲染该工具(注册表全局共享)
213
- const button1 = toolButton(first.el, '标记当前格')
214
- const button2 = toolButton(second.el, '标记当前格')
215
- expect(button1).toBeDefined()
216
- expect(button2).toBeDefined()
217
-
218
- // 点击实例 2 的工具 → 只写实例 2 的 sheet(各自 SheetContext 绑定各自工作簿)
219
- workbook2.activeSheet.selectCell({ row: 2, col: 1 })
220
- await nextTick()
221
- button2!.click()
222
- await nextTick()
223
- expect(workbook2.activeSheet.getCellData({ row: 2, col: 1 })).toEqual({ v: 'marked', t: 's' })
224
- expect(workbook1.activeSheet.getCellData({ row: 2, col: 1 })).toBeUndefined()
225
-
226
- // 该写入经命令系统:实例 2 的 undo 可用且可撤销
227
- expect(workbook2.activeSheet.canUndo).toBe(true)
228
- workbook2.activeSheet.undo()
229
- expect(workbook2.activeSheet.getCellData({ row: 2, col: 1 })).toBeUndefined()
230
-
231
- unregisterTool('mark-active')
232
- })
233
-
234
- it('合并/取消合并按钮随选区联动,点击生效且可 undo', async () => {
235
- const workbook = new Workbook()
236
- const sheet = workbook.activeSheet
237
- const { el } = mount(() => ({ workbook, rows: 10, cols: 6 }))
238
- await nextTick()
239
-
240
- const mergeButton = toolButton(el, '合并')!
241
- const unmergeButton = toolButton(el, '取消合并')!
242
- // 无选区:两者禁用
243
- expect(mergeButton.disabled).toBe(true)
244
- expect(unmergeButton.disabled).toBe(true)
245
-
246
- // 拖选区域(经模型 API 模拟 grid 拖选回写)
247
- sheet.selectRange({ start: { row: 0, col: 0 }, end: { row: 1, col: 1 } })
248
- await nextTick()
249
- expect(mergeButton.disabled).toBe(false)
250
-
251
- mergeButton.click()
252
- await nextTick()
253
- expect(sheet.getCellInfo({ row: 1, col: 1 }).kind).toBe('merged-covered')
254
-
255
- // 选中合并锚点 → 取消合并可用
256
- sheet.selectCell({ row: 0, col: 0 })
257
- await nextTick()
258
- expect(unmergeButton.disabled).toBe(false)
259
-
260
- unmergeButton.click()
261
- await nextTick()
262
- expect(sheet.getCellInfo({ row: 1, col: 1 }).kind).toBe('normal')
263
-
264
- sheet.undo()
265
- expect(sheet.getCellInfo({ row: 1, col: 1 }).kind).toBe('merged-covered')
266
- })
267
- })
package/src/vue/sheet.vue DELETED
@@ -1,235 +0,0 @@
1
- <template>
2
- <div :class="cls.b">
3
- <div v-if="showToolbar" :class="cls.e('toolbar')">
4
- <template v-for="(group, groupIndex) in toolGroups" :key="group.name">
5
- <span v-if="groupIndex > 0" :class="cls.e('toolbar-divider')" />
6
- <button
7
- v-for="item in group.tools"
8
- :key="item.tool.id"
9
- type="button"
10
- :class="cls.e('tool')"
11
- :disabled="item.disabled"
12
- :title="item.tool.tooltip ?? item.tool.title"
13
- @click="handleToolClick(item.tool)"
14
- >
15
- <component :is="item.tool.icon" v-if="item.tool.icon" :class="cls.e('tool-icon')" />
16
- <span>{{ item.tool.title }}</span>
17
- </button>
18
- </template>
19
- </div>
20
-
21
- <div ref="gridRef" :class="cls.e('grid')" />
22
-
23
- <div v-if="showTabs" :class="cls.e('tabs')">
24
- <button
25
- v-for="(sheet, index) in sheetList"
26
- :key="sheet.name"
27
- type="button"
28
- :class="[cls.e('tab'), bem.is('active', index === activeIndex)]"
29
- @click="handleTabClick(index)"
30
- >
31
- {{ sheet.name }}
32
- </button>
33
- </div>
34
- </div>
35
- </template>
36
-
37
- <script lang="ts" setup>
38
- import { contextmenu } from '@veltra/desktop'
39
- import { bem } from '@veltra/utils'
40
- import { computed, onBeforeUnmount, onMounted, ref, shallowRef, useTemplateRef, watch } from 'vue'
41
-
42
- import { rangeContainsAddress } from '../core/address'
43
- import type { Sheet } from '../core/sheet'
44
- import { Workbook } from '../core/workbook'
45
- import { SheetGrid, type SheetGridContextMenuInfo } from '../grid/sheet-grid'
46
- import { createSheetContext } from '../tools/context'
47
- import { defaultToolRegistry, type SheetTool } from '../tools/registry'
48
- import type { SheetEmits, SheetProps, _SheetExposed } from '../types'
49
-
50
- defineOptions({ name: 'USheet' })
51
-
52
- const props = withDefaults(defineProps<SheetProps>(), {
53
- rows: 100,
54
- cols: 26,
55
- showToolbar: true,
56
- showTabs: true
57
- })
58
-
59
- const emit = defineEmits<SheetEmits>()
60
-
61
- const cls = bem('sheet')
62
-
63
- /** 工作簿:外部传入或内部自建(单 sheet) */
64
- const internalWorkbook = new Workbook()
65
- const workbook = computed(() => props.workbook ?? internalWorkbook)
66
-
67
- /** 激活 sheet 索引(镜像 workbook.activeSheetIndex,经事件同步) */
68
- const activeIndex = ref(workbook.value.activeSheetIndex)
69
- /** sheet 列表(tabs 渲染;由 sheets-change 同步) */
70
- const sheetList = shallowRef<Sheet[]>(workbook.value.getSheets())
71
- const activeSheet = computed(() => sheetList.value[activeIndex.value] ?? workbook.value.activeSheet)
72
-
73
- /** 工具上下文:动态解析活动 sheet,tab 切换后自动指向当前 sheet */
74
- const context = createSheetContext(() => activeSheet.value)
75
-
76
- const gridRef = useTemplateRef<HTMLElement>('gridRef')
77
- let grid: SheetGrid | undefined
78
-
79
- // ─── 工具栏状态刷新 ─────────────────────────────────────────
80
- // 工具 visible/disabled 是 (ctx) => boolean 纯函数,状态源变化时 bump 触发重算
81
-
82
- const stateTick = ref(0)
83
- const bump = (): void => {
84
- stateTick.value++
85
- }
86
-
87
- let disposeSheetEvents: (() => void)[] = []
88
- /** 订阅活动 sheet 的状态源(tab 切换 / 工作簿变更时重绑) */
89
- function bindSheetEvents(sheet: Sheet): void {
90
- for (const dispose of disposeSheetEvents) dispose()
91
- disposeSheetEvents = [
92
- sheet.on('selection-change', bump),
93
- sheet.on('history-change', bump),
94
- sheet.on('cell-change', bump),
95
- sheet.on('merge-change', bump)
96
- ]
97
- }
98
-
99
- let disposeWorkbookEvents: (() => void)[] = []
100
- function bindWorkbookEvents(wb: Workbook): void {
101
- for (const dispose of disposeWorkbookEvents) dispose()
102
- disposeWorkbookEvents = [
103
- wb.on('sheets-change', ({ sheets }) => {
104
- sheetList.value = sheets
105
- bump()
106
- }),
107
- wb.on('active-sheet-change', ({ sheet, index }) => {
108
- activeIndex.value = index
109
- bindSheetEvents(sheet)
110
- rebuildGrid()
111
- bump()
112
- emit('active-sheet-change', { sheet, index })
113
- })
114
- ]
115
- }
116
-
117
- const offRegistryChange = defaultToolRegistry.onChange(bump)
118
-
119
- // ─── 工具栏 ────────────────────────────────────────────────
120
-
121
- const toolGroups = computed(() => {
122
- void stateTick.value // 依赖状态源:选区 / 历史 / 单元格 / 合并 / 注册表
123
- return defaultToolRegistry
124
- .getGroups()
125
- .map((group) => ({
126
- name: group.name,
127
- tools: group.tools
128
- .map((tool) => ({
129
- tool,
130
- visible: tool.visible?.(context) ?? true,
131
- disabled: tool.disabled?.(context) ?? false
132
- }))
133
- .filter((item) => item.visible)
134
- }))
135
- .filter((group) => group.tools.length > 0)
136
- })
137
-
138
- function handleToolClick(tool: SheetTool): void {
139
- if (tool.disabled?.(context)) return
140
- tool.onClick(context)
141
- }
142
-
143
- // ─── sheet tabs ─────────────────────────────────────────────
144
-
145
- function handleTabClick(index: number): void {
146
- if (index === activeIndex.value) return
147
- const sheet = sheetList.value[index]
148
- if (sheet) workbook.value.activateSheet(sheet.name)
149
- }
150
-
151
- // ─── 右键菜单(合并 / 取消合并,语义对齐内置工具)────────────
152
-
153
- function handleContextMenu(info: SheetGridContextMenuInfo): void {
154
- // body 格:若点击落在当前选区外则先选中该格;行号/列头保留当前选区
155
- if (info.addr) {
156
- const inSelection = context
157
- .getSelection()
158
- .ranges.some((range) => rangeContainsAddress(range, info.addr!))
159
- if (!inSelection) context.selectCell(info.addr)
160
- }
161
-
162
- const mergeTool = defaultToolRegistry.get('merge')
163
- const unmergeTool = defaultToolRegistry.get('unmerge')
164
-
165
- contextmenu.pop({
166
- mousePosition: { x: info.x, y: info.y },
167
- width: 180,
168
- menus: [
169
- {
170
- label: '合并单元格',
171
- disabled: mergeTool?.disabled?.(context) ?? true,
172
- callback: () => mergeTool?.onClick(context)
173
- },
174
- {
175
- label: '取消合并单元格',
176
- disabled: unmergeTool?.disabled?.(context) ?? true,
177
- callback: () => unmergeTool?.onClick(context)
178
- }
179
- ]
180
- })
181
- }
182
-
183
- // ─── grid 生命周期 ──────────────────────────────────────────
184
-
185
- function rebuildGrid(): void {
186
- const container = gridRef.value
187
- if (!container) return
188
- grid?.release()
189
- grid = new SheetGrid({
190
- container,
191
- sheet: activeSheet.value,
192
- rows: props.rows,
193
- cols: props.cols,
194
- onContextMenu: handleContextMenu
195
- })
196
- }
197
-
198
- onMounted(() => {
199
- bindWorkbookEvents(workbook.value)
200
- bindSheetEvents(activeSheet.value)
201
- rebuildGrid()
202
- })
203
-
204
- watch(() => [props.rows, props.cols], rebuildGrid)
205
-
206
- watch(
207
- () => props.workbook,
208
- (wb, prev) => {
209
- if (wb === prev) return
210
- activeIndex.value = workbook.value.activeSheetIndex
211
- sheetList.value = workbook.value.getSheets()
212
- bindWorkbookEvents(workbook.value)
213
- bindSheetEvents(activeSheet.value)
214
- rebuildGrid()
215
- bump()
216
- }
217
- )
218
-
219
- onBeforeUnmount(() => {
220
- offRegistryChange()
221
- for (const dispose of disposeWorkbookEvents) dispose()
222
- for (const dispose of disposeSheetEvents) dispose()
223
- grid?.release()
224
- grid = undefined
225
- })
226
-
227
- const exposed: _SheetExposed = {
228
- workbook,
229
- getActiveSheet: () => activeSheet.value,
230
- getContext: () => context,
231
- getGrid: () => grid
232
- }
233
-
234
- defineExpose(exposed)
235
- </script>
@@ -1,94 +0,0 @@
1
- @use 'pkg:@veltra/styles/mixins' as m;
2
- @use 'pkg:@veltra/styles/functions' as fn;
3
-
4
- @include m.b(sheet) {
5
- display: flex;
6
- flex-direction: column;
7
- overflow: hidden;
8
- border: fn.use-var(border);
9
- border-radius: fn.use-var(radius, default);
10
- background-color: fn.use-var(bg-color, top);
11
-
12
- @include m.e(toolbar) {
13
- display: flex;
14
- align-items: center;
15
- flex-wrap: wrap;
16
- gap: fn.use-var(gap, small);
17
- padding: fn.use-var(gap, small);
18
- border-bottom: 1px solid fn.use-var(border, muted-color);
19
- }
20
-
21
- @include m.e(toolbar-divider) {
22
- width: 1px;
23
- align-self: stretch;
24
- margin: 2px 0;
25
- background-color: fn.use-var(border, muted-color);
26
- }
27
-
28
- @include m.e(tool) {
29
- display: inline-flex;
30
- align-items: center;
31
- gap: 4px;
32
- height: fn.use-var(form-component-height, small);
33
- padding: 0 8px;
34
- border: none;
35
- border-radius: fn.use-var(radius, small);
36
- background: transparent;
37
- color: fn.use-var(text-color, main);
38
- font-size: fn.use-var(font-size-main, small);
39
- white-space: nowrap;
40
- cursor: pointer;
41
- transition:
42
- background-color fn.use-var(transition, fast) fn.use-var(transition, ease),
43
- color fn.use-var(transition, fast) fn.use-var(transition, ease);
44
-
45
- &:hover:not(:disabled) {
46
- background-color: fn.use-var(bg-color, hover);
47
- }
48
-
49
- &:disabled {
50
- color: fn.use-var(text-color, disabled);
51
- cursor: not-allowed;
52
- }
53
- }
54
-
55
- @include m.e(tool-icon) {
56
- font-size: calc(fn.use-var(font-size-main, small) + 2px);
57
- }
58
-
59
- @include m.e(grid) {
60
- flex: 1;
61
- min-height: 0;
62
- }
63
-
64
- @include m.e(tabs) {
65
- display: flex;
66
- align-items: center;
67
- gap: 2px;
68
- padding: 2px fn.use-var(gap, small);
69
- border-top: 1px solid fn.use-var(border, muted-color);
70
- background-color: fn.use-var(bg-color, middle);
71
- }
72
-
73
- @include m.e(tab) {
74
- padding: 4px 12px;
75
- border: none;
76
- border-radius: fn.use-var(radius, small);
77
- background: transparent;
78
- color: fn.use-var(text-color, second);
79
- font-size: fn.use-var(font-size-main, small);
80
- cursor: pointer;
81
- transition:
82
- background-color fn.use-var(transition, fast) fn.use-var(transition, ease),
83
- color fn.use-var(transition, fast) fn.use-var(transition, ease);
84
-
85
- &:hover {
86
- background-color: fn.use-var(bg-color, hover);
87
- }
88
-
89
- @include m.is(active) {
90
- background-color: fn.use-var(bg-color, top);
91
- color: fn.use-var(color, primary);
92
- }
93
- }
94
- }
package/src/vue/style.ts DELETED
@@ -1,2 +0,0 @@
1
- import '@veltra/desktop/components/contextmenu/style'
2
- import './style.scss'
File without changes