@veltra/desktop 1.0.8 → 1.0.10

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 (220) hide show
  1. package/dist/components/action/action-group.vue.d.ts +2 -2
  2. package/dist/components/action/action.vue.d.ts +3 -3
  3. package/dist/components/auto-complete/auto-complete.vue.d.ts +1 -1
  4. package/dist/components/batch-edit/batch-edit.js.map +1 -1
  5. package/dist/components/batch-edit/batch-edit.vue.d.ts +2 -2
  6. package/dist/components/batch-edit/use-edit.js.map +1 -1
  7. package/dist/components/button/button.js.map +1 -1
  8. package/dist/components/button/button.vue.d.ts +1 -1
  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 +7 -7
  12. package/dist/components/cascade/node.js.map +1 -1
  13. package/dist/components/cascade/use-check.js +3 -2
  14. package/dist/components/cascade/use-check.js.map +1 -1
  15. package/dist/components/cascade/use-select.js +3 -3
  16. package/dist/components/cascade/use-select.js.map +1 -1
  17. package/dist/components/checkbox-group/checkbox-group.js.map +1 -1
  18. package/dist/components/checkbox-group/checkbox-group.vue.d.ts +2 -2
  19. package/dist/components/date-panel/date-panel.js.map +1 -1
  20. package/dist/components/date-panel/date-panel.vue.d.ts +1 -1
  21. package/dist/components/date-picker/date-picker.js +9 -9
  22. package/dist/components/date-picker/date-picker.js.map +1 -1
  23. package/dist/components/date-picker/date-picker.vue.d.ts +1 -1
  24. package/dist/components/date-range-picker/date-range-picker.js +9 -9
  25. package/dist/components/date-range-picker/date-range-picker.js.map +1 -1
  26. package/dist/components/date-range-picker/date-range-picker.vue.d.ts +1 -1
  27. package/dist/components/drawer/drawer.js.map +1 -1
  28. package/dist/components/empty/empty.vue.d.ts +1 -1
  29. package/dist/components/expression-editor/expression-editor.js.map +1 -1
  30. package/dist/components/expression-editor/internal/editor-runtime/create-runtime.js.map +1 -1
  31. package/dist/components/expression-editor/internal/features/commands/register-command-packs.js.map +1 -1
  32. package/dist/components/expression-editor/internal/features/insertion/insertion-service.js.map +1 -1
  33. package/dist/components/expression-editor/use-decorators.js.map +1 -1
  34. package/dist/components/expression-editor/use-expression-drag-drop.js.map +1 -1
  35. package/dist/components/file-picker/file-picker.js.map +1 -1
  36. package/dist/components/file-picker/file-picker.vue.d.ts +1 -1
  37. package/dist/components/file-picker/helper.js +19 -7
  38. package/dist/components/file-picker/helper.js.map +1 -1
  39. package/dist/components/file-viewer/file-viewer.js +294 -0
  40. package/dist/components/file-viewer/file-viewer.js.map +1 -0
  41. package/dist/components/file-viewer/file-viewer.vue.d.ts +42 -0
  42. package/dist/components/file-viewer/helper.js +185 -0
  43. package/dist/components/file-viewer/helper.js.map +1 -0
  44. package/dist/components/file-viewer/index.d.ts +1 -0
  45. package/dist/components/file-viewer/previewers/docx-previewer.js +76 -0
  46. package/dist/components/file-viewer/previewers/docx-previewer.js.map +1 -0
  47. package/dist/components/file-viewer/previewers/image-previewer.js +64 -0
  48. package/dist/components/file-viewer/previewers/image-previewer.js.map +1 -0
  49. package/dist/components/file-viewer/previewers/pdf-previewer.js +90 -0
  50. package/dist/components/file-viewer/previewers/pdf-previewer.js.map +1 -0
  51. package/dist/components/file-viewer/previewers/sheet-previewer.js +175 -0
  52. package/dist/components/file-viewer/previewers/sheet-previewer.js.map +1 -0
  53. package/dist/components/file-viewer/previewers/text-previewer.js +74 -0
  54. package/dist/components/file-viewer/previewers/text-previewer.js.map +1 -0
  55. package/dist/components/file-viewer/previewers/video-previewer.js +62 -0
  56. package/dist/components/file-viewer/previewers/video-previewer.js.map +1 -0
  57. package/dist/components/file-viewer/style.d.ts +1 -0
  58. package/dist/components/file-viewer/style.js +4 -0
  59. package/dist/components/file-viewer/style2.css +445 -0
  60. package/dist/components/form/form-model.js +2 -1
  61. package/dist/components/form/form-model.js.map +1 -1
  62. package/dist/components/grid/grid.js.map +1 -1
  63. package/dist/components/grid/use-responsive.js.map +1 -1
  64. package/dist/components/grid-input/grid-input.vue.d.ts +1 -1
  65. package/dist/components/index.d.ts +12 -9
  66. package/dist/components/input/input.vue.d.ts +3 -3
  67. package/dist/components/list/list.js.map +1 -1
  68. package/dist/components/loading/directive.js.map +1 -1
  69. package/dist/components/menu/menu-item.js.map +1 -1
  70. package/dist/components/message/message2.js.map +1 -1
  71. package/dist/components/multi-select/multi-select-option.js +14 -10
  72. package/dist/components/multi-select/multi-select-option.js.map +1 -1
  73. package/dist/components/multi-select/multi-select.js +16 -19
  74. package/dist/components/multi-select/multi-select.js.map +1 -1
  75. package/dist/components/multi-select/multi-select.vue.d.ts +4 -4
  76. package/dist/components/multi-tree-select/multi-tree-select.vue.d.ts +7 -7
  77. package/dist/components/notification/index.js.map +1 -1
  78. package/dist/components/notification/notification.vue.d.ts +1 -1
  79. package/dist/components/number-input/number-input.js.map +1 -1
  80. package/dist/components/number-input/number-input.vue.d.ts +1 -1
  81. package/dist/components/number-range-input/number-range-input.vue.d.ts +1 -1
  82. package/dist/components/palette/color-transform.js.map +1 -1
  83. package/dist/components/palette/di.js.map +1 -1
  84. package/dist/components/palette/palette-alpha.js +7 -10
  85. package/dist/components/palette/palette-alpha.js.map +1 -1
  86. package/dist/components/palette/palette-hue.js +5 -7
  87. package/dist/components/palette/palette-hue.js.map +1 -1
  88. package/dist/components/palette/palette-sv.js +8 -10
  89. package/dist/components/palette/palette-sv.js.map +1 -1
  90. package/dist/components/palette/palette.js +22 -24
  91. package/dist/components/palette/palette.js.map +1 -1
  92. package/dist/components/password-input/password-input.vue.d.ts +1 -1
  93. package/dist/components/pop-confirm/pop-confirm.vue.d.ts +2 -2
  94. package/dist/components/progress/progress.js +1 -1
  95. package/dist/components/progress/progress.js.map +1 -1
  96. package/dist/components/progress-nodes/progress-nodes.js.map +1 -1
  97. package/dist/components/radio-group/radio-group.vue.d.ts +2 -2
  98. package/dist/components/rich-text-editor/rich-text-editor.js.map +1 -1
  99. package/dist/components/rich-text-editor/rich-text-editor.vue.d.ts +1 -1
  100. package/dist/components/rich-text-editor/toolbar.js.map +1 -1
  101. package/dist/components/scroll/scroll.js.map +1 -1
  102. package/dist/components/select/select.js +14 -12
  103. package/dist/components/select/select.js.map +1 -1
  104. package/dist/components/select/select.vue.d.ts +3 -3
  105. package/dist/components/slider/slider-thumb.js +10 -13
  106. package/dist/components/slider/slider-thumb.js.map +1 -1
  107. package/dist/components/slider/slider.js +12 -15
  108. package/dist/components/slider/slider.js.map +1 -1
  109. package/dist/components/table/di.js.map +1 -1
  110. package/dist/components/table/node/row.d.ts +10 -1
  111. package/dist/components/table/node/row.js +9 -0
  112. package/dist/components/table/node/row.js.map +1 -1
  113. package/dist/components/table/table-body.js +25 -26
  114. package/dist/components/table/table-body.js.map +1 -1
  115. package/dist/components/table/table-cell.js +16 -9
  116. package/dist/components/table/table-cell.js.map +1 -1
  117. package/dist/components/table/table-row.js +77 -19
  118. package/dist/components/table/table-row.js.map +1 -1
  119. package/dist/components/table/table.js +75 -34
  120. package/dist/components/table/table.js.map +1 -1
  121. package/dist/components/table/table.vue.d.ts +2 -2
  122. package/dist/components/table/use-columns.js +4 -0
  123. package/dist/components/table/use-columns.js.map +1 -1
  124. package/dist/components/table/use-fixed-columns.js +27 -8
  125. package/dist/components/table/use-fixed-columns.js.map +1 -1
  126. package/dist/components/table/use-rows.js +2 -2
  127. package/dist/components/table/use-rows.js.map +1 -1
  128. package/dist/components/table/use-table.js +50 -3
  129. package/dist/components/table/use-table.js.map +1 -1
  130. package/dist/components/tabs/index.d.ts +3 -1
  131. package/dist/components/tabs/style2.css +170 -107
  132. package/dist/components/tabs/tabs-horizontal.js +133 -0
  133. package/dist/components/tabs/tabs-horizontal.js.map +1 -0
  134. package/dist/components/tabs/tabs-horizontal.vue.d.ts +40 -0
  135. package/dist/components/tabs/tabs-vertical.js +89 -0
  136. package/dist/components/tabs/tabs-vertical.js.map +1 -0
  137. package/dist/components/tabs/tabs-vertical.vue.d.ts +38 -0
  138. package/dist/components/tabs/tabs.js +75 -105
  139. package/dist/components/tabs/tabs.js.map +1 -1
  140. package/dist/components/tabs/tabs.vue.d.ts +9 -23
  141. package/dist/components/tabs/use-tabs-bar.js +105 -0
  142. package/dist/components/tabs/use-tabs-bar.js.map +1 -0
  143. package/dist/components/text/text.js.map +1 -1
  144. package/dist/components/textarea/textarea.js.map +1 -1
  145. package/dist/components/textarea/textarea.vue.d.ts +4 -4
  146. package/dist/components/theme/theme.js.map +1 -1
  147. package/dist/components/tip/tip.vue.d.ts +1 -1
  148. package/dist/components/tree/style2.css +45 -23
  149. package/dist/components/tree/tree-node.js +50 -35
  150. package/dist/components/tree/tree-node.js.map +1 -1
  151. package/dist/components/tree/tree-node2.js.map +1 -1
  152. package/dist/components/tree/tree.js +27 -20
  153. package/dist/components/tree/tree.js.map +1 -1
  154. package/dist/components/tree/tree.vue.d.ts +5 -5
  155. package/dist/components/tree/use-check.js +52 -14
  156. package/dist/components/tree/use-check.js.map +1 -1
  157. package/dist/components/tree/use-tree-nodes.js +51 -24
  158. package/dist/components/tree/use-tree-nodes.js.map +1 -1
  159. package/dist/components/tree-select/tree-select.vue.d.ts +7 -7
  160. package/dist/index.d.ts +57 -53
  161. package/dist/index.js +51 -48
  162. package/dist/types/file-viewer.d.ts +71 -0
  163. package/dist/types/index.d.ts +3 -2
  164. package/dist/types/tabs.d.ts +106 -14
  165. package/dist/types/tree.d.ts +6 -1
  166. package/package.json +32 -31
  167. package/src/components/cascade/cascade.vue +18 -18
  168. package/src/components/cascade/node.ts +4 -1
  169. package/src/components/cascade/use-check.ts +5 -4
  170. package/src/components/cascade/use-select.ts +4 -5
  171. package/src/components/date-picker/date-picker.vue +10 -9
  172. package/src/components/date-range-picker/date-range-picker.vue +12 -12
  173. package/src/components/file-picker/helper.ts +21 -10
  174. package/src/components/file-viewer/file-viewer.vue +311 -0
  175. package/src/components/file-viewer/helper.ts +193 -0
  176. package/src/components/file-viewer/index.ts +1 -0
  177. package/src/components/file-viewer/previewers/docx-previewer.vue +78 -0
  178. package/src/components/file-viewer/previewers/image-previewer.vue +64 -0
  179. package/src/components/file-viewer/previewers/pdf-previewer.vue +90 -0
  180. package/src/components/file-viewer/previewers/sheet-previewer.vue +210 -0
  181. package/src/components/file-viewer/previewers/text-previewer.vue +76 -0
  182. package/src/components/file-viewer/previewers/video-previewer.vue +72 -0
  183. package/src/components/file-viewer/style.scss +504 -0
  184. package/src/components/file-viewer/style.ts +4 -0
  185. package/src/components/index.ts +2 -0
  186. package/src/components/multi-select/multi-select-option.vue +16 -3
  187. package/src/components/multi-select/multi-select.vue +17 -9
  188. package/src/components/palette/di.ts +5 -3
  189. package/src/components/palette/palette-alpha.vue +7 -10
  190. package/src/components/palette/palette-hue.vue +5 -7
  191. package/src/components/palette/palette-sv.vue +12 -14
  192. package/src/components/palette/palette.vue +19 -21
  193. package/src/components/progress/progress.vue +1 -1
  194. package/src/components/select/select.vue +21 -19
  195. package/src/components/slider/slider-thumb.vue +11 -14
  196. package/src/components/slider/slider.vue +15 -15
  197. package/src/components/table/di.ts +58 -43
  198. package/src/components/table/node/row.ts +10 -1
  199. package/src/components/table/table-body.vue +28 -33
  200. package/src/components/table/table-cell.vue +17 -9
  201. package/src/components/table/table-row.tsx +83 -17
  202. package/src/components/table/table.vue +72 -45
  203. package/src/components/table/use-fixed-columns.ts +46 -12
  204. package/src/components/table/use-rows.ts +14 -3
  205. package/src/components/table/use-table.ts +27 -3
  206. package/src/components/tabs/index.ts +2 -0
  207. package/src/components/tabs/style.scss +219 -133
  208. package/src/components/tabs/tabs-horizontal.vue +128 -0
  209. package/src/components/tabs/tabs-vertical.vue +77 -0
  210. package/src/components/tabs/tabs.vue +56 -127
  211. package/src/components/tabs/use-tabs-bar.ts +119 -0
  212. package/src/components/tree/style.scss +74 -29
  213. package/src/components/tree/tree-node.vue +10 -4
  214. package/src/components/tree/tree.vue +39 -12
  215. package/src/components/tree/use-check.ts +79 -23
  216. package/src/components/tree/use-tree-nodes.ts +85 -34
  217. package/src/types/file-viewer.ts +69 -0
  218. package/src/types/index.ts +1 -0
  219. package/src/types/tabs.ts +113 -19
  220. package/src/types/tree.ts +6 -1
