stk-table-vue 0.8.7 → 0.8.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.
package/README.md CHANGED
@@ -20,7 +20,8 @@
20
20
 
21
21
 
22
22
  ## Documentation
23
- ### [Stk Table Vue Official CN](https://ja-plus.github.io/stk-table-vue/)
23
+ ### [Stk Table Vue Official en](https://ja-plus.github.io/stk-table-vue/en/)
24
+ ### [Stk Table Vue Official zh-CN](https://ja-plus.github.io/stk-table-vue/)
24
25
 
25
26
 
26
27
  ## Repo:
@@ -1,4 +1,4 @@
1
- import { AutoRowHeightConfig, ColResizableConfig, DragRowConfig, ExpandConfig, HeaderDragConfig, HighlightConfig, Order, PrivateRowDT, PrivateStkTableColumn, SeqConfig, SortConfig, SortOption, StkTableColumn, TreeConfig, UniqKey, UniqKeyProp } from './types/index';
1
+ import { AutoRowHeightConfig, ColResizableConfig, DragRowConfig, ExpandConfig, HeaderDragConfig, HighlightConfig, Order, PrivateRowDT, PrivateStkTableColumn, RowActiveOption, SeqConfig, SortConfig, SortOption, StkTableColumn, TreeConfig, UniqKey, UniqKeyProp } from './types/index';
2
2
 
3
3
  /** Generic stands for DataType */
4
4
  type DT = any & PrivateRowDT;
@@ -6,9 +6,11 @@ type DT = any & PrivateRowDT;
6
6
  * 选中一行
7
7
  * @param {string} rowKeyOrRow selected rowKey, undefined to unselect
8
8
  * @param {boolean} option.silent if set true not emit `current-change`. default:false
9
+ * @param {boolean} option.deep if set true, deep search in children. default:false
9
10
  */
10
11
  declare function setCurrentRow(rowKeyOrRow: string | undefined | DT, option?: {
11
- silent: boolean;
12
+ silent?: boolean;
13
+ deep?: boolean;
12
14
  }): void;
13
15
  /**
14
16
  * set highlight active cell (props.cellActive=true)
@@ -90,8 +92,10 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
90
92
  /** 是否高亮鼠标悬浮的行 */
91
93
  rowHover?: boolean;
92
94
  /** 是否高亮选中的行 */
93
- rowActive?: boolean;
94
- /** 当前行再次点击否可以取消 (rowActive=true)*/
95
+ rowActive?: boolean | RowActiveOption<DT>;
96
+ /**
97
+ * @deprecated
98
+ */
95
99
  rowCurrentRevokable?: boolean;
96
100
  /** 表头行高。default = rowHeight */
97
101
  headerRowHeight?: number | string | null;
@@ -238,8 +242,9 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
238
242
  fixedColShadow: boolean;
239
243
  optimizeVue2Scroll: boolean;
240
244
  sortConfig: () => {
241
- emptyToBottom: boolean;
242
- stringLocaleCompare: boolean;
245
+ emptyToBottom: false;
246
+ stringLocaleCompare: false;
247
+ sortChildren: false;
243
248
  };
244
249
  hideHeaderTitle: boolean;
245
250
  highlightConfig: () => {};
@@ -456,8 +461,10 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
456
461
  /** 是否高亮鼠标悬浮的行 */
457
462
  rowHover?: boolean;
458
463
  /** 是否高亮选中的行 */
459
- rowActive?: boolean;
460
- /** 当前行再次点击否可以取消 (rowActive=true)*/
464
+ rowActive?: boolean | RowActiveOption<DT>;
465
+ /**
466
+ * @deprecated
467
+ */
461
468
  rowCurrentRevokable?: boolean;
462
469
  /** 表头行高。default = rowHeight */
463
470
  headerRowHeight?: number | string | null;
@@ -604,8 +611,9 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
604
611
  fixedColShadow: boolean;
605
612
  optimizeVue2Scroll: boolean;
606
613
  sortConfig: () => {
607
- emptyToBottom: boolean;
608
- stringLocaleCompare: boolean;
614
+ emptyToBottom: false;
615
+ stringLocaleCompare: false;
616
+ sortChildren: false;
609
617
  };
610
618
  hideHeaderTitle: boolean;
611
619
  highlightConfig: () => {};
@@ -683,7 +691,7 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
683
691
  fixedMode: boolean;
684
692
  theme: "light" | "dark";
685
693
  rowHover: boolean;
686
- rowActive: boolean;
694
+ rowActive: boolean | RowActiveOption<DT>;
687
695
  rowCurrentRevokable: boolean;
688
696
  virtual: boolean;
689
697
  virtualX: boolean;
@@ -1,3 +1,5 @@
1
+ import { RowActiveOption } from './types';
2
+
1
3
  export declare const DEFAULT_COL_WIDTH = "100";
2
4
  export declare const DEFAULT_TABLE_HEIGHT = 100;
3
5
  export declare const DEFAULT_TABLE_WIDTH = 200;
@@ -24,5 +26,11 @@ export declare const DEFAULT_SMOOTH_SCROLL: boolean;
24
26
  export declare const STK_ID_PREFIX = "stk";
25
27
  /** expanded row key prefix */
26
28
  export declare const EXPANDED_ROW_KEY_PREFIX = "expanded-";
27
- /** cell key 的分隔符 */
29
+ /** cell key split str */
28
30
  export declare const CELL_KEY_SEPARATE = "--";
