@veltra/desktop 1.0.7 → 1.0.9

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 (247) hide show
  1. package/dist/components/action/action-group.vue.d.ts +1 -1
  2. package/dist/components/action/action.vue.d.ts +3 -3
  3. package/dist/components/action/style.js +3 -0
  4. package/dist/components/auto-complete/auto-complete.vue.d.ts +2 -2
  5. package/dist/components/auto-complete/style.js +5 -0
  6. package/dist/components/batch-edit/style.js +9 -0
  7. package/dist/components/breadcrumb/style2.css +0 -6
  8. package/dist/components/button/style.js +1 -0
  9. package/dist/components/cascade/cascade.js +15 -13
  10. package/dist/components/cascade/cascade.js.map +1 -1
  11. package/dist/components/cascade/cascade.vue.d.ts +3 -3
  12. package/dist/components/cascade/node.js.map +1 -1
  13. package/dist/components/cascade/style.js +7 -0
  14. package/dist/components/cascade/use-check.js +3 -2
  15. package/dist/components/cascade/use-check.js.map +1 -1
  16. package/dist/components/cascade/use-select.js +3 -3
  17. package/dist/components/cascade/use-select.js.map +1 -1
  18. package/dist/components/checkbox/style.js +1 -0
  19. package/dist/components/checkbox/style2.css +0 -8
  20. package/dist/components/checkbox-group/checkbox-group.vue.d.ts +2 -2
  21. package/dist/components/checkbox-group/style.js +1 -0
  22. package/dist/components/context-menu/style.js +1 -0
  23. package/dist/components/date-panel/date-panel.vue.d.ts +1 -1
  24. package/dist/components/date-picker/date-picker.js +9 -9
  25. package/dist/components/date-picker/date-picker.js.map +1 -1
  26. package/dist/components/date-picker/date-picker.vue.d.ts +2 -2
  27. package/dist/components/date-picker/style.js +3 -0
  28. package/dist/components/date-range-picker/date-range-picker.js +9 -9
  29. package/dist/components/date-range-picker/date-range-picker.js.map +1 -1
  30. package/dist/components/date-range-picker/date-range-picker.vue.d.ts +2 -2
  31. package/dist/components/date-range-picker/style.js +3 -0
  32. package/dist/components/dialog/style.js +2 -0
  33. package/dist/components/drawer/style.js +1 -0
  34. package/dist/components/drawer/style2.css +4 -16
  35. package/dist/components/empty/style.js +1 -0
  36. package/dist/components/expression-editor/style.js +6 -0
  37. package/dist/components/file-picker/file-picker.vue.d.ts +1 -1
  38. package/dist/components/file-picker/helper.js +19 -7
  39. package/dist/components/file-picker/helper.js.map +1 -1
  40. package/dist/components/file-viewer/file-viewer.js +294 -0
  41. package/dist/components/file-viewer/file-viewer.js.map +1 -0
  42. package/dist/components/file-viewer/file-viewer.vue.d.ts +42 -0
  43. package/dist/components/file-viewer/helper.js +185 -0
  44. package/dist/components/file-viewer/helper.js.map +1 -0
  45. package/dist/components/file-viewer/index.d.ts +1 -0
  46. package/dist/components/file-viewer/previewers/docx-previewer.js +76 -0
  47. package/dist/components/file-viewer/previewers/docx-previewer.js.map +1 -0
  48. package/dist/components/file-viewer/previewers/image-previewer.js +64 -0
  49. package/dist/components/file-viewer/previewers/image-previewer.js.map +1 -0
  50. package/dist/components/file-viewer/previewers/pdf-previewer.js +90 -0
  51. package/dist/components/file-viewer/previewers/pdf-previewer.js.map +1 -0
  52. package/dist/components/file-viewer/previewers/sheet-previewer.js +175 -0
  53. package/dist/components/file-viewer/previewers/sheet-previewer.js.map +1 -0
  54. package/dist/components/file-viewer/previewers/text-previewer.js +74 -0
  55. package/dist/components/file-viewer/previewers/text-previewer.js.map +1 -0
  56. package/dist/components/file-viewer/previewers/video-previewer.js +62 -0
  57. package/dist/components/file-viewer/previewers/video-previewer.js.map +1 -0
  58. package/dist/components/file-viewer/style.d.ts +1 -0
  59. package/dist/components/file-viewer/style.js +4 -0
  60. package/dist/components/file-viewer/style2.css +445 -0
  61. package/dist/components/float-button/style.js +1 -0
  62. package/dist/components/form/style.js +2 -0
  63. package/dist/components/form-item/style.js +1 -0
  64. package/dist/components/form-item/style2.css +2 -3
  65. package/dist/components/grid-input/grid-input.vue.d.ts +1 -1
  66. package/dist/components/index.d.ts +12 -9
  67. package/dist/components/input/input.vue.d.ts +2 -2
  68. package/dist/components/input/style.js +1 -0
  69. package/dist/components/layout/style.js +1 -0
  70. package/dist/components/list/style.js +1 -0
  71. package/dist/components/loading/style2.css +16 -20
  72. package/dist/components/menu/style.js +2 -0
  73. package/dist/components/menu/style2.css +0 -78
  74. package/dist/components/multi-select/multi-select-option.js +14 -10
  75. package/dist/components/multi-select/multi-select-option.js.map +1 -1
  76. package/dist/components/multi-select/multi-select.js +16 -19
  77. package/dist/components/multi-select/multi-select.js.map +1 -1
  78. package/dist/components/multi-select/multi-select.vue.d.ts +3 -3
  79. package/dist/components/multi-select/style.js +7 -0
  80. package/dist/components/multi-tree-select/multi-tree-select.vue.d.ts +4 -4
  81. package/dist/components/multi-tree-select/style.js +7 -0
  82. package/dist/components/notification/notification.vue.d.ts +1 -1
  83. package/dist/components/number-input/number-input.vue.d.ts +2 -2
  84. package/dist/components/number-input/style.js +1 -0
  85. package/dist/components/number-range-input/number-range-input.vue.d.ts +2 -2
  86. package/dist/components/number-range-input/style.js +1 -0
  87. package/dist/components/paginator/style.js +3 -0
  88. package/dist/components/palette/di.js.map +1 -1
  89. package/dist/components/palette/palette-alpha.js +7 -10
  90. package/dist/components/palette/palette-alpha.js.map +1 -1
  91. package/dist/components/palette/palette-hue.js +5 -7
  92. package/dist/components/palette/palette-hue.js.map +1 -1
  93. package/dist/components/palette/palette-sv.js +8 -10
  94. package/dist/components/palette/palette-sv.js.map +1 -1
  95. package/dist/components/palette/palette.js +22 -24
  96. package/dist/components/palette/palette.js.map +1 -1
  97. package/dist/components/palette/style.js +3 -0
  98. package/dist/components/password-input/password-input.vue.d.ts +1 -1
  99. package/dist/components/password-input/style.js +2 -0
  100. package/dist/components/pop-confirm/pop-confirm.vue.d.ts +1 -1
  101. package/dist/components/pop-confirm/style.js +3 -0
  102. package/dist/components/progress-nodes/progress-nodes.vue.d.ts +2 -2
  103. package/dist/components/progress-nodes/style2.css +79 -33
  104. package/dist/components/radio/style2.css +0 -8
  105. package/dist/components/radio-group/radio-group.vue.d.ts +2 -2
  106. package/dist/components/radio-group/style.js +1 -0
  107. package/dist/components/rich-text-editor/rich-text-editor.vue.d.ts +2 -2
  108. package/dist/components/select/select.js +14 -12
  109. package/dist/components/select/select.js.map +1 -1
  110. package/dist/components/select/select.vue.d.ts +2 -2
  111. package/dist/components/select/style.js +5 -0
  112. package/dist/components/select/style2.css +0 -20
  113. package/dist/components/slider/slider-thumb.js +10 -13
  114. package/dist/components/slider/slider-thumb.js.map +1 -1
  115. package/dist/components/slider/slider.js +12 -15
  116. package/dist/components/slider/slider.js.map +1 -1
  117. package/dist/components/steps/style.js +2 -0
  118. package/dist/components/steps/style2.css +28 -35
  119. package/dist/components/switch/style2.css +0 -3
  120. package/dist/components/table/di.js.map +1 -1
  121. package/dist/components/table/node/row.d.ts +10 -1
  122. package/dist/components/table/node/row.js +9 -0
  123. package/dist/components/table/node/row.js.map +1 -1
  124. package/dist/components/table/style.js +7 -0
  125. package/dist/components/table/style2.css +0 -41
  126. package/dist/components/table/table-body.js +25 -26
  127. package/dist/components/table/table-body.js.map +1 -1
  128. package/dist/components/table/table-cell.js +16 -9
  129. package/dist/components/table/table-cell.js.map +1 -1
  130. package/dist/components/table/table-row.js +78 -19
  131. package/dist/components/table/table-row.js.map +1 -1
  132. package/dist/components/table/table.js +76 -34
  133. package/dist/components/table/table.js.map +1 -1
  134. package/dist/components/table/use-fixed-columns.js +27 -8
  135. package/dist/components/table/use-fixed-columns.js.map +1 -1
  136. package/dist/components/table/use-rows.js +2 -2
  137. package/dist/components/table/use-rows.js.map +1 -1
  138. package/dist/components/table/use-table.js +25 -3
  139. package/dist/components/table/use-table.js.map +1 -1
  140. package/dist/components/table-editor/style.js +2 -0
  141. package/dist/components/tabs/index.d.ts +3 -1
  142. package/dist/components/tabs/style.js +2 -0
  143. package/dist/components/tabs/style2.css +169 -107
  144. package/dist/components/tabs/tabs-horizontal.js +133 -0
  145. package/dist/components/tabs/tabs-horizontal.js.map +1 -0
  146. package/dist/components/tabs/tabs-horizontal.vue.d.ts +29 -0
  147. package/dist/components/tabs/tabs-vertical.js +89 -0
  148. package/dist/components/tabs/tabs-vertical.js.map +1 -0
  149. package/dist/components/tabs/tabs-vertical.vue.d.ts +28 -0
  150. package/dist/components/tabs/tabs.js +75 -105
  151. package/dist/components/tabs/tabs.js.map +1 -1
  152. package/dist/components/tabs/tabs.vue.d.ts +9 -23
  153. package/dist/components/tabs/use-tabs-bar.js +105 -0
  154. package/dist/components/tabs/use-tabs-bar.js.map +1 -0
  155. package/dist/components/tag/style2.css +0 -6
  156. package/dist/components/textarea/style.js +1 -0
  157. package/dist/components/textarea/textarea.vue.d.ts +2 -2
  158. package/dist/components/theme/style.js +5 -0
  159. package/dist/components/tip/tip.vue.d.ts +2 -2
  160. package/dist/components/tree/style.js +4 -0
  161. package/dist/components/tree/style2.css +45 -23
  162. package/dist/components/tree/tree-node.js +50 -35
  163. package/dist/components/tree/tree-node.js.map +1 -1
  164. package/dist/components/tree/tree.js +27 -20
  165. package/dist/components/tree/tree.js.map +1 -1
  166. package/dist/components/tree/tree.vue.d.ts +1 -1
  167. package/dist/components/tree/use-check.js +52 -14
  168. package/dist/components/tree/use-check.js.map +1 -1
  169. package/dist/components/tree/use-tree-nodes.js +51 -24
  170. package/dist/components/tree/use-tree-nodes.js.map +1 -1
  171. package/dist/components/tree-select/style.js +4 -0
  172. package/dist/components/tree-select/tree-select.vue.d.ts +3 -3
  173. package/dist/components/watermark/watermark.vue.d.ts +1 -1
  174. package/dist/index.d.ts +57 -53
  175. package/dist/index.js +51 -48
  176. package/dist/types/file-viewer.d.ts +71 -0
  177. package/dist/types/index.d.ts +4 -3
  178. package/dist/types/tabs.d.ts +106 -14
  179. package/dist/types/tree.d.ts +6 -1
  180. package/package.json +32 -31
  181. package/src/components/breadcrumb/style.scss +0 -6
  182. package/src/components/cascade/cascade.vue +18 -18
  183. package/src/components/cascade/node.ts +4 -1
  184. package/src/components/cascade/use-check.ts +5 -4
  185. package/src/components/cascade/use-select.ts +4 -5
  186. package/src/components/checkbox/style.scss +0 -4
  187. package/src/components/date-picker/date-picker.vue +10 -9
  188. package/src/components/date-range-picker/date-range-picker.vue +12 -12
  189. package/src/components/drawer/style.scss +18 -11
  190. package/src/components/file-picker/helper.ts +21 -10
  191. package/src/components/file-viewer/file-viewer.vue +311 -0
  192. package/src/components/file-viewer/helper.ts +193 -0
  193. package/src/components/file-viewer/index.ts +1 -0
  194. package/src/components/file-viewer/previewers/docx-previewer.vue +78 -0
  195. package/src/components/file-viewer/previewers/image-previewer.vue +64 -0
  196. package/src/components/file-viewer/previewers/pdf-previewer.vue +90 -0
  197. package/src/components/file-viewer/previewers/sheet-previewer.vue +210 -0
  198. package/src/components/file-viewer/previewers/text-previewer.vue +76 -0
  199. package/src/components/file-viewer/previewers/video-previewer.vue +72 -0
  200. package/src/components/file-viewer/style.scss +504 -0
  201. package/src/components/file-viewer/style.ts +4 -0
  202. package/src/components/form-item/style.scss +2 -3
  203. package/src/components/index.ts +2 -0
  204. package/src/components/loading/style.scss +125 -126
  205. package/src/components/menu/style.scss +0 -31
  206. package/src/components/multi-select/multi-select-option.vue +16 -3
  207. package/src/components/multi-select/multi-select.vue +17 -9
  208. package/src/components/palette/di.ts +5 -3
  209. package/src/components/palette/palette-alpha.vue +7 -10
  210. package/src/components/palette/palette-hue.vue +5 -7
  211. package/src/components/palette/palette-sv.vue +12 -14
  212. package/src/components/palette/palette.vue +19 -21
  213. package/src/components/progress-nodes/style.scss +28 -22
  214. package/src/components/radio/style.scss +0 -4
  215. package/src/components/select/select.vue +21 -19
  216. package/src/components/select/style.scss +0 -12
  217. package/src/components/slider/slider-thumb.vue +11 -14
  218. package/src/components/slider/slider.vue +15 -15
  219. package/src/components/steps/style.scss +10 -10
  220. package/src/components/switch/style.scss +0 -4
  221. package/src/components/table/di.ts +20 -3
  222. package/src/components/table/node/row.ts +10 -1
  223. package/src/components/table/style.scss +0 -26
  224. package/src/components/table/table-body.vue +28 -33
  225. package/src/components/table/table-cell.vue +17 -9
  226. package/src/components/table/table-row.tsx +83 -17
  227. package/src/components/table/table.vue +73 -45
  228. package/src/components/table/use-fixed-columns.ts +46 -12
  229. package/src/components/table/use-rows.ts +14 -3
  230. package/src/components/table/use-table.ts +27 -3
  231. package/src/components/tabs/index.ts +2 -0
  232. package/src/components/tabs/style.scss +217 -134
  233. package/src/components/tabs/tabs-horizontal.vue +125 -0
  234. package/src/components/tabs/tabs-vertical.vue +75 -0
  235. package/src/components/tabs/tabs.vue +56 -127
  236. package/src/components/tabs/use-tabs-bar.ts +119 -0
  237. package/src/components/tag/style.scss +0 -6
  238. package/src/components/tree/style.scss +74 -29
  239. package/src/components/tree/tree-node.vue +10 -4
  240. package/src/components/tree/tree.vue +39 -12
  241. package/src/components/tree/use-check.ts +79 -23
  242. package/src/components/tree/use-tree-nodes.ts +85 -34
  243. package/src/types/file-viewer.ts +69 -0
  244. package/src/types/index.ts +1 -0
  245. package/src/types/tabs.ts +113 -19
  246. package/src/types/tree.ts +6 -1
  247. package/dist/types/index.js +0 -0