@@ -2,21 +2,68 @@ import _sfc_main from "../icon/icon.js";
2
2
  import _sfc_main$1 from "../button/button.js";
3
3
  import { TableDIKey } from "./di.js";
4
4
  import _sfc_main$2 from "./table-cell.js";
5
- import { createVNode, defineComponent, inject, isVNode, mergeProps } from "vue";
6
- import { bem } from "@veltra/utils";
5
+ import { createVNode, defineComponent, inject, isVNode, mergeProps, onUnmounted } from "vue";
7
6
  import { ArrowRight } from "@veltra/icons/normal";
8
7
  //#region src/components/table/table-row.tsx
8
+ /**
9
+ * A3:行修饰类组合静态查找表。
10
+ *
11
+ * 位模式:bit2 = isCurrent, bit1 = checked, bit0 = expanded。
12
+ * 与 `bem.is('...')` 对于 `'current' | 'checked' | 'expanded'` 的输出完全等价,
13
+ * 直接从 index 读字符串,消除每行渲染期间的字符串拼接和 3 次 bem.is 调用。
14
+ *
15
+ * 放在模块顶层使所有 TableRow 实例共享一份引用(不会随 setup 重建)。
16
+ */
9
17
  function _isSlot(s) {
10
18
  return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !isVNode(s);
11
19
  }