31
+ export declare const DEFAULT_SORT_CONFIG: {
32
+ emptyToBottom: false;
33
+ stringLocaleCompare: false;
34
+ sortChildren: false;
35
+ };
36
+ export declare const DEFAULT_ROW_ACTIVE_CONFIG: Required<RowActiveOption<any>>;
@@ -84,7 +84,7 @@ export type StkTableColumn<T extends Record<string, any>> = {
84
84
  /** 排序方式。按数字/字符串 */
85
85
  sortType?: 'number' | 'string';
86
86
  /** 配置当前列的排序规则 */
87
- sortConfig?: Pick<SortConfig<T>, 'emptyToBottom' | 'stringLocaleCompare'>;
87
+ sortConfig?: Omit<SortConfig<T>, 'defaultSort'>;
88
88
  /** 固定列 */
89
89
  fixed?: 'left' | 'right' | null;
90
90
  /**
@@ -167,17 +167,17 @@ export type UniqKey = string | number;
167
167
  export type UniqKeyFun = (param: any) => UniqKey;
168
168
  export type UniqKeyProp = UniqKey | UniqKeyFun;
169
169
  export type SortConfig<T extends Record<string, any>> = {
170
- /** 空值始终排在列表末尾 */
171
- emptyToBottom?: boolean;
172
170
  /**
173
- * 默认排序(1.初始化时触发 2.排序方向为null时触发)
174
- * 类似onMounted时,调用setSorter点了下表头。
171
+ * 1. trigger when init
172
+ * 2. trigger when sort direction is null
175
173
  */
176
174
  defaultSort?: {
177
175
  /**
178
- * 列唯一键,
176
+ * colKey
177
+ *
178
+ * if set `props.colKey`
179
179
  *
180
- * 如果您配了 `props.colKey` 则这里表示的列唯一键的值
180
+ * default: StkTableColumn<T>['dataIndex']
181
181
  */
182
182
  key?: StkTableColumn<T>['key'];
183
183
  dataIndex: StkTableColumn<T>['dataIndex'];
@@ -185,14 +185,22 @@ export type SortConfig<T extends Record<string, any>> = {
185
185
  sortField?: StkTableColumn<T>['sortField'];
186
186
  sortType?: StkTableColumn<T>['sortType'];
187
187
  sorter?: StkTableColumn<T>['sorter'];
188
- /** 是否禁止触发sort-change事件。默认false,表示触发事件。 */
188
+ /**
189
+ * whether to disable trigger`sort-change` event. default: false
190
+ */
189
191
  silent?: boolean;
190
192
  };
193
+ /** empty value always sort to bottom */
194
+ emptyToBottom?: boolean;
191
195
  /**
192
196
  * string sort if use `String.prototype.localCompare`
193
197
  * default: false
194
198
  */
195
199
  stringLocaleCompare?: boolean;
200
+ /**
201
+ * whether to sort children when sort current column. default: false
202
+ */
203
+ sortChildren?: boolean;
196
204
  };
197
205
  /** th td type */
198
206
  export declare const enum TagType {
@@ -225,7 +233,6 @@ export type ExpandedRow = PrivateRowDT & {
225
233
  export type DragRowConfig = {
226
234
  mode?: 'none' | 'insert' | 'swap';
227
235
  };
228
- /** 树形配置 */
229
236
  export type TreeConfig = {
230
237
  defaultExpandAll?: boolean;
231
238
  defaultExpandKeys?: UniqKey[];
@@ -234,13 +241,13 @@ export type TreeConfig = {
234
241
  /** header drag config */
235
242
  export type HeaderDragConfig<DT extends Record<string, any> = any> = {
236
243
  /**
237
- * 列交换模式
238
- * - none - 不做任何事
239
- * - insert - 插入(默认值)
240
- * - swap - 交换
244
+ * col switch mode
245
+ * - none
246
+ * - insert - (default)
247
+ * - swap
241
248
  */
242
249
  mode?: 'none' | 'insert' | 'swap';
243
- /** 禁用拖动的列 */
250
+ /** disabled drag col */
244
251
  disabled?: (col: StkTableColumn<DT>) => boolean;
245
252
  };
246
253
  export type AutoRowHeightConfig<DT> = {
@@ -253,4 +260,11 @@ export type ColResizableConfig<DT extends Record<string, any>> = {
253
260
  export type RowKeyGen = (row: any) => UniqKey;
254
261
  export type ColKeyGen = ComputedRef<(col: StkTableColumn<any>) => UniqKey>;
255
262
  export type CellKeyGen = (row: any, col: StkTableColumn<any>) => string;
263
+ export type RowActiveOption<DT> = {
264
+ enabled?: boolean;
265
+ /** disabled row active */
266
+ disabled?: (row: DT) => boolean;
267
+ /** current row again click can revoke active */
268
+ revokable?: boolean;
269
+ };
256
270
  export {};
@@ -1,22 +1,22 @@
1
- import { ShallowRef } from 'vue';
2
- import { ColKeyGen, MergeCellsParam, PrivateStkTableColumn, RowKeyGen, UniqKey } from './types';
1
+ import { Ref, ShallowRef } from 'vue';
2
+ import { ColKeyGen, MergeCellsParam, PrivateStkTableColumn, RowActiveOption, RowKeyGen, UniqKey } from './types';
3
3
 
4
4
  type Options = {
5
- props: any;
5
+ rowActiveProp: Ref<RowActiveOption<any>>;
6
6
  tableHeaderLast: ShallowRef<PrivateStkTableColumn<any>[]>;
7
7
  rowKeyGen: RowKeyGen;
8
8
  colKeyGen: ColKeyGen;
9
9
  virtual_dataSourcePart: ShallowRef<any[]>;
10
10
  };
11
- export declare function useMergeCells({ props, tableHeaderLast, rowKeyGen, colKeyGen, virtual_dataSourcePart, }: Options): {
12
- hiddenCellMap: import('vue').Ref<Record<UniqKey, Set<UniqKey>>, Record<UniqKey, Set<UniqKey>>>;
11
+ export declare function useMergeCells({ rowActiveProp, tableHeaderLast, rowKeyGen, colKeyGen, virtual_dataSourcePart }: Options): {
12
+ hiddenCellMap: Ref<Record<UniqKey, Set<UniqKey>>, Record<UniqKey, Set<UniqKey>>>;
13
13
  mergeCellsWrapper: (row: MergeCellsParam<any>["row"], col: MergeCellsParam<any>["col"], rowIndex: MergeCellsParam<any>["rowIndex"], colIndex: MergeCellsParam<any>["colIndex"]) => {
14
14
  colspan?: number;
15
15
  rowspan?: number;
16
16
  } | undefined;
17
- hoverMergedCells: import('vue').Ref<Set<string> & Omit<Set<string>, keyof Set<any>>, Set<string> | (Set<string> & Omit<Set<string>, keyof Set<any>>)>;
17
+ hoverMergedCells: Ref<Set<string> & Omit<Set<string>, keyof Set<any>>, Set<string> | (Set<string> & Omit<Set<string>, keyof Set<any>>)>;
18
18
  updateHoverMergedCells: (rowKey: UniqKey | undefined) => void;
19
- activeMergedCells: import('vue').Ref<Set<string> & Omit<Set<string>, keyof Set<any>>, Set<string> | (Set<string> & Omit<Set<string>, keyof Set<any>>)>;
20
- updateActiveMergedCells: (clear?: boolean) => void;
19
+ activeMergedCells: Ref<Set<string> & Omit<Set<string>, keyof Set<any>>, Set<string> | (Set<string> & Omit<Set<string>, keyof Set<any>>)>;
20
+ updateActiveMergedCells: (clear?: boolean, rowKey?: UniqKey) => void;
21
21
  };
22
22
  export {};
@@ -134,30 +134,41 @@ function separatedData(sortOption, targetDataSource, isNumber) {
134
134
  }
135
135
  function tableSort(sortOption, order, dataSource, sortConfig = {}) {
136
136
  if (!(dataSource == null ? void 0 : dataSource.length) || !sortOption) return dataSource || [];
137
- sortConfig = { emptyToBottom: false, ...sortConfig };
137
+ sortConfig = { ...DEFAULT_SORT_CONFIG, ...sortConfig };
138
138
  let targetDataSource = dataSource.slice();
139
139
  let sortField = sortOption.sortField || sortOption.dataIndex;
140
- if (!order && sortConfig.defaultSort) {
141
- order = sortConfig.defaultSort.order;
142
- sortField = sortConfig.defaultSort.dataIndex;
140
+ const { defaultSort, stringLocaleCompare, emptyToBottom, sortChildren } = sortConfig;
141
+ if (!order && defaultSort) {
142
+ order = defaultSort.order;
143
+ sortField = defaultSort.dataIndex;
143
144
  }
144
145
  if (typeof sortOption.sorter === "function") {
145
146
  const customSorterData = sortOption.sorter(targetDataSource, { order, column: sortOption });
146
147
  if (customSorterData) targetDataSource = customSorterData;
148
+ if (sortChildren) {
149
+ targetDataSource.forEach((item) => {
150
+ var _a;
151
+ if (!((_a = item.children) == null ? void 0 : _a.length)) return;
152
+ item.children = tableSort(sortOption, order, item.children, sortConfig);
153
+ });
154
+ }
147
155
  } else if (order) {
148
156
  let { sortType } = sortOption;
149
157
  if (!sortType) sortType = typeof dataSource[0][sortField];
150
158
  const isNumber = sortType === "number";
151
159
  const [valueArr, emptyArr] = separatedData(sortOption, targetDataSource, isNumber);
152
160
  if (order === "asc") {
153
- valueArr.sort((a, b) => strCompare(a[sortField], b[sortField], isNumber, sortConfig.stringLocaleCompare));
154
- } else {
155
- valueArr.sort((a, b) => strCompare(b[sortField], a[sortField], isNumber, sortConfig.stringLocaleCompare));
156
- }
157
- if (order === "desc" || sortConfig.emptyToBottom) {
158
- targetDataSource = valueArr.concat(emptyArr);
161
+ valueArr.sort((a, b) => strCompare(a[sortField], b[sortField], isNumber, stringLocaleCompare));
159
162
  } else {
160
- targetDataSource = emptyArr.concat(valueArr);
163
+ valueArr.sort((a, b) => strCompare(b[sortField], a[sortField], isNumber, stringLocaleCompare));
164
+ }
165
+ targetDataSource = order === "desc" || emptyToBottom ? valueArr.concat(emptyArr) : emptyArr.concat(valueArr);
166
+ if (sortChildren) {
167
+ targetDataSource.forEach((item) => {
168
+ var _a;
169
+ if (!((_a = item.children) == null ? void 0 : _a.length)) return;
170
+ item.children = tableSort(sortOption, order, item.children, sortConfig);
171
+ });
161
172
  }
162
173
  }
163
174
  return targetDataSource;
@@ -210,6 +221,16 @@ const DEFAULT_SMOOTH_SCROLL = _chromeVersion < 85;
210
221
  const STK_ID_PREFIX = "stk";
211
222
  const EXPANDED_ROW_KEY_PREFIX = "expanded-";
212
223
  const CELL_KEY_SEPARATE = "--";
224
+ const DEFAULT_SORT_CONFIG = {
225
+ emptyToBottom: false,
226
+ stringLocaleCompare: false,
227
+ sortChildren: false
228
+ };
229
+ const DEFAULT_ROW_ACTIVE_CONFIG = {
230
+ enabled: false,
231
+ disabled: () => false,
232
+ revokable: false
233
+ };
213
234
  var TagType = /* @__PURE__ */ ((TagType2) => {
214
235
  TagType2[TagType2["TH"] = 0] = "TH";
215
236
  TagType2[TagType2["TD"] = 1] = "TD";
@@ -817,7 +838,8 @@ function useKeyboardArrowScroll(targetElement, { props, scrollTo, virtualScroll,
817
838
  }
818
839
  function handleKeydown(e) {
819
840
  if (!virtual_on.value) return;
820
- if (!ScrollCodesValues.includes(e.code)) return;
841
+ const keyCode = e.code;
842
+ if (!ScrollCodesValues.includes(keyCode)) return;
821
843
  if (!isMouseOver) return;
822
844
  e.preventDefault();
823
845
  const { scrollTop, rowHeight, containerHeight, scrollHeight } = virtualScroll.value;
@@ -825,21 +847,21 @@ function useKeyboardArrowScroll(targetElement, { props, scrollTo, virtualScroll,
825
847
  const { headless, headerRowHeight } = props;
826
848
  const headerHeight = headless ? 0 : tableHeaders.value.length * (headerRowHeight || rowHeight);
827
849
  const bodyPageSize = Math.floor((containerHeight - headerHeight) / rowHeight);
828
- if (e.code === "ArrowUp") {
850
+ if (keyCode === "ArrowUp") {
829
851
  scrollTo(scrollTop - rowHeight, null);
830
- } else if (e.code === "ArrowRight") {
852
+ } else if (keyCode === "ArrowRight") {
831
853
  scrollTo(null, scrollLeft + 50);
832
- } else if (e.code === "ArrowDown") {
854
+ } else if (keyCode === "ArrowDown") {
833
855
  scrollTo(scrollTop + rowHeight, null);
834
- } else if (e.code === "ArrowLeft") {
856
+ } else if (keyCode === "ArrowLeft") {
835
857
  scrollTo(null, scrollLeft - 50);
836
- } else if (e.code === "PageUp") {
858
+ } else if (keyCode === "PageUp") {
837
859
  scrollTo(scrollTop - rowHeight * bodyPageSize + headerHeight, null);
838
- } else if (e.code === "PageDown") {
860
+ } else if (keyCode === "PageDown") {
839
861
  scrollTo(scrollTop + rowHeight * bodyPageSize - headerHeight, null);
840
- } else if (e.code === "Home") {
862
+ } else if (keyCode === "Home") {
841
863
  scrollTo(0, null);
842
- } else if (e.code === "End") {
864
+ } else if (keyCode === "End") {
843
865
  scrollTo(scrollHeight, null);
844
866
  }
845
867
  }
@@ -886,13 +908,7 @@ function useMaxRowSpan({ props, tableHeaderLast, rowKeyGen, dataSourceCopy }) {
886
908
  updateMaxRowSpan
887
909
  };
888
910
  }
889
- function useMergeCells({
890
- props,
891
- tableHeaderLast,
892
- rowKeyGen,
893
- colKeyGen,
894
- virtual_dataSourcePart
895
- }) {
911
+ function useMergeCells({ rowActiveProp, tableHeaderLast, rowKeyGen, colKeyGen, virtual_dataSourcePart }) {
896
912
  const hiddenCellMap = ref({});
897
913
  const hoverRowMap = ref({});
898
914
  const hoverMergedCells = ref(/* @__PURE__ */ new Set());
@@ -937,13 +953,13 @@ function useMergeCells({
937
953
  const set = rowKey === void 0 ? null : hoverRowMap.value[rowKey];
938
954
  hoverMergedCells.value = set || /* @__PURE__ */ new Set();
939
955
  }
940
- function updateActiveMergedCells(clear) {
941
- if (!props.rowActive) return;
956
+ function updateActiveMergedCells(clear, rowKey) {
957
+ if (!rowActiveProp.value.enabled) return;
942
958
  if (clear) {
943
959
  activeMergedCells.value.clear();
944
- } else {
945
- activeMergedCells.value = new Set(hoverMergedCells.value);
960
+ return;
946
961
  }
962
+ activeMergedCells.value = rowKey !== void 0 && hoverRowMap.value[rowKey] || new Set(hoverMergedCells.value);
947
963
  }
948
964
  return {
949
965
  hiddenCellMap,
@@ -1751,10 +1767,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1751
1767
  autoResize: { type: [Boolean, Function], default: true },
1752
1768
  fixedColShadow: { type: Boolean, default: false },
1753
1769
  optimizeVue2Scroll: { type: Boolean, default: false },
1754
- sortConfig: { default: () => ({
1755
- emptyToBottom: false,
1756
- stringLocaleCompare: false
1757
- }) },
1770
+ sortConfig: { default: () => DEFAULT_SORT_CONFIG },
1758
1771
  hideHeaderTitle: { type: [Boolean, Array], default: false },
1759
1772
  highlightConfig: { default: () => ({}) },
1760
1773
  seqConfig: { default: () => ({}) },
@@ -1788,6 +1801,18 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1788
1801
  const isTreeData = computed(() => {
1789
1802
  return props.columns.some((col) => col.type === "tree-node");
1790
1803
  });
1804
+ const rowActiveProp = computed(() => {
1805
+ const { rowActive } = props;
1806
+ if (typeof rowActive === "boolean") {
1807
+ return {
1808
+ ...DEFAULT_ROW_ACTIVE_CONFIG,
1809
+ enabled: rowActive,
1810
+ revokable: Boolean(props.rowCurrentRevokable)
1811
+ };
1812
+ } else {
1813
+ return { ...DEFAULT_ROW_ACTIVE_CONFIG, ...rowActive };
1814
+ }
1815
+ });
1791
1816
  const dataSourceCopy = shallowRef([]);
1792
1817
  const rowKeyGenComputed = computed(() => {
1793
1818
  const { rowKey } = props;
@@ -1821,7 +1846,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1821
1846
  });
1822
1847
  const SRBRBottomHeight = computed(() => {
1823
1848
  if (!isSRBRActive.value || !props.virtual) return 0;
1824
- return (virtualScroll.value.containerHeight - tableHeaderHeight.value) % virtualScroll.value.rowHeight;
1849
+ const { containerHeight, rowHeight } = virtualScroll.value;
1850
+ return (containerHeight - tableHeaderHeight.value) % rowHeight;
1825
1851
  });
1826
1852
  const rowKeyGenCache = /* @__PURE__ */ new WeakMap();
1827
1853
  const { isSRBRActive } = useScrollRowByRow({ props, tableContainerRef });
@@ -1854,7 +1880,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1854
1880
  updateHoverMergedCells,
1855
1881
  activeMergedCells,
1856
1882
  updateActiveMergedCells
1857
- } = useMergeCells({ props, tableHeaderLast, rowKeyGen, colKeyGen, virtual_dataSourcePart });
1883
+ } = useMergeCells({ rowActiveProp, tableHeaderLast, rowKeyGen, colKeyGen, virtual_dataSourcePart });
1858
1884
  const getFixedColPosition = useGetFixedColPosition({ colKeyGen, tableHeadersForCalc });
1859
1885
  const getFixedStyle = useFixedStyle({
1860
1886
  props,
@@ -2118,8 +2144,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
2118
2144
  if (click) sortOrderIndex.value++;
2119
2145
  sortOrderIndex.value = sortOrderIndex.value % 3;
2120
2146
  let order = sortSwitchOrder[sortOrderIndex.value];
2121
- const sortConfig = { ...props.sortConfig, ...col.sortConfig };
2122
- const defaultSort = sortConfig.defaultSort;
2147
+ const sortConfig = { ...DEFAULT_SORT_CONFIG, ...props.sortConfig, ...col.sortConfig };
2148
+ const { defaultSort } = sortConfig;
2123
2149
  const colKeyGenValue = colKeyGen.value;
2124
2150
  if (!order && defaultSort) {
2125
2151
  const defaultColKey = defaultSort.key || defaultSort.dataIndex;
@@ -2143,30 +2169,30 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
2143
2169
  }
2144
2170
  }
2145
2171
  }
2172
+ let dataSourceTemp = props.dataSource.slice();
2146
2173
  if (!props.sortRemote || options.force) {
2147
2174
  const sortOption = col || defaultSort;
2148
2175
  if (sortOption) {
2149
- dataSourceCopy.value = tableSort(sortOption, order, props.dataSource, sortConfig);
2176
+ dataSourceTemp = tableSort(sortOption, order, dataSourceTemp, sortConfig);
2177
+ dataSourceCopy.value = isTreeData.value ? flatTreeData(dataSourceTemp) : dataSourceTemp;
2150
2178
  }
2151
2179
  }
2152
2180
  if (click || options.emit) {
2153
- emits("sort-change", col, order, toRaw(dataSourceCopy.value), sortConfig);
2181
+ emits("sort-change", col, order, toRaw(dataSourceTemp), sortConfig);
2154
2182
  }
2155
2183
  }
2156
2184
  function onRowClick(e, row, rowIndex) {
2185
+ var _a, _b;
2157
2186
  emits("row-click", e, row, { rowIndex });
2187
+ if ((_b = (_a = rowActiveProp.value).disabled) == null ? void 0 : _b.call(_a, row)) return;
2158
2188
  const isCurrentRow = props.rowKey ? currentRowKey.value === rowKeyGen(row) : currentRow.value === row;
2159
2189
  if (isCurrentRow) {
2160
- if (!props.rowCurrentRevokable) {
2190
+ if (!rowActiveProp.value.revokable) {
2161
2191
  return;
2162
2192
  }
2163
- currentRow.value = void 0;
2164
- currentRowKey.value = void 0;
2165
- updateActiveMergedCells(true);
2193
+ setCurrentRow(void 0, { silent: true });
2166
2194
  } else {
2167
- currentRow.value = row;
2168
- currentRowKey.value = rowKeyGen(row);
2169
- updateActiveMergedCells();
2195
+ setCurrentRow(row, { silent: true });
2170
2196
  }
2171
2197
  emits("current-change", e, row, { select: !isCurrentRow });
2172
2198
  }
@@ -2290,30 +2316,49 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
2290
2316
  updateHoverMergedCells(void 0);
2291
2317
  }
2292
2318
  }
2293
- function setCurrentRow(rowKeyOrRow, option = { silent: false }) {
2294
- if (!dataSourceCopy.value.length) return;
2319
+ function setCurrentRow(rowKeyOrRow, option = { silent: false, deep: false }) {
2295
2320
  const select = rowKeyOrRow !== void 0;
2321
+ const currentRowTemp = currentRow.value;
2296
2322
  if (!select) {
2297
2323
  currentRow.value = void 0;
2298
2324
  currentRowKey.value = void 0;
2325
+ updateActiveMergedCells(true);
2299
2326
  } else if (typeof rowKeyOrRow === "string") {
2300
- const row = dataSourceCopy.value.find((it) => rowKeyGen(it) === rowKeyOrRow);
2327
+ const findRowByKey = (data, key) => {
2328
+ var _a;
2329
+ for (let i = 0; i < data.length; i++) {
2330
+ const item = data[i];
2331
+ if (rowKeyGen(item) === key) {
2332
+ return item;
2333
+ }
2334
+ if (option.deep && ((_a = item.children) == null ? void 0 : _a.length)) {
2335
+ const found = findRowByKey(item.children, key);
2336
+ if (found) {
2337
+ return found;
2338
+ }
2339
+ }
2340
+ }
2341
+ return null;
2342
+ };
2343
+ currentRowKey.value = rowKeyOrRow;
2344
+ updateActiveMergedCells(false, currentRowKey.value);
2345
+ const row = findRowByKey(dataSourceCopy.value || [], rowKeyOrRow);
2301
2346
  if (!row) {
2302
2347
  console.warn("setCurrentRow failed.rowKey:", rowKeyOrRow);
2303
2348
  return;
2304
2349
  }
2305
2350
  currentRow.value = row;
2306
- currentRowKey.value = rowKeyOrRow;
2307
2351
  } else {
2308
2352
  currentRow.value = rowKeyOrRow;
2309
2353
  currentRowKey.value = rowKeyGen(rowKeyOrRow);
2354
+ updateActiveMergedCells(false, currentRowKey.value);
2310
2355
  }
2311
2356
  if (!option.silent) {
2312
2357
  emits(
2313
2358
  "current-change",
2314
2359
  /** no Event */
2315
2360
  null,
2316
- currentRow.value,
2361
+ select ? currentRow.value : currentRowTemp,
2317
2362
  { select }
2318
2363
  );
2319
2364
  }
@@ -2503,7 +2548,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
2503
2548
  "cell-hover": props.cellHover,
2504
2549
  "cell-active": props.cellActive,
2505
2550
  "row-hover": props.rowHover,
2506
- "row-active": props.rowActive,
2551
+ "row-active": rowActiveProp.value.enabled,
2507
2552
  "text-overflow": props.showOverflow,
2508
2553
  "header-text-overflow": props.showHeaderOverflow,
2509
2554
  "fixed-relative-mode": isRelativeMode.value,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stk-table-vue",
3
- "version": "0.8.7",
3
+ "version": "0.8.9",
4
4
  "description": "Simple realtime virtual table for vue3 and vue2.7",
5
5
  "main": "./lib/stk-table-vue.js",
6
6
  "types": "./lib/src/StkTable/index.d.ts",
@@ -59,15 +59,15 @@
59
59
  "postcss-discard-comments": "^6.0.2",
60
60
  "postcss-preset-env": "^9.5.11",
61
61
  "prettier": "^3.2.5",
62
- "stk-table-vue": "^0.8.1",
62
+ "stk-table-vue": "^0.8.7",
63
63
  "typescript": "^5.8.3",
64
- "vite": "^7.0.2",
64
+ "vite": "^7.1.7",
65
65
  "vite-plugin-dts": "3.9.1",
66
66
  "vitepress": "^1.6.4",
67
- "vitepress-demo-plugin": "^1.4.5",
67
+ "vitepress-demo-plugin": "^1.4.7",
68
68
  "vitepress-plugin-llms": "^1.7.5",
69
69
  "vitest": "^3.2.4",
70
- "vue": "^3.5.17",
70
+ "vue": "^3.5.22",
71
71
  "vue-eslint-parser": "^9.4.2"
72
72
  }
73
73
  }
@@ -20,7 +20,7 @@
20
20
  'cell-hover': props.cellHover,
21
21
  'cell-active': props.cellActive,
22
22
  'row-hover': props.rowHover,
23
- 'row-active': props.rowActive,
23
+ 'row-active': rowActiveProp.enabled,
24
24
  'text-overflow': props.showOverflow,
25
25
  'header-text-overflow': props.showHeaderOverflow,
26
26
  'fixed-relative-mode': isRelativeMode,
@@ -253,7 +253,14 @@ import { CSSProperties, computed, nextTick, onMounted, ref, shallowRef, toRaw, w
253
253
  import DragHandle from './components/DragHandle.vue';
254
254
  import SortIcon from './components/SortIcon.vue';
255
255
  import TriangleIcon from './components/TriangleIcon.vue';
256
- import { CELL_KEY_SEPARATE, DEFAULT_ROW_HEIGHT, DEFAULT_SMOOTH_SCROLL, IS_LEGACY_MODE } from './const';
256
+ import {
257
+ CELL_KEY_SEPARATE,
258
+ DEFAULT_ROW_ACTIVE_CONFIG,
259
+ DEFAULT_ROW_HEIGHT,
260
+ DEFAULT_SMOOTH_SCROLL,
261
+ DEFAULT_SORT_CONFIG,
262
+ IS_LEGACY_MODE,
263
+ } from './const';
257
264
  import {
258
265
  AutoRowHeightConfig,
259
266
  ColResizableConfig,
@@ -264,6 +271,7 @@ import {
264
271
  Order,
265
272
  PrivateRowDT,
266
273
  PrivateStkTableColumn,
274
+ RowActiveOption,
267
275
  SeqConfig,
268
276
  SortConfig,
269
277
  SortOption,
@@ -328,8 +336,10 @@ const props = withDefaults(
328
336
  /** 是否高亮鼠标悬浮的行 */
329
337
  rowHover?: boolean;
330
338
  /** 是否高亮选中的行 */
331
- rowActive?: boolean;
332
- /** 当前行再次点击否可以取消 (rowActive=true)*/
339
+ rowActive?: boolean | RowActiveOption<DT>;
340
+ /**
341
+ * @deprecated
342
+ */
333
343
  rowCurrentRevokable?: boolean;
334
344
  /** 表头行高。default = rowHeight */
335
345
  headerRowHeight?: number | string | null;
@@ -473,10 +483,7 @@ const props = withDefaults(
473
483
  autoResize: true,
474
484
  fixedColShadow: false,
475
485
  optimizeVue2Scroll: false,
476
- sortConfig: () => ({
477
- emptyToBottom: false,
478
- stringLocaleCompare: false,
479
- }),
486
+ sortConfig: () => DEFAULT_SORT_CONFIG,
480
487
  hideHeaderTitle: false,
481
488
  highlightConfig: () => ({}),
482
489
  seqConfig: () => ({}),
@@ -709,6 +716,19 @@ const isTreeData = computed(() => {
709
716
  return props.columns.some(col => col.type === 'tree-node');
710
717
  });
711
718
 
719
+ const rowActiveProp = computed<Required<RowActiveOption<DT>>>(() => {
720
+ const { rowActive } = props;
721
+ if (typeof rowActive === 'boolean') {
722
+ return {
723
+ ...DEFAULT_ROW_ACTIVE_CONFIG,
724
+ enabled: rowActive,
725
+ revokable: Boolean(props.rowCurrentRevokable),
726
+ };
727
+ } else {
728
+ return { ...DEFAULT_ROW_ACTIVE_CONFIG, ...rowActive };
729
+ }
730
+ });
731
+
712
732
  const dataSourceCopy = shallowRef<DT[]>([]);
713
733
 
714
734
  const rowKeyGenComputed = computed(() => {
@@ -749,7 +769,8 @@ const SRBRTotalHeight = computed(() => {
749
769
  });
750
770
  const SRBRBottomHeight = computed(() => {
751
771
  if (!isSRBRActive.value || !props.virtual) return 0;
752
- return (virtualScroll.value.containerHeight - tableHeaderHeight.value) % virtualScroll.value.rowHeight;
772
+ const { containerHeight, rowHeight } = virtualScroll.value;
773
+ return (containerHeight - tableHeaderHeight.value) % rowHeight;
753
774
  });
754
775
 
755
776
  const rowKeyGenCache = new WeakMap();
@@ -788,7 +809,7 @@ const {
788
809
  updateHoverMergedCells,
789
810
  activeMergedCells,
790
811
  updateActiveMergedCells,
791
- } = useMergeCells({ props, tableHeaderLast, rowKeyGen, colKeyGen, virtual_dataSourcePart });
812
+ } = useMergeCells({ rowActiveProp, tableHeaderLast, rowKeyGen, colKeyGen, virtual_dataSourcePart });
792
813
 
793
814
  const getFixedColPosition = useGetFixedColPosition({ colKeyGen, tableHeadersForCalc });
794
815
 
@@ -1131,8 +1152,8 @@ function onColumnSort(col: StkTableColumn<DT> | undefined | null, click = true,
1131
1152
  sortOrderIndex.value = sortOrderIndex.value % 3;
1132
1153
 
1133
1154
  let order = sortSwitchOrder[sortOrderIndex.value];
1134
- const sortConfig = { ...props.sortConfig, ...col.sortConfig };
1135
- const defaultSort = sortConfig.defaultSort;
1155
+ const sortConfig: SortConfig<any> = { ...DEFAULT_SORT_CONFIG, ...props.sortConfig, ...col.sortConfig };
1156
+ const { defaultSort } = sortConfig;
1136
1157
  const colKeyGenValue = colKeyGen.value;
1137
1158
 
1138
1159
  if (!order && defaultSort) {
@@ -1158,34 +1179,31 @@ function onColumnSort(col: StkTableColumn<DT> | undefined | null, click = true,
1158
1179
  }
1159
1180
  }
1160
1181
  }
1182
+ let dataSourceTemp: any[] = props.dataSource.slice();
1161
1183
  if (!props.sortRemote || options.force) {
1162
1184
  const sortOption = col || defaultSort;
1163
1185
  if (sortOption) {
1164
- dataSourceCopy.value = tableSort(sortOption, order, props.dataSource, sortConfig);
1186
+ dataSourceTemp = tableSort(sortOption, order, dataSourceTemp, sortConfig);
1187
+ dataSourceCopy.value = isTreeData.value ? flatTreeData(dataSourceTemp) : dataSourceTemp;
1165
1188
  }
1166
1189
  }
1167
- // 只有点击才触发事件
1190
+ // only emit sort-change event when click
1168
1191
  if (click || options.emit) {
1169
- emits('sort-change', col, order, toRaw(dataSourceCopy.value), sortConfig);
1192
+ emits('sort-change', col, order, toRaw(dataSourceTemp), sortConfig);
1170
1193
  }
1171
1194
  }
1172
1195
 
1173
1196
  function onRowClick(e: MouseEvent, row: DT, rowIndex: number) {
1174
1197
  emits('row-click', e, row, { rowIndex });
1198
+ if (rowActiveProp.value.disabled?.(row)) return;
1175
1199
  const isCurrentRow = props.rowKey ? currentRowKey.value === rowKeyGen(row) : currentRow.value === row;
1176
1200
  if (isCurrentRow) {
1177
- if (!props.rowCurrentRevokable) {
1178
- // 不可取消
1201
+ if (!rowActiveProp.value.revokable) {
1179
1202
  return;
1180
1203
  }
1181
- // 点击同一行,取消当前选中行。
1182
- currentRow.value = void 0;
1183
- currentRowKey.value = void 0;
1184
- updateActiveMergedCells(true);
1204
+ setCurrentRow(void 0, { silent: true });
1185
1205
  } else {
1186
- currentRow.value = row;
1187
- currentRowKey.value = rowKeyGen(row);
1188
- updateActiveMergedCells();
1206
+ setCurrentRow(row, { silent: true });
1189
1207
  }
1190
1208
  emits('current-change', e, row, { select: !isCurrentRow });
1191
1209
  }
@@ -1391,27 +1409,47 @@ function onTrMouseLeave(e: MouseEvent) {
1391
1409
  * 选中一行
1392
1410
  * @param {string} rowKeyOrRow selected rowKey, undefined to unselect
1393
1411
  * @param {boolean} option.silent if set true not emit `current-change`. default:false
1412
+ * @param {boolean} option.deep if set true, deep search in children. default:false
1394
1413
  */
1395
- function setCurrentRow(rowKeyOrRow: string | undefined | DT, option = { silent: false }) {
1396
- if (!dataSourceCopy.value.length) return;
1414
+ function setCurrentRow(rowKeyOrRow: string | undefined | DT, option: { silent?: boolean; deep?: boolean } = { silent: false, deep: false }) {
1397
1415
  const select = rowKeyOrRow !== void 0;
1416
+ const currentRowTemp = currentRow.value;
1398
1417
  if (!select) {
1399
1418
  currentRow.value = void 0;
1400
1419
  currentRowKey.value = void 0;
1420
+ updateActiveMergedCells(true);
1401
1421
  } else if (typeof rowKeyOrRow === 'string') {
1402
- const row = dataSourceCopy.value.find(it => rowKeyGen(it) === rowKeyOrRow);
1422
+ const findRowByKey = (data: DT[], key: string): DT | null => {
1423
+ for (let i = 0; i < data.length; i++) {
1424
+ const item = data[i];
1425
+ if (rowKeyGen(item) === key) {
1426
+ return item;
1427
+ }
1428
+ if (option.deep && item.children?.length) {
1429
+ const found = findRowByKey(item.children, key);
1430
+ if (found) {
1431
+ return found;
1432
+ }
1433
+ }
1434
+ }
1435
+ return null;
1436
+ };
1437
+
1438
+ currentRowKey.value = rowKeyOrRow;
1439
+ updateActiveMergedCells(false, currentRowKey.value);
1440
+ const row = findRowByKey(dataSourceCopy.value || [], rowKeyOrRow);
1403
1441
  if (!row) {
1404
1442
  console.warn('setCurrentRow failed.rowKey:', rowKeyOrRow);
1405
1443
  return;
1406
1444
  }
1407
1445
  currentRow.value = row;
1408
- currentRowKey.value = rowKeyOrRow;
1409
1446
  } else {
1410
1447
  currentRow.value = rowKeyOrRow;
1411
1448
  currentRowKey.value = rowKeyGen(rowKeyOrRow);
1449
+ updateActiveMergedCells(false, currentRowKey.value);
1412
1450
  }
1413
1451
  if (!option.silent) {
1414
- emits('current-change', /** no Event */ null, currentRow.value, { select });
1452
+ emits('current-change', /** no Event */ null, select ? currentRow.value : currentRowTemp, { select });
1415
1453
  }
1416
1454
  }
1417
1455
 
@@ -1447,7 +1485,6 @@ function setSorter(colKey: string, order: Order, option: { sortOption?: SortOpti
1447
1485
  const colKeyGenValue = colKeyGen.value;
1448
1486
 
1449
1487
  if (newOption.sort && dataSourceCopy.value?.length) {
1450
- // 如果表格有数据,则进行排序
1451
1488
  const column = newOption.sortOption || tableHeaderLast.value.find(it => colKeyGenValue(it) === sortCol.value);
1452
1489
  if (column) onColumnSort(column, false, { force: option.force ?? true, emit: !newOption.silent });
1453
1490
  else console.warn('Can not find column by key:', sortCol.value);
@@ -1,3 +1,4 @@
1
+ import { RowActiveOption, SortConfig } from './types';
1
2
  import { getBrowsersVersion } from './utils';
2
3
 
3
4
  export const DEFAULT_COL_WIDTH = '100';
@@ -33,5 +34,17 @@ export const STK_ID_PREFIX = 'stk';
33
34
  /** expanded row key prefix */
34
35
  export const EXPANDED_ROW_KEY_PREFIX = 'expanded-';
35
36
 
36
- /** cell key 的分隔符 */
37
+ /** cell key split str */
37
38
  export const CELL_KEY_SEPARATE = '--';
39
+
40
+ export const DEFAULT_SORT_CONFIG = {
41
+ emptyToBottom: false,
42
+ stringLocaleCompare: false,
43
+ sortChildren: false,
44
+ } satisfies SortConfig<any>;
45
+
46
+ export const DEFAULT_ROW_ACTIVE_CONFIG: Required<RowActiveOption<any>> = {
47
+ enabled: false,
48
+ disabled: () => false,
49
+ revokable: false,
50
+ };
@@ -88,7 +88,7 @@ export type StkTableColumn<T extends Record<string, any>> = {
88
88
  /** 排序方式。按数字/字符串 */
89
89
  sortType?: 'number' | 'string';
90
90
  /** 配置当前列的排序规则 */
91
- sortConfig?: Pick<SortConfig<T>, 'emptyToBottom' | 'stringLocaleCompare'>;
91
+ sortConfig?: Omit<SortConfig<T>, 'defaultSort'>;
92
92
  /** 固定列 */
93
93
  fixed?: 'left' | 'right' | null;
94
94
  /**
@@ -176,17 +176,17 @@ export type UniqKeyFun = (param: any) => UniqKey;
176
176
  export type UniqKeyProp = UniqKey | UniqKeyFun;
177
177
 
178
178
  export type SortConfig<T extends Record<string, any>> = {
179
- /** 空值始终排在列表末尾 */
180
- emptyToBottom?: boolean;
181
179
  /**
182
- * 默认排序(1.初始化时触发 2.排序方向为null时触发)
183
- * 类似onMounted时,调用setSorter点了下表头。
180
+ * 1. trigger when init
181
+ * 2. trigger when sort direction is null
184
182
  */
185
183
  defaultSort?: {
186
184
  /**
187
- * 列唯一键,
185
+ * colKey
186
+ *
187
+ * if set `props.colKey`
188
188
  *
189
- * 如果您配了 `props.colKey` 则这里表示的列唯一键的值
189
+ * default: StkTableColumn<T>['dataIndex']
190
190
  */
191
191
  key?: StkTableColumn<T>['key'];
192
192
  dataIndex: StkTableColumn<T>['dataIndex'];
@@ -194,14 +194,22 @@ export type SortConfig<T extends Record<string, any>> = {
194
194
  sortField?: StkTableColumn<T>['sortField'];
195
195
  sortType?: StkTableColumn<T>['sortType'];
196
196
  sorter?: StkTableColumn<T>['sorter'];
197
- /** 是否禁止触发sort-change事件。默认false,表示触发事件。 */
197
+ /**
198
+ * whether to disable trigger`sort-change` event. default: false
199
+ */
198
200
  silent?: boolean;
199
201
  };
202
+ /** empty value always sort to bottom */
203
+ emptyToBottom?: boolean;
200
204
  /**
201
205
  * string sort if use `String.prototype.localCompare`
202
206
  * default: false
203
207
  */
204
208
  stringLocaleCompare?: boolean;
209
+ /**
210
+ * whether to sort children when sort current column. default: false
211
+ */
212
+ sortChildren?: boolean;
205
213
  };
206
214
 
207
215
  /** th td type */
@@ -242,7 +250,6 @@ export type DragRowConfig = {
242
250
  // disabled?: (row: T, rowIndex: number) => boolean;
243
251
  };
244
252
 
245
- /** 树形配置 */
246
253
  export type TreeConfig = {
247
254
  // childrenField?: string;
248
255
  defaultExpandAll?: boolean;
@@ -253,13 +260,13 @@ export type TreeConfig = {
253
260
  /** header drag config */
254
261
  export type HeaderDragConfig<DT extends Record<string, any> = any> = {
255
262
  /**
256
- * 列交换模式
257
- * - none - 不做任何事
258
- * - insert - 插入(默认值)
259
- * - swap - 交换
263
+ * col switch mode
264
+ * - none
265
+ * - insert - (default)
266
+ * - swap
260
267
  */
261
268
  mode?: 'none' | 'insert' | 'swap';
262
- /** 禁用拖动的列 */
269
+ /** disabled drag col */
263
270
  disabled?: (col: StkTableColumn<DT>) => boolean;
264
271
  };
265
272
 
@@ -277,3 +284,11 @@ export type RowKeyGen = (row: any) => UniqKey;
277
284
  export type ColKeyGen = ComputedRef<(col: StkTableColumn<any>) => UniqKey>;
278
285
 
279
286
  export type CellKeyGen = (row: any, col: StkTableColumn<any>) => string;
287
+
288
+ export type RowActiveOption<DT> = {
289
+ enabled?: boolean;
290
+ /** disabled row active */
291
+ disabled?: (row: DT) => boolean;
292
+ /** current row again click can revoke active */
293
+ revokable?: boolean;
294
+ };
@@ -64,7 +64,8 @@ export function useKeyboardArrowScroll<DT extends Record<string, any>>(
64
64
  /** 键盘按下事件 */
65
65
  function handleKeydown(e: KeyboardEvent) {
66
66
  if (!virtual_on.value) return; // 非虚拟滚动使用浏览器默认滚动
67
- if (!ScrollCodesValues.includes(e.code as any)) return;
67
+ const keyCode = e.code;
68
+ if (!ScrollCodesValues.includes(keyCode as any)) return;
68
69
  if (!isMouseOver) return; // 不悬浮还是要触发键盘事件的
69
70
  e.preventDefault(); // 不触发键盘默认的箭头事件
70
71
 
@@ -76,22 +77,21 @@ export function useKeyboardArrowScroll<DT extends Record<string, any>>(
76
77
  const headerHeight = headless ? 0 : tableHeaders.value.length * (headerRowHeight || rowHeight);
77
78
  /** 表体的page */
78
79
  const bodyPageSize = Math.floor((containerHeight - headerHeight) / rowHeight);
79
-
80
- if (e.code === ScrollCodes.ArrowUp) {
80
+ if (keyCode=== ScrollCodes.ArrowUp) {
81
81
  scrollTo(scrollTop - rowHeight, null);
82
- } else if (e.code === ScrollCodes.ArrowRight) {
82
+ } else if (keyCode=== ScrollCodes.ArrowRight) {
83
83
  scrollTo(null, scrollLeft + 50);
84
- } else if (e.code === ScrollCodes.ArrowDown) {
84
+ } else if (keyCode=== ScrollCodes.ArrowDown) {
85
85
  scrollTo(scrollTop + rowHeight, null);
86
- } else if (e.code === ScrollCodes.ArrowLeft) {
86
+ } else if (keyCode=== ScrollCodes.ArrowLeft) {
87
87
  scrollTo(null, scrollLeft - 50);
88
- } else if (e.code === ScrollCodes.PageUp) {
88
+ } else if (keyCode=== ScrollCodes.PageUp) {
89
89
  scrollTo(scrollTop - rowHeight * bodyPageSize + headerHeight, null);
90
- } else if (e.code === ScrollCodes.PageDown) {
90
+ } else if (keyCode=== ScrollCodes.PageDown) {
91
91
  scrollTo(scrollTop + rowHeight * bodyPageSize - headerHeight, null);
92
- } else if (e.code === ScrollCodes.Home) {
92
+ } else if (keyCode=== ScrollCodes.Home) {
93
93
  scrollTo(0, null);
94
- } else if (e.code === ScrollCodes.End) {
94
+ } else if (keyCode=== ScrollCodes.End) {
95
95
  scrollTo(scrollHeight, null);
96
96
  }
97
97
  }
@@ -1,20 +1,14 @@
1
- import { ref, ShallowRef, watch } from 'vue';
2
- import { ColKeyGen, MergeCellsParam, PrivateStkTableColumn, RowKeyGen, UniqKey } from './types';
1
+ import { Ref, ref, ShallowRef, watch } from 'vue';
2
+ import { ColKeyGen, MergeCellsParam, PrivateStkTableColumn, RowActiveOption, RowKeyGen, UniqKey } from './types';
3
3
  import { pureCellKeyGen } from './utils';
4
4
  type Options = {
5
- props: any;
5
+ rowActiveProp: Ref<RowActiveOption<any>>;
6
6
  tableHeaderLast: ShallowRef<PrivateStkTableColumn<any>[]>;
7
7
  rowKeyGen: RowKeyGen;
8
8
  colKeyGen: ColKeyGen;
9
9
  virtual_dataSourcePart: ShallowRef<any[]>;
10
- }
11
- export function useMergeCells({
12
- props,
13
- tableHeaderLast,
14
- rowKeyGen,
15
- colKeyGen,
16
- virtual_dataSourcePart,
17
- }:Options ) {
10
+ };
11
+ export function useMergeCells({ rowActiveProp, tableHeaderLast, rowKeyGen, colKeyGen, virtual_dataSourcePart }: Options) {
18
12
  /**
19
13
  * which cell need be hidden
20
14
  * - key: rowKey
@@ -33,13 +27,12 @@ export function useMergeCells({
33
27
  /** click current row , which rowspan cells should be highlight */
34
28
  const activeMergedCells = ref(new Set<string>());
35
29
 
36
-
37
30
  watch([virtual_dataSourcePart, tableHeaderLast], () => {
38
31
  hiddenCellMap.value = {};
39
32
  hoverRowMap.value = {};
40
33
  });
41
34
 
42
- /**
35
+ /**
43
36
  * abstract the logic of hiding cells
44
37
  */
45
38
  function hideCells(rowKey: UniqKey, startIndex: number, count: number, isSelfRow = false, mergeCellKey: string) {
@@ -84,14 +77,14 @@ export function useMergeCells({
84
77
  if (colspan === 1 && rowspan === 1) return;
85
78
 
86
79
  const rowKey = rowKeyGen(row);
87
-
80
+
88
81
  const colKey = colKeyGen.value(col);
89
82
  const curColIndex = tableHeaderLast.value.findIndex(item => colKeyGen.value(item) === colKey);
90
83
  const curRowIndex = virtual_dataSourcePart.value.findIndex(item => rowKeyGen(item) === rowKey);
91
84
  const mergedCellKey = pureCellKeyGen(rowKey, colKey);
92
85
 
93
86
  if (curRowIndex === -1) return;
94
-
87
+
95
88
  for (let i = curRowIndex; i < curRowIndex + rowspan; i++) {
96
89
  const row = virtual_dataSourcePart.value[i];
97
90
  if (!row) break;
@@ -106,13 +99,13 @@ export function useMergeCells({
106
99
  hoverMergedCells.value = set || new Set();
107
100
  }
108
101
 
109
- function updateActiveMergedCells(clear?: boolean) {
110
- if (!props.rowActive) return;
102
+ function updateActiveMergedCells(clear?: boolean, rowKey?: UniqKey) {
103
+ if (!rowActiveProp.value.enabled) return;
111
104
  if (clear) {
112
105
  activeMergedCells.value.clear();
113
- } else {
114
- activeMergedCells.value = new Set(hoverMergedCells.value);
106
+ return;
115
107
  }
108
+ activeMergedCells.value = (rowKey !== void 0 && hoverRowMap.value[rowKey]) || new Set(hoverMergedCells.value);
116
109
  }
117
110
 
118
111
  return {
@@ -1,4 +1,4 @@
1
- import { CELL_KEY_SEPARATE } from '../const';
1
+ import { CELL_KEY_SEPARATE, DEFAULT_SORT_CONFIG } from '../const';
2
2
  import { Order, SortConfig, SortOption, SortState, StkTableColumn, UniqKey } from '../types';
3
3
 
4
4
  /** 是否空值 */
@@ -158,19 +158,28 @@ export function tableSort<T extends Record<string, any>>(
158
158
  ): T[] {
159
159
  if (!dataSource?.length || !sortOption) return dataSource || [];
160
160
 
161
- sortConfig = { emptyToBottom: false, ...sortConfig };
161
+ sortConfig = { ...DEFAULT_SORT_CONFIG, ...sortConfig };
162
162
  let targetDataSource = dataSource.slice();
163
163
  let sortField = sortOption.sortField || sortOption.dataIndex;
164
+ const { defaultSort, stringLocaleCompare, emptyToBottom, sortChildren } = sortConfig;
164
165
 
165
- if (!order && sortConfig.defaultSort) {
166
+ if (!order && defaultSort) {
166
167
  // 默认排序
167
- order = sortConfig.defaultSort.order;
168
- sortField = sortConfig.defaultSort.dataIndex;
168
+ order = defaultSort.order;
169
+ sortField = defaultSort.dataIndex;
169
170
  }
170
171
 
171
172
  if (typeof sortOption.sorter === 'function') {
172
173
  const customSorterData = sortOption.sorter(targetDataSource, { order, column: sortOption });
173
174
  if (customSorterData) targetDataSource = customSorterData;
175
+
176
+ // 如果开启了子节点排序且使用了自定义排序器,递归排序children
177
+ if (sortChildren) {
178
+ targetDataSource.forEach(item => {
179
+ if (!item.children?.length) return;
180
+ (item as any).children = tableSort(sortOption, order, item.children, sortConfig);
181
+ });
182
+ }
174
183
  } else if (order) {
175
184
  let { sortType } = sortOption;
176
185
  if (!sortType) sortType = typeof dataSource[0][sortField] as 'number' | 'string';
@@ -179,15 +188,19 @@ export function tableSort<T extends Record<string, any>>(
179
188
  const [valueArr, emptyArr] = separatedData(sortOption, targetDataSource, isNumber);
180
189
 
181
190
  if (order === 'asc') {
182
- valueArr.sort((a, b) => strCompare(a[sortField], b[sortField], isNumber, sortConfig.stringLocaleCompare));
191
+ valueArr.sort((a, b) => strCompare(a[sortField], b[sortField], isNumber, stringLocaleCompare));
183
192
  } else {
184
- valueArr.sort((a, b) => strCompare(b[sortField], a[sortField], isNumber, sortConfig.stringLocaleCompare));
193
+ valueArr.sort((a, b) => strCompare(b[sortField], a[sortField], isNumber, stringLocaleCompare));
185
194
  }
186
195
 
187
- if (order === 'desc' || sortConfig.emptyToBottom) {
188
- targetDataSource = valueArr.concat(emptyArr);
189
- } else {
190
- targetDataSource = emptyArr.concat(valueArr);
196
+ targetDataSource = order === 'desc' || emptyToBottom ? valueArr.concat(emptyArr) : emptyArr.concat(valueArr);
197
+
198
+ // 递归排序子节点
199
+ if (sortChildren) {
200
+ targetDataSource.forEach(item => {
201
+ if (!item.children?.length) return;
202
+ (item as any).children = tableSort(sortOption, order, item.children, sortConfig);
203
+ });
191
204
  }
192
205
  }
193
206
  return targetDataSource;