@@ -16,12 +16,36 @@ interface UseCheckReturned {
16
16
  toggleCheck: (node: TreeNode, check: boolean, ctrlKey?: boolean) => void
17
17
  }
18
18
 
19
+ /**
20
+ * 展开目标节点的所有祖先。返回是否发生了实际展开。
21
+ */
22
+ function expandAncestors(node: TreeNode): boolean {
23
+ let changed = false
24
+ node.bubbleSet((n) => {
25
+ if (n.parent) {
26
+ if (n.parent.expanded) return false
27
+ n.parent.expanded = true
28
+ changed = true
29
+ }
30
+ })
31
+ return changed
32
+ }
33
+
19
34
  export function useCheck(options: Options): UseCheckReturned {
20
35
  const { emit, props, nodeDict, getFlattedNodes } = options
21
36
 
22
37
  const checkedData = new Set<Record<string, any>>()
23
38
 
24
- function checkNode(node: TreeNode) {
39
+ /**
40
+ * 上一次回显使用的 value 集合(仅限 props.checked)。
41
+ * 用于在相同 `nodeDict` 下走差集回显,避免每次全量清空再重建。
42
+ */
43
+ let lastCheckedSet = new Set<unknown>()
44
+ /** 最近一次参与差集比较的 nodeDict 引用;引用变化时视为整棵树重建。 */
45
+ let lastDict: Map<any, TreeNode> | null = null
46
+
47
+ function checkNode(node: TreeNode): void {
48
+ if (node.checked) return
25
49
  node.checked = true
26
50
  if (node.parent) {
27
51
  node.parent.childrenCheckCount++
@@ -29,7 +53,8 @@ export function useCheck(options: Options): UseCheckReturned {
29
53
  checkedData.add(node.data)
30
54
  }
31
55
 
32
- function uncheckNode(node: TreeNode) {
56
+ function uncheckNode(node: TreeNode): void {
57
+ if (!node.checked) return
33
58
  node.checked = false
34
59
  if (node.parent) {
35
60
  node.parent.childrenCheckCount--
@@ -45,27 +70,56 @@ export function useCheck(options: Options): UseCheckReturned {
45
70
  // 回显
46
71
  watch(
47
72
  [() => props.checked, nodeDict],
48
- ([c, nodeDict]) => {
73
+ ([c, dict]) => {
49
74
  // 事件已经触发模型变更了,所以不再进行下面的计算
50
75
  if (checkedByEvent || !props.checkable) return
51
-
52
- if (!nodeDict.size) return
53
- checkedData.clear()
54
-
55
- c?.forEach((v) => {
56
- const node = nodeDict.get(v)
57
- if (node) {
58
- checkNode(node)
59
- node.bubbleSet((node) => {
60
- if (node.parent) {
61
- if (node.parent.expanded) return false
62
- node.parent.expanded = true
76
+ if (!dict.size) return
77
+
78
+ const nextSet = new Set<unknown>(c ?? [])
79
+
80
+ // 森林重建(dict 引用变化)→ 走全量清空重建路径,
81
+ // 因为所有 TreeNode 实例都是新的,上一轮缓存的 lastCheckedSet 失效。
82
+ const dictChanged = dict !== lastDict
83
+ if (dictChanged) {
84
+ checkedData.clear()
85
+ lastCheckedSet = new Set()
86
+ }
87
+
88
+ let mutated = false
89
+
90
+ // 取消:上一轮有但本轮没有的 value
91
+ for (const v of lastCheckedSet) {
92
+ if (!nextSet.has(v)) {
93
+ const node = dict.get(v)
94
+ if (node) {
95
+ uncheckNode(node)
96
+ mutated = true
97
+ }
98
+ }
99
+ }
100
+
101
+ // 新增:本轮有但上一轮没有的 value
102
+ let ancestorsExpanded = false
103
+ for (const v of nextSet) {
104
+ if (!lastCheckedSet.has(v) || dictChanged) {
105
+ const node = dict.get(v)
106
+ if (node) {
107
+ checkNode(node)
108
+ mutated = true
109
+ if (expandAncestors(node)) {
110
+ ancestorsExpanded = true
63
111
  }
64
- })
112
+ }
65
113
  }
66
- })
114
+ }
67
115
 
68
- getFlattedNodes()
116
+ lastCheckedSet = nextSet
117
+ lastDict = dict
118
+
119
+ // 只在真实发生变化时才触发扁平化,避免空转。
120
+ if (mutated || ancestorsExpanded) {
121
+ getFlattedNodes()
122
+ }
69
123
  },
70
124
  { immediate: true }
71
125
  )
@@ -134,11 +188,13 @@ export function useCheck(options: Options): UseCheckReturned {
134
188
 
135
189
  const checkedArr = Array.from(checkedData)
136
190
 
137
- emit(
138
- 'update:checked',
139
- checkedArr.map((item) => o(item).get(props.valueKey!)),
140
- checkedArr
141
- )
191
+ const valueKey = props.valueKey!
192
+ const nextValues = checkedArr.map((item) => o(item).get(valueKey) as unknown)
193
+
194
+ // 与外部 checked 保持差集缓存同步,避免下一次 watch 回调把刚勾选的值又误判为“新增”。
195
+ lastCheckedSet = new Set(nextValues)
196
+
197
+ emit('update:checked', nextValues as any[], checkedArr)
142
198
 
143
199
  nextTick(() => {
144
200
  checkedByEvent = false
@@ -1,5 +1,5 @@
1
1
  import { Forest } from '@cat-kit/core'
2
- import { computed, shallowRef, type ShallowRef, type ComputedRef } from 'vue'
2
+ import { computed, shallowRef, triggerRef, watch, type ShallowRef, type ComputedRef } from 'vue'
3
3
 
4
4
  import type { TreeProps } from '../../types'
5
5
  import { TreeNode } from './tree-node'
@@ -13,12 +13,29 @@ interface UseTreeNodesReturned {
13
13
  forest: ComputedRef<Forest<Record<string, unknown>, any>>
14
14
  getFlattedNodes: () => void
15
15
  nodeDict: ComputedRef<Map<string | number, TreeNode>>
16
+ /** 强制刷新 `nodes` 的订阅者(供字段级别变化但列表引用不变时手动触发)。 */
17
+ triggerNodes: () => void
16
18
  }
19
+
17
20
  export function useTreeNodes(options: Options): UseTreeNodesReturned {
18
21
  const { props } = options
19
22
 
20
- /** 森林 */
21
- const forest = computed(() => {
23
+ // forest / nodeDict 保持为 shallowRef 而非 computed:
24
+ // - computed 会因为任一 prop 变化(尤其是内联 disabledNode 函数)而整棵重建,
25
+ // 丢失 expanded/checked/visible 等运行时状态;
26
+ // - 显式 watch 仅在真正影响结构的输入变化时才重建,行为可控、可测量。
27
+ const forestRef = shallowRef<Forest<Record<string, unknown>, any>>(
28
+ new Forest<Record<string, unknown>, any>({
29
+ data: [],
30
+ childrenKey: props.childrenKey ?? 'children'
31
+ })
32
+ )
33
+
34
+ const nodeDictRef = shallowRef<Map<string | number, TreeNode>>(new Map())
35
+
36
+ const nodes = shallowRef<TreeNode[]>([])
37
+
38
+ function buildForest(): Forest<Record<string, unknown>, any> {
22
39
  const { disabledNode, expandAll = false, valueKey, labelKey } = props
23
40
  const childrenKey = props.childrenKey ?? 'children'
24
41
 
@@ -26,9 +43,8 @@ export function useTreeNodes(options: Options): UseTreeNodesReturned {
26
43
  data: Record<string, any>,
27
44
  index: number,
28
45
  depth: number,
29
- _f: Forest<Record<string, unknown>, any>,
30
46
  parent?: TreeNode
31
- ) {
47
+ ): TreeNode {
32
48
  const node = new TreeNode({
33
49
  data,
34
50
  index,
@@ -42,47 +58,82 @@ export function useTreeNodes(options: Options): UseTreeNodesReturned {
42
58
  }
43
59
 
44
60
  return new Forest<Record<string, unknown>, any>({
45
- data: props.data! as Record<string, unknown>[],
61
+ data: (props.data ?? []) as Record<string, unknown>[],
46
62
  childrenKey,
47
63
  createNode: disabledNode
48
- ? (data, index, depth, f, parent) => {
49
- const node = createNode(
50
- data as Record<string, any>,
51
- index,
52
- depth,
53
- f,
54
- parent as TreeNode
55
- )
64
+ ? (data, index, depth, _f, parent) => {
65
+ const node = createNode(data as Record<string, any>, index, depth, parent as TreeNode)
56
66
  if (data) {
57
- node.disabled = disabledNode(data, node) ?? false
67
+ node.disabled = disabledNode(data as Record<string, any>, node) ?? false
58
68
  }
59
69
  return node
60
70
  }
61
- : (data, index, depth, f, parent) =>
62
- createNode(data as Record<string, any>, index, depth, f, parent as TreeNode)
71
+ : (data, index, depth, _f, parent) =>
72
+ createNode(data as Record<string, any>, index, depth, parent as TreeNode)
63
73
  })
64
- })
65
-
66
- /** 碾平后的节点 */
67
- const nodes = shallowRef<TreeNode[]>([])
74
+ }
68
75
 
69
- /**
70
- * 节点的字典,key为指定的valueKey的值
71
- */
72
- const nodeDict = computed(() => {
73
- const dict = new Map<string | number, TreeNode>()
76
+ function rebuildForest(): void {
77
+ const nextForest = buildForest()
78
+ const nextDict = new Map<string | number, TreeNode>()
74
79
 
75
- forest.value.dfs((node) => {
76
- dict.set(node.key, node)
80
+ // 构建森林的同时一次 DFS 同步填充字典,
81
+ // 避免旧版 “forest computed → nodeDict computed” 两次完整遍历。
82
+ nextForest.dfs((node) => {
83
+ nextDict.set(node.key, node)
77
84
  })
78
85
 
79
- return dict
80
- })
86
+ forestRef.value = nextForest
87
+ nodeDictRef.value = nextDict
88
+
89
+ getFlattedNodes()
90
+ }
91
+
92
+ /** 按展开与可见性扁平化:仅一次 DFS。 */
93
+ function getFlattedNodes(): void {
94
+ const result: TreeNode[] = []
95
+ const roots = forestRef.value.roots as TreeNode[]
96
+
97
+ const stack: TreeNode[] = []
98
+ for (let i = roots.length - 1; i >= 0; i--) {
99
+ stack.push(roots[i]!)
100
+ }
101
+
102
+ while (stack.length) {
103
+ const node = stack.pop()!
104
+ if (!node.visible) continue
105
+ result.push(node)
106
+ if (node.expanded && node.children && node.children.length) {
107
+ for (let i = node.children.length - 1; i >= 0; i--) {
108
+ stack.push(node.children[i]!)
109
+ }
110
+ }
111
+ }
112
+
113
+ nodes.value = result
114
+ }
81
115
 
82
- /** 获取碾平后的节点 */
83
- function getFlattedNodes() {
84
- nodes.value = forest.value.flattenVisible((n) => n.expanded).filter((n) => n.visible)
116
+ function triggerNodes(): void {
117
+ triggerRef(nodes)
85
118
  }
86
119
 
87
- return { nodes, forest, getFlattedNodes, nodeDict }
120
+ watch(
121
+ [
122
+ () => props.data,
123
+ () => props.disabledNode,
124
+ () => props.childrenKey,
125
+ () => props.valueKey,
126
+ () => props.labelKey,
127
+ () => props.expandAll
128
+ ],
129
+ () => {
130
+ rebuildForest()
131
+ },
132
+ { immediate: true }
133
+ )
134
+
135
+ const forest = computed(() => forestRef.value)
136
+ const nodeDict = computed(() => nodeDictRef.value)
137
+
138
+ return { nodes, forest, getFlattedNodes, nodeDict, triggerNodes }
88
139
  }
@@ -0,0 +1,69 @@
1
+ import type { DeconstructValue } from '@veltra/utils'
2
+ import type { ShallowRef } from 'vue'
3
+
4
+ /** 预览器类别:xlsx 与 csv 归一为 sheet */
5
+ export type FileViewerKind = 'image' | 'video' | 'pdf' | 'sheet' | 'docx' | 'text'
6
+
7
+ /** 单个预览文件定义 */
8
+ export interface FileViewerItem {
9
+ /** 唯一 id;未提供时组件内部按索引生成 */
10
+ id?: string
11
+ /** 展示名(通常为原始文件名) */
12
+ name: string
13
+ /**
14
+ * 文件源:
15
+ * - string: URL(支持 http(s):、blob:、data:)
16
+ * - File / Blob / ArrayBuffer / Uint8Array: 二进制原始数据
17
+ */
18
+ src: string | File | Blob | ArrayBuffer | Uint8Array
19
+ /** 类型;缺省时根据 name 后缀推断 */
20
+ kind?: FileViewerKind
21
+ /** MIME type,仅用于原生 <video> / <img> / 下载时的类型提示 */
22
+ mime?: string
23
+ /** 文件大小(字节),可选,仅用于侧栏展示 */
24
+ size?: number
25
+ }
26
+
27
+ /** 文件预览组件属性 */
28
+ export interface FileViewerProps {
29
+ /** 待预览的文件列表 */
30
+ files: FileViewerItem[]
31
+ /** 当前激活文件 id(配合 v-model) */
32
+ modelValue?: string
33
+ /** 侧栏宽度(CSS length 或 false 隐藏侧栏),默认 280px */
34
+ sidebarWidth?: string | number | false
35
+ /** sheet 场景单文件最大渲染行数,默认 50000;0 表示不截断 */
36
+ sheetMaxRows?: number
37
+ /** 是否显示下载按钮,默认 true */
38
+ downloadable?: boolean
39
+ /**
40
+ * 全屏模态模式开关(支持 v-model:open)。
41
+ *
42
+ * - `undefined`(缺省):内嵌模式,组件在原位置渲染
43
+ * - `true` / `false`:进入模态模式,Teleport 到 body,按本值控制显隐
44
+ */
45
+ open?: boolean
46
+ /** 模态模式下点击背景是否关闭,默认 true */
47
+ closeOnClickBackdrop?: boolean
48
+ /** 模态模式下按 ESC 是否关闭,默认 true */
49
+ closeOnEsc?: boolean
50
+ }
51
+
52
+ /** 文件预览组件事件 */
53
+ export interface FileViewerEmits {
54
+ (e: 'update:modelValue', id: string): void
55
+ (e: 'update:open', value: boolean): void
56
+ (e: 'change', file: FileViewerItem): void
57
+ (e: 'error', err: { file: FileViewerItem; error: unknown }): void
58
+ }
59
+
60
+ /** 文件预览组件暴露的属性和方法(组件内部使用) */
61
+ export interface _FileViewerExposed {
62
+ activeId: ShallowRef<string | undefined>
63
+ activate: (id: string) => void
64
+ next: () => void
65
+ prev: () => void
66
+ }
67
+
68
+ /** 文件预览组件暴露的属性和方法(组件外部使用, 引用的值会被自动解构) */
69
+ export type FileViewerExposed = DeconstructValue<_FileViewerExposed>
@@ -77,3 +77,4 @@ export * from './auto-complete'
77
77
  export * from './switch'
78
78
  export * from './steps'
79
79
  export * from './rich-text-editor'
80
+ export * from './file-viewer'
package/src/types/tabs.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ComponentProps } from '@veltra/utils'
1
+ import type { ComponentProps, ComponentSize } from '@veltra/utils'
2
2
 
3
3
  export type TabItem = {
4
4
  /**
@@ -12,44 +12,138 @@ export type TabItem = {
12
12
  key: string
13
13
  /** 是否禁用 */
14
14
  disabled?: boolean
15
+ /**
16
+ * 单个标签是否可关闭
17
+ * @description 未显式设置时,沿用组件级 `closable` 属性
18
+ */
19
+ closable?: boolean
20
+ }
21
+
22
+ /** 水平标签栏(top/bottom)属性 */
23
+ export interface TabsHorizontalProps {
24
+ /** 组件尺寸 */
25
+ size?: ComponentSize
26
+ /** 当前激活的标签 key */
27
+ modelValue?: string
28
+ /** 标签项 */
29
+ items: TabItem[]
30
+ /**
31
+ * 是否可关闭
32
+ * @description 作为所有 TabItem 未显式 `closable` 时的默认值;禁用项不显示关闭按钮
33
+ * @default false
34
+ */
35
+ closable?: boolean
36
+ /**
37
+ * 是否填充父容器宽度
38
+ * @description 开启时 header 容器占满父容器宽度,背景完整铺开;tab-item 自身宽度保持不变
39
+ * @default false
40
+ */
41
+ block?: boolean
42
+ /**
43
+ * 是否开启圆角胶囊风格
44
+ * @default false
45
+ */
46
+ rounded?: boolean
47
+ /**
48
+ * 位置
49
+ * @default 'top'
50
+ */
51
+ position?: 'top' | 'bottom'
52
+ }
53
+
54
+ /** 垂直标签栏(left/right)属性 */
55
+ export interface TabsVerticalProps {
56
+ /** 组件尺寸 */
57
+ size?: ComponentSize
58
+ /** 当前激活的标签 key */
59
+ modelValue?: string
60
+ /** 标签项 */
61
+ items: TabItem[]
62
+ /**
63
+ * 是否可关闭
64
+ * @description 作为所有 TabItem 未显式 `closable` 时的默认值;禁用项不显示关闭按钮
65
+ * @default false
66
+ */
67
+ closable?: boolean
68
+ /**
69
+ * 是否开启圆角胶囊风格
70
+ * @default false
71
+ */
72
+ rounded?: boolean
73
+ /**
74
+ * 位置
75
+ * @default 'left'
76
+ */
77
+ position?: 'left' | 'right'
78
+ }
79
+
80
+ /** 水平标签栏事件 */
81
+ export interface TabsHorizontalEmits {
82
+ (e: 'update:modelValue', value: string): void
83
+ (e: 'click', item: TabItem, index: number): void
84
+ (e: 'close', item: TabItem, index: number): void
85
+ }
86
+
87
+ /** 垂直标签栏事件 */
88
+ export interface TabsVerticalEmits {
89
+ (e: 'update:modelValue', value: string): void
90
+ (e: 'click', item: TabItem, index: number): void
91
+ (e: 'close', item: TabItem, index: number): void
15
92
  }
16
93
 
17
94
  /** 标签页组件组件属性 */
18
95
  export interface TabsProps extends ComponentProps {
96
+ /** 当前激活的标签 key */
19
97
  modelValue?: string
20
98
  /** 标签项 */
21
99
  items: TabItem[]
100
+ /**
101
+ * 是否可关闭
102
+ * @description 作为所有 TabItem 未显式 `closable` 时的默认值;禁用项不显示关闭按钮
103
+ * @default false
104
+ */
105
+ closable?: boolean
106
+ /**
107
+ * 是否填充父容器宽度(仅在 position=top/bottom 时生效)
108
+ * @description 开启时 header 容器占满父容器宽度,背景完整铺开;tab-item 自身宽度保持不变
109
+ * @default false
110
+ */
111
+ block?: boolean
112
+ /**
113
+ * 是否开启圆角胶囊风格
114
+ * @default false
115
+ */
116
+ rounded?: boolean
22
117
  /** 显示位置 */
23
118
  position?: 'left' | 'right' | 'top' | 'bottom'
24
- /** 是否可以动态编辑 */
25
- editable?: boolean
26
119
  /**
27
120
  * 是否保活
28
121
  * @default false
29
122
  */
30
123
  keepAlive?: boolean
31
- /** 是否允许拖拽排序 */
32
- // sortable?: boolean
33
- // beforeLeave?: (
34
- // prev: string | number,
35
- // next: string | number
36
- // ) => void | boolean | Promise<void | boolean>
37
124
  }
38
125
 
39
126
  /** 标签页组件组件定义的事件 */
40
127
  export interface TabsEmits {
41
- (e: 'update:modelValue', value: string | number): void
42
- (e: 'update:items', items: TabItem[]): void
43
- (e: 'update:active', active: string | number): void
44
- (e: 'delete', item: TabItem, index: number): void
45
- (e: 'create'): void
128
+ (e: 'update:modelValue', value: string): void
46
129
  (e: 'click', item: TabItem, index: number): void
130
+ (e: 'close', item: TabItem, index: number): void
47
131
  }
48
132
 
49
- /** 标签页组件组件暴露的属性和方法(组件内部使用) */
133
+ /** 标签页组件暴露的属性和方法(组件内部使用) */
50
134
  export interface _TabsExposed {}
51
135
 
52
- /** 标签页组件组件暴露的属性和方法(组件外部使用, 引用的值会被自动解构) */
53
- export interface TabsExposed {
54
- delete(key: number | string): void
55
- }
136
+ /** 标签页组件暴露的属性和方法(组件外部使用, 引用的值会被自动解构) */
137
+ export interface TabsExposed {}
138
+
139
+ /** 水平标签栏暴露的属性和方法(组件内部使用) */
140
+ export interface _TabsHorizontalExposed {}
141
+
142
+ /** 水平标签栏暴露的属性和方法(组件外部使用) */
143
+ export interface TabsHorizontalExposed {}
144
+
145
+ /** 垂直标签栏暴露的属性和方法(组件内部使用) */
146
+ export interface _TabsVerticalExposed {}
147
+
148
+ /** 垂直标签栏暴露的属性和方法(组件外部使用) */
149
+ export interface TabsVerticalExposed {}
package/src/types/tree.ts CHANGED
@@ -76,7 +76,12 @@ export interface TreeEmit {
76
76
 
77
77
  export interface TreeNodeProps {
78
78
  node: TreeNode
79
- measureElement?: (el: any) => void
79
+ /**
80
+ * 虚拟项索引:对应 `nodes` 数组中的绝对位置。
81
+ * 需要传入以便在节点卸载时正确通知 `Virtualizer` 解绑,避免 size=0 的脏测量。
82
+ */
83
+ index?: number
84
+ measureElement?: (index: number, el: Element | null) => void
80
85
  }
81
86
 
82
87
  /** 树组件暴露的属性和方法(组件内部使用) */
File without changes