20
+ const ROW_MOD_CLASS = [
21
+ "",
22
+ "is-expanded",
23
+ "is-checked",
24
+ "is-checked is-expanded",
25
+ "is-current",
26
+ "is-current is-expanded",
27
+ "is-current is-checked",
28
+ "is-current is-checked is-expanded"
29
+ ];
30
+ function rowModCls(row) {
31
+ return ROW_MOD_CLASS[(row.isCurrent ? 4 : 0) | (row.checked ? 2 : 0) | (row.expanded ? 1 : 0)];
32
+ }
12
33
  const UTableRow = defineComponent({
13
34
  name: "TableRow",
14
- props: ["row"],
35
+ props: {
36
+ row: {
37
+ type: Object,
38
+ required: true
39
+ },
40
+ index: {
41
+ type: Number,
42
+ required: true
43
+ }
44
+ },
15
45
  setup(props) {
16
- const { row } = props;
17
- const { cls, columnConfig, getColumnSlotsNode, toggleTreeRowExpand, getCellCtx, handleRowClick, handleCellClick, tableProps, measureElement } = inject(TableDIKey);
46
+ const { cls, columnConfig, getColumnSlotsNode, toggleTreeRowExpand, getCellCtx, handleRowClick, handleCellClick, tableProps, measureElement, getCellClass } = inject(TableDIKey);
47
+ const rowBaseCls = cls.e("row");
48
+ const expandToggleCls = cls.e("expand-toggle");
49
+ const expandSpaceCls = cls.e("expand-space");
50
+ const measureRefCache = /* @__PURE__ */ new Map();
51
+ const getMeasureRef = (index) => {
52
+ let ref = measureRefCache.get(index);
53
+ if (ref === void 0) {
54
+ ref = (el) => {
55
+ measureElement(index, el);
56
+ };
57
+ measureRefCache.set(index, ref);
58
+ }
59
+ return ref;
60
+ };
61
+ onUnmounted(() => {
62
+ measureRefCache.clear();
63
+ });
18
64
  const { columns, expandColumn } = columnConfig;
19
65
  return () => {
66
+ const { row } = props;
20
67
  const _expandColumn = expandColumn.value;
21
68
  let expandCell = null;
22
69
  if (_expandColumn) {
@@ -25,13 +72,13 @@ const UTableRow = defineComponent({
25
72
  if (!cellSpan || cellSpan.colspan && cellSpan.rowspan) {
26
73
  const marginLeft = tableProps.tree ? (row.depth - 1) * 14 : 0;
27
74
  expandCell = createVNode(_sfc_main$2, mergeProps({
28
- "column": _expandColumn,
75
+ "cellClass": getCellClass(_expandColumn),
29
76
  "left": _expandColumn.style.left,
30
77
  "right": _expandColumn.style.right,
31
78
  "key": row.uid + _expandColumn.key
32
79
  }, tableProps.mergeCell?.(expandCtx)), { default: () => [!row.isLeaf || tableProps.expandable && !row.isExpandRow ? createVNode(_sfc_main$1, {
33
80
  "text": true,
34
- "class": cls.e("expand-toggle"),
81
+ "class": expandToggleCls,
35
82
  "type": "primary",
36
83
  "size": "small",
37
84
  "circle": true,
@@ -41,19 +88,16 @@ const UTableRow = defineComponent({
41
88
  },
42
89
  "style": `margin-left: ${marginLeft}px`
43
90
  }, { default: () => [createVNode(_sfc_main, null, { default: () => [createVNode(ArrowRight, null, null)] })] }) : createVNode("i", {
44
- "class": cls.e("expand-space"),
91
+ "class": expandSpaceCls,
45
92
  "style": `margin-left: ${marginLeft}px`
46
93
  }, null), getColumnSlotsNode(expandCtx)] });
47
94
  }
48
95
  }
96
+ const mod = rowModCls(row);
49
97
  return createVNode("tr", {
50
- "class": [
51
- cls.e("row"),
52
- bem.is("expanded", row.expanded),
53
- bem.is("checked", row.checked)
54
- ],
98
+ "class": mod ? rowBaseCls + " " + mod : rowBaseCls,
55
99
  "onClick": (e) => handleRowClick(row, e),
56
- "ref": measureElement,
100
+ "ref": getMeasureRef(props.index),
57
101
  "key": row.uid
58
102
  }, [expandCell, columns.value.map((column) => {
59
103
  const cellCtx = getCellCtx(row, column);
@@ -61,7 +105,7 @@ const UTableRow = defineComponent({
61
105
  if (cellSpan && (!cellSpan.colspan || !cellSpan.rowspan)) return null;
62
106
  const cellNode = getColumnSlotsNode(cellCtx);
63
107
  return createVNode(_sfc_main$2, mergeProps({
64
- "column": column,
108
+ "cellClass": getCellClass(column),
65
109
  "left": column.style.left,
66
110
  "right": column.style.right,
67
111
  "key": row.uid + column.key,
@@ -73,10 +117,24 @@ const UTableRow = defineComponent({
73
117
  });
74
118
  const UExpandTableRow = defineComponent({
75
119
  name: "ExpandTableRow",
76
- props: ["row"],
120
+ props: {
121
+ row: {
122
+ type: Object,
123
+ required: true
124
+ },
125
+ index: {
126
+ type: Number,
127
+ required: true
128
+ }
129
+ },
77
130
  setup(props) {
78
131
  const { getExpandRowSlotsNode, cls, measureElement, columnConfig } = inject(TableDIKey);
79
132
  const { leafColumns } = columnConfig;
133
+ const rowBaseCls = cls.e("row");
134
+ const cellCls = cls.e("cell");
135
+ const measureRef = (el) => {
136
+ measureElement(props.index, el);
137
+ };
80
138
  return () => {
81
139
  const { row } = props;
82
140
  const node = getExpandRowSlotsNode({
@@ -86,11 +144,11 @@ const UExpandTableRow = defineComponent({
86
144
  rowData: row.data
87
145
  });
88
146
  return createVNode("tr", {
89
- "class": cls.e("row"),
90
- "ref": measureElement
147
+ "class": rowBaseCls,
148
+ "ref": measureRef
91
149
  }, [createVNode("td", {
92
150
  "colspan": leafColumns.value.length,
93
- "class": cls.e("cell")
151
+ "class": cellCls
94
152
  }, [node])]);
95
153
  };
96
154
  }
@@ -1 +1 @@
1
- {"version":3,"file":"table-row.js","names":["ArrowRight","bem","defineComponent","DefineComponent","VNodeRef","inject","JSX","TableRow","ITableRow","UButton","UIcon","TableDIKey","UTabelCell","_isSlot","s","Object","prototype","toString","call","_isVNode","UTableRow","row","name","props","setup","cls","columnConfig","getColumnSlotsNode","toggleTreeRowExpand","getCellCtx","handleRowClick","handleCellClick","tableProps","measureElement","columns","expandColumn","_expandColumn","value","expandCell","Element","expandCtx","cellSpan","mergeCell","colspan","rowspan","marginLeft","tree","depth","_createVNode","_mergeProps","style","left","right","uid","key","default","isLeaf","expandable","isExpandRow","e","stopPropagation","is","expanded","checked","map","column","cellCtx","cellNode","UExpandTableRow","getExpandRowSlotsNode","leafColumns","node","index","rowData","data","length"],"sources":["../../../src/components/table/table-row.tsx"],"sourcesContent":["import { ArrowRight } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { defineComponent, type DefineComponent, type VNodeRef } from 'vue'\nimport { inject } from 'vue'\nimport type { JSX } from 'vue/jsx-runtime'\n\nimport type { TableRow as ITableRow } from '../../types'\nimport { UButton } from '../button'\nimport { UIcon } from '../icon'\nimport { TableDIKey } from './di'\nimport UTabelCell from './table-cell.vue'\n\nexport const UTableRow: DefineComponent<{ row: ITableRow }> = defineComponent({\n name: 'TableRow',\n\n props: ['row'],\n\n setup(props) {\n const { row } = props\n\n const {\n cls,\n columnConfig,\n getColumnSlotsNode,\n toggleTreeRowExpand,\n getCellCtx,\n handleRowClick,\n handleCellClick,\n tableProps,\n measureElement\n } = inject(TableDIKey)!\n\n const { columns, expandColumn } = columnConfig\n\n return () => {\n const _expandColumn = expandColumn.value\n\n let expandCell: JSX.Element | null = null\n if (_expandColumn) {\n const expandCtx = getCellCtx(row, _expandColumn)\n const cellSpan = tableProps.mergeCell?.(expandCtx)\n\n if (!cellSpan || (cellSpan.colspan && cellSpan.rowspan)) {\n const marginLeft = tableProps.tree ? (row.depth - 1) * 14 : 0\n expandCell = (\n <UTabelCell\n column={_expandColumn}\n left={_expandColumn.style.left}\n right={_expandColumn.style.right}\n key={row.uid + _expandColumn.key}\n {...tableProps.mergeCell?.(expandCtx)}\n >\n {!row.isLeaf || (tableProps.expandable && !row.isExpandRow) ? (\n <UButton\n text\n class={cls.e('expand-toggle')}\n type='primary'\n size='small'\n circle\n onClick={(e) => {\n e.stopPropagation()\n toggleTreeRowExpand(row)\n }}\n style={`margin-left: ${marginLeft}px`}\n >\n <UIcon>\n <ArrowRight />\n </UIcon>\n </UButton>\n ) : (\n <i class={cls.e('expand-space')} style={`margin-left: ${marginLeft}px`}></i>\n )}\n\n {getColumnSlotsNode(expandCtx)}\n </UTabelCell>\n )\n }\n }\n\n return (\n <tr\n class={[cls.e('row'), bem.is('expanded', row.expanded), bem.is('checked', row.checked)]}\n onClick={(e) => handleRowClick(row, e)}\n ref={measureElement as VNodeRef}\n key={row.uid}\n >\n {expandCell}\n\n {columns.value.map((column) => {\n const cellCtx = getCellCtx(row, column)\n const cellSpan = tableProps.mergeCell?.(cellCtx)\n if (cellSpan && (!cellSpan.colspan || !cellSpan.rowspan)) {\n return null\n }\n\n const cellNode = getColumnSlotsNode(cellCtx)\n\n return (\n <UTabelCell\n column={column}\n left={column.style.left}\n right={column.style.right}\n key={row.uid + column.key}\n // @ts-ignore\n onClick={(e) => handleCellClick(row, column, e)}\n {...cellSpan}\n >\n {cellNode}\n </UTabelCell>\n )\n })}\n </tr>\n )\n }\n }\n})\n\nexport const UExpandTableRow = defineComponent({\n name: 'ExpandTableRow',\n props: ['row'],\n setup(props) {\n const { getExpandRowSlotsNode, cls, measureElement, columnConfig } = inject(TableDIKey)!\n const { leafColumns } = columnConfig\n\n return () => {\n const { row } = props\n const node = getExpandRowSlotsNode({\n row,\n index: row.index,\n columns: leafColumns.value,\n rowData: row.data\n })\n return (\n <tr class={cls.e('row')} ref={measureElement as VNodeRef}>\n <td colspan={leafColumns.value.length} class={cls.e('cell')}>\n {node}\n </td>\n </tr>\n )\n }\n }\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"table-row.js","names":["ArrowRight","defineComponent","DefineComponent","inject","onUnmounted","JSX","TableRow","ITableRow","UButton","UIcon","TableDIKey","UTabelCell","_isSlot","s","Object","prototype","toString","call","_isVNode","ROW_MOD_CLASS","const","rowModCls","row","i","isCurrent","checked","expanded","UTableRow","index","name","props","type","required","Number","setup","cls","columnConfig","getColumnSlotsNode","toggleTreeRowExpand","getCellCtx","handleRowClick","handleCellClick","tableProps","measureElement","getCellClass","rowBaseCls","e","expandToggleCls","expandSpaceCls","measureRefCache","Map","el","getMeasureRef","ref","get","undefined","Element","set","clear","columns","expandColumn","_expandColumn","value","expandCell","expandCtx","cellSpan","mergeCell","colspan","rowspan","marginLeft","tree","depth","_createVNode","_mergeProps","style","left","right","uid","key","default","isLeaf","expandable","isExpandRow","stopPropagation","mod","rowCls","map","column","cellCtx","cellNode","UExpandTableRow","getExpandRowSlotsNode","leafColumns","cellCls","measureRef","node","rowData","data","length"],"sources":["../../../src/components/table/table-row.tsx"],"sourcesContent":["import { ArrowRight } from '@veltra/icons/normal'\nimport { defineComponent, type DefineComponent } from 'vue'\nimport { inject, onUnmounted } from 'vue'\nimport type { JSX } from 'vue/jsx-runtime'\n\nimport type { TableRow as ITableRow } from '../../types'\nimport { UButton } from '../button'\nimport { UIcon } from '../icon'\nimport { TableDIKey } from './di'\nimport UTabelCell from './table-cell.vue'\n\n/**\n * A3:行修饰类组合静态查找表。\n *\n * 位模式:bit2 = isCurrent, bit1 = checked, bit0 = expanded。\n * 与 `bem.is('...')` 对于 `'current' | 'checked' | 'expanded'` 的输出完全等价,\n * 直接从 index 读字符串,消除每行渲染期间的字符串拼接和 3 次 bem.is 调用。\n *\n * 放在模块顶层使所有 TableRow 实例共享一份引用(不会随 setup 重建)。\n */\nconst ROW_MOD_CLASS: readonly string[] = [\n '',\n 'is-expanded',\n 'is-checked',\n 'is-checked is-expanded',\n 'is-current',\n 'is-current is-expanded',\n 'is-current is-checked',\n 'is-current is-checked is-expanded'\n] as const\n\nfunction rowModCls(row: ITableRow): string {\n const i = (row.isCurrent ? 4 : 0) | (row.checked ? 2 : 0) | (row.expanded ? 1 : 0)\n return ROW_MOD_CLASS[i]!\n}\n\nexport const UTableRow: DefineComponent<{ row: ITableRow; index: number }> = defineComponent({\n name: 'TableRow',\n\n props: {\n row: { type: Object as () => ITableRow, required: true },\n index: { type: Number, required: true }\n },\n\n setup(props) {\n const {\n cls,\n columnConfig,\n getColumnSlotsNode,\n toggleTreeRowExpand,\n getCellCtx,\n handleRowClick,\n handleCellClick,\n tableProps,\n measureElement,\n getCellClass\n } = inject(TableDIKey)!\n\n // A1:把 cls.e('row') / cls.e('expand-toggle') 等静态字符串提升到 setup 一次性计算,\n // 避免每次 render 重新走 `cls.e` 拼接。\n const rowBaseCls = cls.e('row')\n const expandToggleCls = cls.e('expand-toggle')\n const expandSpaceCls = cls.e('expand-space')\n\n // A2:measureRef 按 index 缓存闭包。\n // 行虚拟化下,同一 TableRow 实例的 props.index 大多稳定,但在虚拟化重排或展开行切换时\n // 仍会发生变化;把 (index) → refFn 缓存起来,既保证引用稳定(利于 Vue 的 ref diff),\n // 又避免在未来可能的\"同实例跨 index 复用\"情形下重复分配闭包。\n const measureRefCache = new Map<number, (el: unknown) => void>()\n const getMeasureRef = (index: number): ((el: unknown) => void) => {\n let ref = measureRefCache.get(index)\n if (ref === undefined) {\n ref = (el: unknown) => {\n measureElement(index, el as Element | null)\n }\n measureRefCache.set(index, ref)\n }\n return ref\n }\n onUnmounted(() => {\n measureRefCache.clear()\n })\n\n const { columns, expandColumn } = columnConfig\n\n return () => {\n const { row } = props\n const _expandColumn = expandColumn.value\n\n let expandCell: JSX.Element | null = null\n if (_expandColumn) {\n const expandCtx = getCellCtx(row, _expandColumn)\n const cellSpan = tableProps.mergeCell?.(expandCtx)\n\n if (!cellSpan || (cellSpan.colspan && cellSpan.rowspan)) {\n const marginLeft = tableProps.tree ? (row.depth - 1) * 14 : 0\n expandCell = (\n <UTabelCell\n cellClass={getCellClass(_expandColumn)}\n left={_expandColumn.style.left}\n right={_expandColumn.style.right}\n key={row.uid + _expandColumn.key}\n {...tableProps.mergeCell?.(expandCtx)}\n >\n {!row.isLeaf || (tableProps.expandable && !row.isExpandRow) ? (\n <UButton\n text\n class={expandToggleCls}\n type='primary'\n size='small'\n circle\n onClick={(e) => {\n e.stopPropagation()\n toggleTreeRowExpand(row)\n }}\n style={`margin-left: ${marginLeft}px`}\n >\n <UIcon>\n <ArrowRight />\n </UIcon>\n </UButton>\n ) : (\n <i class={expandSpaceCls} style={`margin-left: ${marginLeft}px`}></i>\n )}\n\n {getColumnSlotsNode(expandCtx)}\n </UTabelCell>\n )\n }\n }\n\n // A3:行 class 由 base + 3-bit 组合查找产出,避免 Vue 的 class 数组归一化开销。\n const mod = rowModCls(row)\n const rowCls = mod ? rowBaseCls + ' ' + mod : rowBaseCls\n\n return (\n <tr\n class={rowCls}\n onClick={(e) => handleRowClick(row, e)}\n ref={getMeasureRef(props.index)}\n key={row.uid}\n >\n {expandCell}\n\n {columns.value.map((column) => {\n const cellCtx = getCellCtx(row, column)\n const cellSpan = tableProps.mergeCell?.(cellCtx)\n if (cellSpan && (!cellSpan.colspan || !cellSpan.rowspan)) {\n return null\n }\n\n const cellNode = getColumnSlotsNode(cellCtx)\n\n return (\n <UTabelCell\n cellClass={getCellClass(column)}\n left={column.style.left}\n right={column.style.right}\n key={row.uid + column.key}\n // @ts-ignore\n onClick={(e) => handleCellClick(row, column, e)}\n {...cellSpan}\n >\n {cellNode}\n </UTabelCell>\n )\n })}\n </tr>\n )\n }\n }\n})\n\nexport const UExpandTableRow = defineComponent({\n name: 'ExpandTableRow',\n props: {\n row: { type: Object as () => ITableRow, required: true },\n index: { type: Number, required: true }\n },\n setup(props) {\n const { getExpandRowSlotsNode, cls, measureElement, columnConfig } = inject(TableDIKey)!\n const { leafColumns } = columnConfig\n\n const rowBaseCls = cls.e('row')\n const cellCls = cls.e('cell')\n\n const measureRef = (el: unknown) => {\n measureElement(props.index, el as Element | null)\n }\n\n return () => {\n const { row } = props\n const node = getExpandRowSlotsNode({\n row,\n index: row.index,\n columns: leafColumns.value,\n rowData: row.data\n })\n return (\n <tr class={rowBaseCls} ref={measureRef}>\n <td colspan={leafColumns.value.length} class={cellCls}>\n {node}\n </td>\n </tr>\n )\n }\n }\n})\n"],"mappings":"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"}
@@ -9,10 +9,21 @@ import { useColumns } from "./use-columns.js";
9
9
  import { useFixedColumns } from "./use-fixed-columns.js";
10
10
  import { useRows } from "./use-rows.js";
11
11
  import { useTable } from "./use-table.js";
12
- import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createVNode, defineComponent, nextTick, normalizeClass, normalizeStyle, openBlock, provide, renderList, renderSlot, shallowRef, toRef, unref, useSlots, useTemplateRef, watch, withCtx } from "vue";
13
- import { bem, setStyles, withUnit } from "@veltra/utils";
14
- import { useFallbackProps, useVirtual } from "@veltra/compositions";
12
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createVNode, defineComponent, normalizeClass, normalizeStyle, openBlock, provide, renderList, renderSlot, shallowRef, toRef, unref, useSlots, useTemplateRef, watch, withCtx } from "vue";
13
+ import { bem, withUnit } from "@veltra/utils";
14
+ import { useFallbackProps, useVirtualizer } from "@veltra/compositions";
15
15
  //#region src/components/table/table.vue
16
+ const _hoisted_1 = {
17
+ key: 0,
18
+ "aria-hidden": "true"
19
+ };
20
+ const _hoisted_2 = ["colspan"];
21
+ const _hoisted_3 = {
22
+ key: 1,
23
+ "aria-hidden": "true"
24
+ };
25
+ const _hoisted_4 = ["colspan"];
26
+ const LENGTH_DELTA_RATIO_TO_RESET_SCROLL = .5;
16
27
  const _sfc_main = /* @__PURE__ */ defineComponent({
17
28
  name: "Table",
18
29
  __name: "table",
@@ -60,9 +71,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
60
71
  const slots = useSlots();
61
72
  const cls = bem("table");
62
73
  const { size } = useFallbackProps([props], { size: "default" });
74
+ const scrollRef = shallowRef();
75
+ const beforeSpacerRef = useTemplateRef("beforeSpacerRef");
76
+ const afterSpacerRef = useTemplateRef("afterSpacerRef");
77
+ const isScrollingRelay = shallowRef(false);
63
78
  const { rows, toggleTreeRowExpand, allExpanded, toggleAllTreeRowExpand, rowForest, handleRowClick, handleCellClick, getRowByData } = useRows({
64
79
  props,
65
- emit
80
+ emit,
81
+ isScrolling: isScrollingRelay
66
82
  });
67
83
  const { createCheckColumn, createSelectColumn, clearChecked, clearSelected, checkedRows } = useCheck({
68
84
  size,
@@ -80,39 +96,47 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
80
96
  cls
81
97
  });
82
98
  const { leafColumns } = columnConfig;
83
- const { handleScroll, leftFixed, rightFixed } = useFixedColumns();
99
+ const { handleScroll, leftFixed, rightFixed } = useFixedColumns({ isScrolling: isScrollingRelay });
84
100
  const { getColumnSlotsNode, getExpandRowSlotsNode, getHeaderSlotsNode, getCellClass, getCellCtx, getHeaderCellClass } = useTable({
85
101
  props,
86
102
  cls,
87
103
  leftFixed,
88
104
  rightFixed
89
105
  });
90
- const scrollRef = shallowRef();
91
106
  const { showResizeLine, resizeLineRef, colgroupRef } = useColResize({
92
107
  scrollRef,
93
108
  leafColumns
94
109
  });
95
- const virtualCtx = useVirtual({
110
+ const { virtualizer, items, isScrolling } = useVirtualizer({
96
111
  count: computed(() => rows.value.length),
97
- scrollEl: computed(() => scrollRef.value?.containerRef ?? null),
98
- estimateSize: () => 52,
99
- virtualThreshold: toRef(props, "virtualThreshold")
112
+ scrollEl: () => scrollRef.value?.containerRef ?? null,
113
+ beforeEl: beforeSpacerRef,
114
+ afterEl: afterSpacerRef,
115
+ estimateSize: () => 41,
116
+ getItemKey: (i) => rows.value[i]?.uid ?? i
117
+ });
118
+ const virtualEnabled = computed(() => {
119
+ const t = props.virtualThreshold;
120
+ return t ? rows.value.length > t : true;
100
121
  });
101
- const { virtualList, totalHeight, virtualEnabled } = virtualCtx;
102
- const spaceHeight = computed(() => {
103
- if (virtualList.value.length) return totalHeight.value - virtualList.value[virtualList.value.length - 1].end + virtualList.value[0].start;
104
- return totalHeight.value;
122
+ watch(isScrolling, (v) => {
123
+ isScrollingRelay.value = v;
105
124
  });
106
- const spaceRef = shallowRef();
107
- watch(spaceHeight, (spaceHeight) => {
108
- nextTick(() => {
109
- spaceRef.value && setStyles(spaceRef.value, { height: spaceHeight ? `${spaceHeight}px` : void 0 });
110
- });
111
- }, { immediate: true });
112
- const tableBodyRef = useTemplateRef("tableBody");
113
- watch(() => props.data, () => {
114
- tableBodyRef.value?.setBodyTransform(0);
115
- scrollRef.value?.scrollTo({ y: 0 });
125
+ /**
126
+ * E1:数据替换时的条件置顶。
127
+ *
128
+ * 旧实现无差别地 `scrollTo({ y: 0 })`,在「行内增删 / 排序 / 单行更新」等
129
+ * 场景会把用户当前阅读位置跳走;仅在「翻页 / 显著数据集替换」时才需要复位。
130
+ *
131
+ * 判定阈值:|Δlen| / max(newLen, oldLen) ≥ 0.5,即行数变化量超过更大侧的一半时视为显著变化。
132
+ * 选择 0.5 是因为典型的分页/搜索场景会带来 50% 以上的行数差(通常完全替换数据集),
133
+ * 而行内追加 / 删除个位数通常只带来 <5% 的变化;两者区分度足够宽。
134
+ */
135
+ watch(() => props.data, (next, prev) => {
136
+ const nextLen = next?.length ?? 0;
137
+ const prevLen = prev?.length ?? 0;
138
+ const denom = Math.max(nextLen, prevLen, 1);
139
+ if (Math.abs(nextLen - prevLen) / denom >= LENGTH_DELTA_RATIO_TO_RESET_SCROLL) scrollRef.value?.scrollTo({ y: 0 });
116
140
  });
117
141
  provide(TableDIKey, {
118
142
  tableProps: props,
@@ -130,7 +154,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
130
154
  getCellCtx,
131
155
  getHeaderCellClass,
132
156
  toggleTreeRowExpand,
133
- ...virtualCtx
157
+ virtualList: items,
158
+ virtualEnabled,
159
+ measureElement: (index, el) => virtualizer.measureElement(index, el)
134
160
  });
135
161
  const tableFootRef = useTemplateRef("tableFoot");
136
162
  __expose({
@@ -170,7 +196,18 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
170
196
  }, null, 6);
171
197
  }), 128))], 512),
172
198
  createVNode(unref(TableHead)),
173
- createVNode(_sfc_main$2, { ref: "tableBody" }, createSlots({
199
+ createCommentVNode("\n 虚拟滚动上占位:替代 tbody transform,避免 table-layout: fixed 下列宽抖动。\n 高度由 useVirtualizer 命令式写入 `style.height`,不经过模板响应式绑定,\n 因此滚动窗口变化不会引起表格模板重渲染。\n "),
200
+ virtualEnabled.value ? (openBlock(), createElementBlock("tbody", _hoisted_1, [createElementVNode("tr", {
201
+ ref_key: "beforeSpacerRef",
202
+ ref: beforeSpacerRef
203
+ }, [createElementVNode("td", {
204
+ colspan: unref(leafColumns).length,
205
+ style: {
206
+ "padding": "0",
207
+ "border": "none"
208
+ }
209
+ }, null, 8, _hoisted_2)], 512)])) : createCommentVNode("v-if", true),
210
+ createVNode(_sfc_main$2, null, createSlots({
174
211
  default: withCtx(() => [renderSlot(_ctx.$slots, "body", {
175
212
  columns: unref(leafColumns),
176
213
  rows: unref(rows)
@@ -180,14 +217,18 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
180
217
  name: "empty",
181
218
  fn: withCtx(() => [renderSlot(_ctx.$slots, "empty")]),
182
219
  key: "0"
183
- } : void 0]), 1536),
184
- createCommentVNode(" 占用空间,用来撑开表格高度 "),
185
- unref(virtualEnabled) ? (openBlock(), createElementBlock("tbody", {
186
- key: 0,
187
- ref_key: "spaceRef",
188
- ref: spaceRef,
189
- style: { width: "1px" }
190
- }, null, 512)) : createCommentVNode("v-if", true),
220
+ } : void 0]), 1024),
221
+ createCommentVNode(" 虚拟滚动下占位(高度由 useVirtualizer 命令式写入) "),
222
+ virtualEnabled.value ? (openBlock(), createElementBlock("tbody", _hoisted_3, [createElementVNode("tr", {
223
+ ref_key: "afterSpacerRef",
224
+ ref: afterSpacerRef
225
+ }, [createElementVNode("td", {
226
+ colspan: unref(leafColumns).length,
227
+ style: {
228
+ "padding": "0",
229
+ "border": "none"
230
+ }
231
+ }, null, 8, _hoisted_4)], 512)])) : createCommentVNode("v-if", true),
191
232
  createVNode(_sfc_main$3, { ref: "tableFoot" }, {
192
233
  default: withCtx(() => [renderSlot(_ctx.$slots, "foot", {
193
234
  columns: unref(leafColumns),
@@ -1 +1 @@
1
- {"version":3,"file":"table.js","names":[],"sources":["../../../src/components/table/table.vue"],"sourcesContent":["<template>\n <u-scroll\n :class=\"[\n cls.b,\n cls.m(size),\n bem.is('border', border),\n bem.is('all-expanded', allExpanded),\n bem.is('text-ellipsis', textEllipsis)\n ]\"\n ref=\"scrollRef\"\n :content-class=\"cls.e('content')\"\n @scroll=\"handleScroll\"\n >\n <table :class=\"cls.e('wrap')\">\n <colgroup ref=\"colgroupRef\">\n <col\n v-for=\"column of leafColumns\"\n :key=\"column.key\"\n :class=\"column.fixed\"\n :style=\"{\n width: withUnit(column.width, 'px'),\n minWidth: withUnit(column.minWidth, 'px')\n }\"\n />\n </colgroup>\n <UTableHead />\n\n <u-table-body ref=\"tableBody\">\n <slot name=\"body\" :columns=\"leafColumns\" :rows=\"rows\" />\n\n <template #empty v-if=\"slots.empty\">\n <slot name=\"empty\" />\n </template>\n </u-table-body>\n\n <!-- 占用空间,用来撑开表格高度 -->\n <tbody v-if=\"virtualEnabled\" ref=\"spaceRef\" :style=\"{ width: '1px' }\"></tbody>\n\n <u-table-foot ref=\"tableFoot\">\n <slot name=\"foot\" :columns=\"leafColumns\" :rows=\"rows\" />\n </u-table-foot>\n </table>\n\n <slot name=\"append\" />\n\n <div v-if=\"showResizeLine\" :class=\"cls.e('resize-line')\" ref=\"resizeLineRef\"></div>\n\n <!-- <u-tip v-if=\"textEllipsis\" ref=\"tip\"> </u-tip> -->\n </u-scroll>\n</template>\n\n<script lang=\"ts\" setup>\nimport { useFallbackProps, useVirtual } from '@veltra/compositions'\nimport { bem, setStyles, withUnit } from '@veltra/utils'\nimport { computed, nextTick, provide, shallowRef, toRef, useTemplateRef, watch } from 'vue'\n\nimport type {\n TableProps,\n TableEmits,\n _TableExposed,\n TableColumnSlotsScope,\n ComponentSize,\n ScrollExposed,\n TableRowSlotsScope\n} from '../../types'\nimport { UScroll } from '../scroll'\nimport { TableDIKey } from './di'\nimport type { ColumnNode } from './node/col'\nimport type { TableRowNode } from './node/row'\nimport UTableBody from './table-body.vue'\nimport UTableFoot from './table-foot.vue'\n// import { UTip } from '../tip'\nimport UTableHead from './table-head'\nimport { useCheck } from './use-check'\nimport { useColResize } from './use-col-resize'\nimport { useColumns } from './use-columns'\nimport { useFixedColumns } from './use-fixed-columns'\nimport { useRows } from './use-rows'\nimport { useTable } from './use-table'\n\ndefineOptions({ name: 'Table' })\n\nconst props = withDefaults(defineProps<TableProps>(), {\n tree: false,\n stripe: true,\n textOverflow: 'line-break',\n virtualThreshold: 80\n})\nconst emit = defineEmits<TableEmits>()\n\nconst slots = defineSlots<{\n [key: `column:${string}`]: (props: TableColumnSlotsScope) => any\n [key: `header:${string}`]: (props: { column: ColumnNode }) => any\n 'row:expand'?: (props: TableRowSlotsScope) => any\n foot?: (props: { columns: ColumnNode[]; rows: TableRowNode[] }) => any\n body?: (props: { columns: ColumnNode[]; rows: TableRowNode[] }) => any\n empty?: () => any\n append?: () => any\n}>()\n\nconst cls = bem('table')\n\nconst { size } = useFallbackProps([props], { size: 'default' as ComponentSize })\n\n// 行\nconst {\n rows,\n toggleTreeRowExpand,\n allExpanded,\n toggleAllTreeRowExpand,\n rowForest,\n handleRowClick,\n handleCellClick,\n getRowByData\n} = useRows({ props, emit })\n\n// 选中\nconst { createCheckColumn, createSelectColumn, clearChecked, clearSelected, checkedRows } =\n useCheck({ size, props, rows, rowForest, emit, cls })\n\n// 列\nconst columnConfig = useColumns({\n props,\n createCheckColumn,\n createSelectColumn,\n toggleAllTreeRowExpand,\n cls\n})\n\nconst { leafColumns } = columnConfig\n\nconst { handleScroll, leftFixed, rightFixed } = useFixedColumns()\n\n// 在表格中提供的通用方法和属性\nconst {\n getColumnSlotsNode,\n getExpandRowSlotsNode,\n getHeaderSlotsNode,\n getCellClass,\n getCellCtx,\n getHeaderCellClass\n} = useTable({ props, cls, leftFixed, rightFixed })\n\nconst scrollRef = shallowRef<ScrollExposed>()\n\nconst { showResizeLine, resizeLineRef, colgroupRef } = useColResize({ scrollRef, leafColumns })\n\nconst virtualCtx = useVirtual({\n count: computed(() => rows.value.length),\n scrollEl: computed(() => scrollRef.value?.containerRef ?? null),\n estimateSize: () => 52,\n virtualThreshold: toRef(props, 'virtualThreshold')\n})\n\nconst { virtualList, totalHeight, virtualEnabled } = virtualCtx\n\nconst spaceHeight = computed(() => {\n if (virtualList.value.length) {\n return (\n totalHeight.value -\n virtualList.value[virtualList.value.length - 1]!.end +\n virtualList.value[0]!.start\n )\n }\n return totalHeight.value\n})\n\nconst spaceRef = shallowRef<HTMLElement>()\n\nwatch(\n spaceHeight,\n (spaceHeight) => {\n nextTick(() => {\n spaceRef.value &&\n setStyles(spaceRef.value, { height: spaceHeight ? `${spaceHeight}px` : undefined })\n })\n },\n { immediate: true }\n)\n\nconst tableBodyRef = useTemplateRef('tableBody')\nwatch(\n () => props.data,\n () => {\n tableBodyRef.value?.setBodyTransform(0)\n scrollRef.value?.scrollTo({ y: 0 })\n }\n)\n\n// const tipRef = useTemplateRef('tip')\n\nprovide(TableDIKey, {\n tableProps: props,\n tableSlots: slots,\n cls,\n rows,\n checkedRows,\n columnConfig,\n handleRowClick,\n handleCellClick,\n getColumnSlotsNode,\n getExpandRowSlotsNode,\n getHeaderSlotsNode,\n getCellClass,\n getCellCtx,\n getHeaderCellClass,\n // tipRef,\n toggleTreeRowExpand,\n ...virtualCtx\n})\n\nconst tableFootRef = useTemplateRef('tableFoot')\n\ndefineExpose<_TableExposed>({\n el: toRef(() => scrollRef.value?.el),\n clearChecked,\n clearSelected,\n getRowByData,\n getSummaryRow: () => tableFootRef.value!.getSummaryRow()\n})\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"table.js","names":[],"sources":["../../../src/components/table/table.vue"],"sourcesContent":["<template>\n <u-scroll\n :class=\"[\n cls.b,\n cls.m(size),\n bem.is('border', border),\n bem.is('all-expanded', allExpanded),\n bem.is('text-ellipsis', textEllipsis)\n ]\"\n ref=\"scrollRef\"\n :content-class=\"cls.e('content')\"\n @scroll=\"handleScroll\"\n >\n <table :class=\"cls.e('wrap')\">\n <colgroup ref=\"colgroupRef\">\n <col\n v-for=\"column of leafColumns\"\n :key=\"column.key\"\n :class=\"column.fixed\"\n :style=\"{\n width: withUnit(column.width, 'px'),\n minWidth: withUnit(column.minWidth, 'px')\n }\"\n />\n </colgroup>\n <UTableHead />\n\n <!--\n 虚拟滚动上占位:替代 tbody transform,避免 table-layout: fixed 下列宽抖动。\n 高度由 useVirtualizer 命令式写入 `style.height`,不经过模板响应式绑定,\n 因此滚动窗口变化不会引起表格模板重渲染。\n -->\n <tbody v-if=\"virtualEnabled\" aria-hidden=\"true\">\n <tr ref=\"beforeSpacerRef\">\n <td :colspan=\"leafColumns.length\" style=\"padding: 0; border: none\"></td>\n </tr>\n </tbody>\n\n <u-table-body>\n <slot name=\"body\" :columns=\"leafColumns\" :rows=\"rows\" />\n\n <template #empty v-if=\"slots.empty\">\n <slot name=\"empty\" />\n </template>\n </u-table-body>\n\n <!-- 虚拟滚动下占位(高度由 useVirtualizer 命令式写入) -->\n <tbody v-if=\"virtualEnabled\" aria-hidden=\"true\">\n <tr ref=\"afterSpacerRef\">\n <td :colspan=\"leafColumns.length\" style=\"padding: 0; border: none\"></td>\n </tr>\n </tbody>\n\n <u-table-foot ref=\"tableFoot\">\n <slot name=\"foot\" :columns=\"leafColumns\" :rows=\"rows\" />\n </u-table-foot>\n </table>\n\n <slot name=\"append\" />\n\n <div v-if=\"showResizeLine\" :class=\"cls.e('resize-line')\" ref=\"resizeLineRef\"></div>\n\n <!-- <u-tip v-if=\"textEllipsis\" ref=\"tip\"> </u-tip> -->\n </u-scroll>\n</template>\n\n<script lang=\"ts\" setup>\nimport { useFallbackProps, useVirtualizer } from '@veltra/compositions'\nimport { bem, withUnit } from '@veltra/utils'\nimport { computed, provide, shallowRef, toRef, useTemplateRef, watch } from 'vue'\n\nimport type {\n TableProps,\n TableEmits,\n _TableExposed,\n TableColumnSlotsScope,\n ComponentSize,\n ScrollExposed,\n TableRowSlotsScope\n} from '../../types'\nimport { UScroll } from '../scroll'\nimport { TableDIKey } from './di'\nimport type { ColumnNode } from './node/col'\nimport type { TableRowNode } from './node/row'\nimport UTableBody from './table-body.vue'\nimport UTableFoot from './table-foot.vue'\n// import { UTip } from '../tip'\nimport UTableHead from './table-head'\nimport { useCheck } from './use-check'\nimport { useColResize } from './use-col-resize'\nimport { useColumns } from './use-columns'\nimport { useFixedColumns } from './use-fixed-columns'\nimport { useRows } from './use-rows'\nimport { useTable } from './use-table'\n\ndefineOptions({ name: 'Table' })\n\nconst props = withDefaults(defineProps<TableProps>(), {\n tree: false,\n stripe: true,\n textOverflow: 'line-break',\n virtualThreshold: 80\n})\nconst emit = defineEmits<TableEmits>()\n\nconst slots = defineSlots<{\n [key: `column:${string}`]: (props: TableColumnSlotsScope) => any\n [key: `header:${string}`]: (props: { column: ColumnNode }) => any\n 'row:expand'?: (props: TableRowSlotsScope) => any\n foot?: (props: { columns: ColumnNode[]; rows: TableRowNode[] }) => any\n body?: (props: { columns: ColumnNode[]; rows: TableRowNode[] }) => any\n empty?: () => any\n append?: () => any\n}>()\n\nconst cls = bem('table')\n\nconst { size } = useFallbackProps([props], { size: 'default' as ComponentSize })\n\nconst scrollRef = shallowRef<ScrollExposed>()\n\n// 占位 tr 的 DOM 句柄;交给 useVirtualizer 直接命令式写 style.height。\nconst beforeSpacerRef = useTemplateRef<HTMLElement>('beforeSpacerRef')\nconst afterSpacerRef = useTemplateRef<HTMLElement>('afterSpacerRef')\n\n// 行(useRows / useFixedColumns 需要 isScrolling,而虚拟化 hook 又依赖 rows.length;\n// 先用中继占位,下方 isScrolling 到位后 watch 回灌)。\nconst isScrollingRelay = shallowRef(false)\n\nconst {\n rows,\n toggleTreeRowExpand,\n allExpanded,\n toggleAllTreeRowExpand,\n rowForest,\n handleRowClick,\n handleCellClick,\n getRowByData\n} = useRows({ props, emit, isScrolling: isScrollingRelay })\n\nconst { createCheckColumn, createSelectColumn, clearChecked, clearSelected, checkedRows } =\n useCheck({ size, props, rows, rowForest, emit, cls })\n\nconst columnConfig = useColumns({\n props,\n createCheckColumn,\n createSelectColumn,\n toggleAllTreeRowExpand,\n cls\n})\n\nconst { leafColumns } = columnConfig\n\nconst { handleScroll, leftFixed, rightFixed } = useFixedColumns({\n isScrolling: isScrollingRelay\n})\n\nconst {\n getColumnSlotsNode,\n getExpandRowSlotsNode,\n getHeaderSlotsNode,\n getCellClass,\n getCellCtx,\n getHeaderCellClass\n} = useTable({ props, cls, leftFixed, rightFixed })\n\nconst { showResizeLine, resizeLineRef, colgroupRef } = useColResize({ scrollRef, leafColumns })\n\nconst { virtualizer, items, isScrolling } = useVirtualizer({\n count: computed(() => rows.value.length),\n scrollEl: () => scrollRef.value?.containerRef ?? null,\n beforeEl: beforeSpacerRef,\n afterEl: afterSpacerRef,\n estimateSize: () => 41,\n // 注意:getItemKey 在构造期一次性写入底层 Virtualizer;闭包每次读的是当前 rows.value,\n // rows 引用整体替换后 key 仍有效(无需再 setOptions)。\n getItemKey: (i) => rows.value[i]?.uid ?? i\n})\n\nconst virtualEnabled = computed(() => {\n const t = props.virtualThreshold\n return t ? rows.value.length > t : true\n})\n\n// 把虚拟化 isScrolling 回灌到中继,供 useRows / useFixedColumns 读取。\nwatch(isScrolling, (v) => {\n isScrollingRelay.value = v\n})\n\n/**\n * E1:数据替换时的条件置顶。\n *\n * 旧实现无差别地 `scrollTo({ y: 0 })`,在「行内增删 / 排序 / 单行更新」等\n * 场景会把用户当前阅读位置跳走;仅在「翻页 / 显著数据集替换」时才需要复位。\n *\n * 判定阈值:|Δlen| / max(newLen, oldLen) ≥ 0.5,即行数变化量超过更大侧的一半时视为显著变化。\n * 选择 0.5 是因为典型的分页/搜索场景会带来 50% 以上的行数差(通常完全替换数据集),\n * 而行内追加 / 删除个位数通常只带来 <5% 的变化;两者区分度足够宽。\n */\nconst LENGTH_DELTA_RATIO_TO_RESET_SCROLL = 0.5\n\nwatch(\n () => props.data,\n (next, prev) => {\n const nextLen = next?.length ?? 0\n const prevLen = prev?.length ?? 0\n const denom = Math.max(nextLen, prevLen, 1)\n const ratio = Math.abs(nextLen - prevLen) / denom\n if (ratio >= LENGTH_DELTA_RATIO_TO_RESET_SCROLL) {\n scrollRef.value?.scrollTo({ y: 0 })\n }\n }\n)\n\n// const tipRef = useTemplateRef('tip')\n\nprovide(TableDIKey, {\n tableProps: props,\n tableSlots: slots,\n cls,\n rows,\n checkedRows,\n columnConfig,\n handleRowClick,\n handleCellClick,\n getColumnSlotsNode,\n getExpandRowSlotsNode,\n getHeaderSlotsNode,\n getCellClass,\n getCellCtx,\n getHeaderCellClass,\n // tipRef,\n toggleTreeRowExpand,\n virtualList: items,\n virtualEnabled,\n measureElement: (index, el) => virtualizer.measureElement(index, el)\n})\n\nconst tableFootRef = useTemplateRef('tableFoot')\n\ndefineExpose<_TableExposed>({\n el: toRef(() => scrollRef.value?.el),\n clearChecked,\n clearSelected,\n getRowByData,\n getSummaryRow: () => tableFootRef.value!.getSummaryRow()\n})\n</script>\n"],"mappings":"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"}
@@ -23,16 +23,16 @@ type __VLS_Slots = {
23
23
  append?: () => any;
24
24
  };
25
25
  declare const __VLS_base: _$vue.DefineComponent<TableProps, _TableExposed, {}, {}, {}, _$vue.ComponentOptionsMixin, _$vue.ComponentOptionsMixin, {} & {
26
- "update:checked": (value: Record<string, any>[]) => any;
27
26
  "update:selected": (value: Record<string, any> | undefined) => any;
27
+ "update:checked": (value: Record<string, any>[]) => any;
28
28
  "update:rows": (rows: TableRow[]) => any;
29
29
  "update:forest": (rows?: _$_cat_kit_core0.Forest<Record<string, unknown>, any> | undefined) => any;
30
30
  "update:current": (row?: TableRow | undefined) => any;
31
31
  "cell-click": (row: TableRow, column: TableColumn, ev: MouseEvent) => any;
32
32
  "row-click": (row: TableRow, ev: MouseEvent) => any;
33
33
  }, string, _$vue.PublicProps, Readonly<TableProps> & Readonly<{
34
- "onUpdate:checked"?: ((value: Record<string, any>[]) => any) | undefined;
35
34
  "onUpdate:selected"?: ((value: Record<string, any> | undefined) => any) | undefined;
35
+ "onUpdate:checked"?: ((value: Record<string, any>[]) => any) | undefined;
36
36
  "onUpdate:rows"?: ((rows: TableRow[]) => any) | undefined;
37
37
  "onUpdate:forest"?: ((rows?: _$_cat_kit_core0.Forest<Record<string, unknown>, any> | undefined) => any) | undefined;
38
38
  "onUpdate:current"?: ((row?: TableRow | undefined) => any) | undefined;
@@ -153,9 +153,13 @@ function useColumns(options) {
153
153
  }
154
154
  }, { immediate: true });
155
155
  return {
156
+ /** 第一列 */
156
157
  expandColumn,
158
+ /** 所有列 */
157
159
  leafColumns,
160
+ /** 列 */
158
161
  columns,
162
+ /** 表格头的分层展示 */
159
163
  headers
160
164
  };
161
165
  }
@@ -1 +1 @@
1
- {"version":3,"file":"use-columns.js","names":["UButton","UIcon"],"sources":["../../../src/components/table/use-columns.ts"],"sourcesContent":["import { Forest, dfs, last } from '@cat-kit/core'\nimport { ArrowRight } from '@veltra/icons/normal'\nimport { type BEM } from '@veltra/utils'\nimport { computed, createVNode, shallowRef, watch, type ComputedRef, type ShallowRef } from 'vue'\n\nimport type { TableColumn, TableProps } from '../../types'\nimport { UButton } from '../button'\nimport { UIcon } from '../icon'\nimport { ColumnNode } from './node/col'\n\n/**\n * 定义表格列\n * @param columns 表格列\n */\nexport function defineTableColumns(\n columns: TableColumn[],\n commonProps?: Partial<Pick<TableColumn, 'align' | 'minWidth'>>\n): TableColumn[] {\n columns.forEach((col) => {\n dfs(col, (node) => {\n for (const key in commonProps) {\n if (node[key] !== undefined) continue\n node[key] = commonProps[key]\n }\n })\n })\n return columns\n}\n\nexport interface ColumnConfig {\n /** 表头 */\n headers: ComputedRef<ColumnNode[][]>\n\n /**\n * body列, 在body中使用\n */\n columns: ShallowRef<ColumnNode[]>\n\n /** 所有叶子列 */\n leafColumns: ShallowRef<ColumnNode[]>\n\n /** 第一列 */\n expandColumn: ShallowRef<ColumnNode | undefined>\n}\n\ninterface Options {\n props: TableProps\n cls: BEM<'table'>\n /** 创建复选框 */\n createCheckColumn: () => TableColumn\n createSelectColumn: () => TableColumn\n toggleAllTreeRowExpand: () => void\n}\n\nexport function useColumns(options: Options): ColumnConfig {\n const { props, createCheckColumn, createSelectColumn, toggleAllTreeRowExpand, cls } = options\n\n /** 前置列 */\n const preColumns = computed<TableColumn[]>(() => {\n const { selectable, checkable, showIndex } = props\n\n const columns: TableColumn[] = []\n\n if (selectable) {\n columns.push(createSelectColumn())\n } else if (checkable) {\n columns.push(createCheckColumn())\n }\n if (showIndex) {\n columns.push({\n key: '__index__',\n name: '#',\n resizable: false,\n width: 60,\n minWidth: 60,\n align: 'center',\n fixed: 'left',\n render({ row }) {\n return row.index + 1\n }\n })\n }\n\n return columns\n })\n\n const columnForest = shallowRef<Forest<TableColumn, any>>()\n\n const renderExpandAll = () =>\n createVNode(\n UButton,\n {\n text: true,\n title: '展开或收起全部',\n class: cls.e('expand-all'),\n type: 'primary',\n size: 'small',\n circle: true,\n onClick: (e) => {\n e.stopPropagation()\n toggleAllTreeRowExpand()\n }\n },\n () => [createVNode(UIcon, undefined, () => [createVNode(ArrowRight)])]\n )\n\n watch(\n [preColumns, () => props.columns, () => props.tree, () => props.expandable],\n ([preColumns, columns, tree, expandable]) => {\n /** 固定到左侧的列 */\n const fixedOnLeft: TableColumn[] = [...preColumns]\n /** 未固定的列 */\n const unfixed: TableColumn[] = []\n /** 固定到右侧的列 */\n const fixedOnRight: TableColumn[] = []\n\n columns?.forEach((column) => {\n if (!column.fixed || column.children) {\n column.fixed = undefined\n return unfixed.push(column)\n }\n if (column.fixed === 'left') {\n fixedOnLeft.push(column)\n } else {\n fixedOnRight.push(column)\n }\n })\n\n if (last(fixedOnLeft)) {\n last(fixedOnLeft)!.isLastFixed = true\n }\n if (fixedOnRight[0]) {\n fixedOnRight[0].isFirstFixed = true\n }\n\n const sortedColumns = [...fixedOnLeft, ...unfixed, ...fixedOnRight]\n // 操作时避免改变原数据\n const firstColumn = { ...sortedColumns[0] } as TableColumn\n sortedColumns[0] = firstColumn\n\n // 树形表格需要给第一列添加展开按钮\n // 因此要重新设置第一列的宽度和对齐方式\n if ((!!tree || expandable) && firstColumn) {\n firstColumn.align = 'left'\n firstColumn.width = firstColumn.width ? firstColumn.width + 60 : undefined\n\n const oldNameRender = firstColumn.nameRender\n\n firstColumn.nameRender = oldNameRender\n ? (ctx) => {\n const oldNodes = oldNameRender!(ctx)\n return [renderExpandAll(), ...(Array.isArray(oldNodes) ? oldNodes : [oldNodes])]\n }\n : () => {\n return [renderExpandAll(), firstColumn.name]\n }\n }\n\n const result = new Forest<TableColumn, any>({\n data: sortedColumns,\n createNode(data, index, depth, _f, parent) {\n return new ColumnNode(data, index, depth, parent)\n }\n })\n\n columnForest.value = result\n },\n { immediate: true }\n )\n\n const headers = computed(() => {\n const headers: ColumnNode[][] = []\n const forest = columnForest.value\n if (!forest) return headers\n\n // Forest.bfs 对每个根单独 BFS,按 depth 拼行会把后续根节点错放到深层,且根节点无 parent,\n // 回溯 leafs 时会读到 undefined。这里从所有根一次性层序遍历,与多列表头布局一致。\n const queue: ColumnNode[] = [...forest.roots]\n while (queue.length > 0) {\n const size = queue.length\n const layer: ColumnNode[] = []\n for (let i = 0; i < size; i++) {\n const node = queue.shift()!\n layer.push(node)\n const ch = node.children\n if (ch?.length) {\n for (const c of ch) {\n queue.push(c)\n }\n }\n }\n headers.push(layer)\n }\n\n // 从叶子节点开始回溯计算每个节点的累计叶子节点数量,叶子节点数量代表表头的宽度\n for (let i = headers.length - 1; i > 0; i--) {\n const header = headers[i]!\n\n header.forEach((node) => {\n const parent = node.parent\n if (!parent) return\n if (parent.leafs !== undefined) return\n parent.leafs = parent.children!.reduce((sum, node) => {\n return sum + (node.leafs ?? 1)\n }, 0)\n })\n }\n\n return headers\n })\n\n /** 除展开按钮之外的列 */\n const columns = shallowRef<ColumnNode[]>([])\n\n /** 所有叶子节点 */\n const leafColumns = shallowRef<ColumnNode[]>([])\n\n const expandColumn = shallowRef<ColumnNode>()\n\n // 监听列的变化\n watch(\n [columnForest, () => props.tree, () => props.expandable],\n ([forest, tree, expandable]) => {\n const _columns: ColumnNode[] = []\n\n forest?.dfs((node) => {\n if (node.isLeaf) {\n _columns.push(node)\n }\n })\n\n leafColumns.value = _columns\n\n if (tree || expandable) {\n expandColumn.value = _columns[0]\n columns.value = _columns.slice(1)\n } else {\n columns.value = _columns\n expandColumn.value = undefined\n }\n },\n { immediate: true }\n )\n\n return {\n /** 第一列 */\n expandColumn,\n /** 所有列 */\n leafColumns,\n /** 列 */\n columns,\n /** 表格头的分层展示 */\n headers\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-columns.js","names":["UButton","UIcon"],"sources":["../../../src/components/table/use-columns.ts"],"sourcesContent":["import { Forest, dfs, last } from '@cat-kit/core'\nimport { ArrowRight } from '@veltra/icons/normal'\nimport { type BEM } from '@veltra/utils'\nimport { computed, createVNode, shallowRef, watch, type ComputedRef, type ShallowRef } from 'vue'\n\nimport type { TableColumn, TableProps } from '../../types'\nimport { UButton } from '../button'\nimport { UIcon } from '../icon'\nimport { ColumnNode } from './node/col'\n\n/**\n * 定义表格列\n * @param columns 表格列\n */\nexport function defineTableColumns(\n columns: TableColumn[],\n commonProps?: Partial<Pick<TableColumn, 'align' | 'minWidth'>>\n): TableColumn[] {\n columns.forEach((col) => {\n dfs(col, (node) => {\n for (const key in commonProps) {\n if (node[key] !== undefined) continue\n node[key] = commonProps[key]\n }\n })\n })\n return columns\n}\n\nexport interface ColumnConfig {\n /** 表头 */\n headers: ComputedRef<ColumnNode[][]>\n\n /**\n * body列, 在body中使用\n */\n columns: ShallowRef<ColumnNode[]>\n\n /** 所有叶子列 */\n leafColumns: ShallowRef<ColumnNode[]>\n\n /** 第一列 */\n expandColumn: ShallowRef<ColumnNode | undefined>\n}\n\ninterface Options {\n props: TableProps\n cls: BEM<'table'>\n /** 创建复选框 */\n createCheckColumn: () => TableColumn\n createSelectColumn: () => TableColumn\n toggleAllTreeRowExpand: () => void\n}\n\nexport function useColumns(options: Options): ColumnConfig {\n const { props, createCheckColumn, createSelectColumn, toggleAllTreeRowExpand, cls } = options\n\n /** 前置列 */\n const preColumns = computed<TableColumn[]>(() => {\n const { selectable, checkable, showIndex } = props\n\n const columns: TableColumn[] = []\n\n if (selectable) {\n columns.push(createSelectColumn())\n } else if (checkable) {\n columns.push(createCheckColumn())\n }\n if (showIndex) {\n columns.push({\n key: '__index__',\n name: '#',\n resizable: false,\n width: 60,\n minWidth: 60,\n align: 'center',\n fixed: 'left',\n render({ row }) {\n return row.index + 1\n }\n })\n }\n\n return columns\n })\n\n const columnForest = shallowRef<Forest<TableColumn, any>>()\n\n const renderExpandAll = () =>\n createVNode(\n UButton,\n {\n text: true,\n title: '展开或收起全部',\n class: cls.e('expand-all'),\n type: 'primary',\n size: 'small',\n circle: true,\n onClick: (e) => {\n e.stopPropagation()\n toggleAllTreeRowExpand()\n }\n },\n () => [createVNode(UIcon, undefined, () => [createVNode(ArrowRight)])]\n )\n\n watch(\n [preColumns, () => props.columns, () => props.tree, () => props.expandable],\n ([preColumns, columns, tree, expandable]) => {\n /** 固定到左侧的列 */\n const fixedOnLeft: TableColumn[] = [...preColumns]\n /** 未固定的列 */\n const unfixed: TableColumn[] = []\n /** 固定到右侧的列 */\n const fixedOnRight: TableColumn[] = []\n\n columns?.forEach((column) => {\n if (!column.fixed || column.children) {\n column.fixed = undefined\n return unfixed.push(column)\n }\n if (column.fixed === 'left') {\n fixedOnLeft.push(column)\n } else {\n fixedOnRight.push(column)\n }\n })\n\n if (last(fixedOnLeft)) {\n last(fixedOnLeft)!.isLastFixed = true\n }\n if (fixedOnRight[0]) {\n fixedOnRight[0].isFirstFixed = true\n }\n\n const sortedColumns = [...fixedOnLeft, ...unfixed, ...fixedOnRight]\n // 操作时避免改变原数据\n const firstColumn = { ...sortedColumns[0] } as TableColumn\n sortedColumns[0] = firstColumn\n\n // 树形表格需要给第一列添加展开按钮\n // 因此要重新设置第一列的宽度和对齐方式\n if ((!!tree || expandable) && firstColumn) {\n firstColumn.align = 'left'\n firstColumn.width = firstColumn.width ? firstColumn.width + 60 : undefined\n\n const oldNameRender = firstColumn.nameRender\n\n firstColumn.nameRender = oldNameRender\n ? (ctx) => {\n const oldNodes = oldNameRender!(ctx)\n return [renderExpandAll(), ...(Array.isArray(oldNodes) ? oldNodes : [oldNodes])]\n }\n : () => {\n return [renderExpandAll(), firstColumn.name]\n }\n }\n\n const result = new Forest<TableColumn, any>({\n data: sortedColumns,\n createNode(data, index, depth, _f, parent) {\n return new ColumnNode(data, index, depth, parent)\n }\n })\n\n columnForest.value = result\n },\n { immediate: true }\n )\n\n const headers = computed(() => {\n const headers: ColumnNode[][] = []\n const forest = columnForest.value\n if (!forest) return headers\n\n // Forest.bfs 对每个根单独 BFS,按 depth 拼行会把后续根节点错放到深层,且根节点无 parent,\n // 回溯 leafs 时会读到 undefined。这里从所有根一次性层序遍历,与多列表头布局一致。\n const queue: ColumnNode[] = [...forest.roots]\n while (queue.length > 0) {\n const size = queue.length\n const layer: ColumnNode[] = []\n for (let i = 0; i < size; i++) {\n const node = queue.shift()!\n layer.push(node)\n const ch = node.children\n if (ch?.length) {\n for (const c of ch) {\n queue.push(c)\n }\n }\n }\n headers.push(layer)\n }\n\n // 从叶子节点开始回溯计算每个节点的累计叶子节点数量,叶子节点数量代表表头的宽度\n for (let i = headers.length - 1; i > 0; i--) {\n const header = headers[i]!\n\n header.forEach((node) => {\n const parent = node.parent\n if (!parent) return\n if (parent.leafs !== undefined) return\n parent.leafs = parent.children!.reduce((sum, node) => {\n return sum + (node.leafs ?? 1)\n }, 0)\n })\n }\n\n return headers\n })\n\n /** 除展开按钮之外的列 */\n const columns = shallowRef<ColumnNode[]>([])\n\n /** 所有叶子节点 */\n const leafColumns = shallowRef<ColumnNode[]>([])\n\n const expandColumn = shallowRef<ColumnNode>()\n\n // 监听列的变化\n watch(\n [columnForest, () => props.tree, () => props.expandable],\n ([forest, tree, expandable]) => {\n const _columns: ColumnNode[] = []\n\n forest?.dfs((node) => {\n if (node.isLeaf) {\n _columns.push(node)\n }\n })\n\n leafColumns.value = _columns\n\n if (tree || expandable) {\n expandColumn.value = _columns[0]\n columns.value = _columns.slice(1)\n } else {\n columns.value = _columns\n expandColumn.value = undefined\n }\n },\n { immediate: true }\n )\n\n return {\n /** 第一列 */\n expandColumn,\n /** 所有列 */\n leafColumns,\n /** 列 */\n columns,\n /** 表格头的分层展示 */\n headers\n }\n}\n"],"mappings":"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"}
@@ -1,22 +1,41 @@
1
- import { ref } from "vue";
1
+ import { ref, watch } from "vue";
2
2
  import { debounce } from "@cat-kit/core";
3
3
  //#region src/components/table/use-fixed-columns.ts
4
4
  /**
5
5
  * 固定列
6
6
  * @returns
7
7
  */
8
- function useFixedColumns() {
8
+ function useFixedColumns(options = {}) {
9
+ const { isScrolling } = options;
9
10
  const leftFixed = ref(false);
10
11
  const rightFixed = ref(false);
12
+ let pendingLeft = null;
13
+ let pendingRight = null;
14
+ const applyImmediate = (nextLeft, nextRight) => {
15
+ if (nextLeft !== leftFixed.value) leftFixed.value = nextLeft;
16
+ if (nextRight !== rightFixed.value) rightFixed.value = nextRight;
17
+ pendingLeft = null;
18
+ pendingRight = null;
19
+ };
20
+ const handleScroll = debounce((e) => {
21
+ const nextLeft = e.x > 0;
22
+ const nextRight = !(e.cw + e.x + 1 >= e.sw);
23
+ if (isScrolling?.value) {
24
+ pendingLeft = nextLeft;
25
+ pendingRight = nextRight;
26
+ return;
27
+ }
28
+ applyImmediate(nextLeft, nextRight);
29
+ }, 50);
30
+ if (isScrolling) watch(isScrolling, (v) => {
31
+ if (v) return;
32
+ if (pendingLeft === null && pendingRight === null) return;
33
+ applyImmediate(pendingLeft ?? leftFixed.value, pendingRight ?? rightFixed.value);
34
+ });
11
35
  return {
12
36
  leftFixed,
13
37
  rightFixed,
14
- handleScroll: debounce((e) => {
15
- if (e.x > 0) leftFixed.value = true;
16
- else leftFixed.value = false;
17
- if (e.cw + e.x + 1 >= e.sw) rightFixed.value = false;
18
- else rightFixed.value = true;
19
- }, 50)
38
+ handleScroll
20
39
  };
21
40
  }
22
41
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"use-fixed-columns.js","names":[],"sources":["../../../src/components/table/use-fixed-columns.ts"],"sourcesContent":["import { debounce } from '@cat-kit/core'\nimport { type ShallowRef, ref } from 'vue'\n\nimport type { ScrollPosition } from '../../types'\n\ninterface UseColumnFixedReturned {\n leftFixed: ShallowRef<boolean>\n rightFixed: ShallowRef<boolean>\n handleScroll: (e: Required<ScrollPosition>) => void\n}\n\n/**\n * 固定列\n * @returns\n */\nexport function useFixedColumns(): UseColumnFixedReturned {\n const leftFixed = ref(false)\n const rightFixed = ref(false)\n\n const handleScroll = debounce((e: Required<ScrollPosition>) => {\n if (e.x > 0) {\n leftFixed.value = true\n } else {\n leftFixed.value = false\n }\n\n // 精度修正\n if (e.cw + e.x + 1 >= e.sw) {\n rightFixed.value = false\n } else {\n rightFixed.value = true\n }\n }, 50)\n\n return { leftFixed, rightFixed, handleScroll }\n}\n"],"mappings":";;;;;;;AAeA,SAAgB,kBAA0C;CACxD,MAAM,YAAY,IAAI,MAAM;CAC5B,MAAM,aAAa,IAAI,MAAM;AAiB7B,QAAO;EAAE;EAAW;EAAY,cAfX,UAAU,MAAgC;AAC7D,OAAI,EAAE,IAAI,EACR,WAAU,QAAQ;OAElB,WAAU,QAAQ;AAIpB,OAAI,EAAE,KAAK,EAAE,IAAI,KAAK,EAAE,GACtB,YAAW,QAAQ;OAEnB,YAAW,QAAQ;KAEpB,GAAG;EAEwC"}
1
+ {"version":3,"file":"use-fixed-columns.js","names":[],"sources":["../../../src/components/table/use-fixed-columns.ts"],"sourcesContent":["import { debounce } from '@cat-kit/core'\nimport { type ShallowRef, type Ref, ref, watch } from 'vue'\n\nimport type { ScrollPosition } from '../../types'\n\ninterface UseColumnFixedReturned {\n leftFixed: ShallowRef<boolean>\n rightFixed: ShallowRef<boolean>\n handleScroll: (e: Required<ScrollPosition>) => void\n}\n\ninterface Options {\n /**\n * D1:滚动中 (`true`) 暂缓 `leftFixed` / `rightFixed` 的切换,滚动结束后\n * 一次性补算。\n *\n * 背景:固定列的阴影是通过在 cell 上切换 `is-last-fixed` / `is-first-fixed`\n * 等 class 实现的,这些 class 会穿透到 `useTable.getCellClass` 的缓存键,\n * 任何一次切换都会让全表的单元格类名失效重算。滚动本身并不需要实时更新阴影,\n * 因此把切换推迟到 `isScrolling` 归零时做一次即可。\n *\n * 未传入时退化到旧行为(实时切换)。\n */\n isScrolling?: Ref<boolean>\n}\n\n/**\n * 固定列\n * @returns\n */\nexport function useFixedColumns(options: Options = {}): UseColumnFixedReturned {\n const { isScrolling } = options\n\n const leftFixed = ref(false)\n const rightFixed = ref(false)\n\n let pendingLeft: boolean | null = null\n let pendingRight: boolean | null = null\n\n const applyImmediate = (nextLeft: boolean, nextRight: boolean): void => {\n if (nextLeft !== leftFixed.value) leftFixed.value = nextLeft\n if (nextRight !== rightFixed.value) rightFixed.value = nextRight\n pendingLeft = null\n pendingRight = null\n }\n\n const handleScroll = debounce((e: Required<ScrollPosition>) => {\n const nextLeft = e.x > 0\n // 精度修正:浏览器滚动条最后 1px 的误差\n const nextRight = !(e.cw + e.x + 1 >= e.sw)\n\n if (isScrolling?.value) {\n pendingLeft = nextLeft\n pendingRight = nextRight\n return\n }\n\n applyImmediate(nextLeft, nextRight)\n }, 50)\n\n if (isScrolling) {\n watch(isScrolling, (v) => {\n if (v) return\n if (pendingLeft === null && pendingRight === null) return\n applyImmediate(pendingLeft ?? leftFixed.value, pendingRight ?? rightFixed.value)\n })\n }\n\n return { leftFixed, rightFixed, handleScroll }\n}\n"],"mappings":";;;;;;;AA8BA,SAAgB,gBAAgB,UAAmB,EAAE,EAA0B;CAC7E,MAAM,EAAE,gBAAgB;CAExB,MAAM,YAAY,IAAI,MAAM;CAC5B,MAAM,aAAa,IAAI,MAAM;CAE7B,IAAI,cAA8B;CAClC,IAAI,eAA+B;CAEnC,MAAM,kBAAkB,UAAmB,cAA6B;AACtE,MAAI,aAAa,UAAU,MAAO,WAAU,QAAQ;AACpD,MAAI,cAAc,WAAW,MAAO,YAAW,QAAQ;AACvD,gBAAc;AACd,iBAAe;;CAGjB,MAAM,eAAe,UAAU,MAAgC;EAC7D,MAAM,WAAW,EAAE,IAAI;EAEvB,MAAM,YAAY,EAAE,EAAE,KAAK,EAAE,IAAI,KAAK,EAAE;AAExC,MAAI,aAAa,OAAO;AACtB,iBAAc;AACd,kBAAe;AACf;;AAGF,iBAAe,UAAU,UAAU;IAClC,GAAG;AAEN,KAAI,YACF,OAAM,cAAc,MAAM;AACxB,MAAI,EAAG;AACP,MAAI,gBAAgB,QAAQ,iBAAiB,KAAM;AACnD,iBAAe,eAAe,UAAU,OAAO,gBAAgB,WAAW,MAAM;GAChF;AAGJ,QAAO;EAAE;EAAW;EAAY;EAAc"}
@@ -4,7 +4,7 @@ import { Forest, o } from "@cat-kit/core";
4
4
  import { useModel as useModel$1 } from "@veltra/compositions";
5
5
  //#region src/components/table/use-rows.ts
6
6
  function useRows(options) {
7
- const { props, emit } = options;
7
+ const { props, emit, isScrolling } = options;
8
8
  /** 所有可见的行 */
9
9
  const rows = shallowRef([]);
10
10
  /** 数据行, 不包括展开和折叠的行 */
@@ -145,7 +145,7 @@ function useRows(options) {
145
145
  }
146
146
  }
147
147
  function handleRowClick(row, e) {
148
- currentRow.value = currentRow.value === row ? void 0 : row;
148
+ if (!isScrolling?.value) currentRow.value = currentRow.value === row ? void 0 : row;
149
149
  emit("row-click", row, e);
150
150
  }
151
151
  function handleCellClick(row, column, e) {