Skip to content

Commit a6a270b

Browse files
committed
refactor: table
1 parent 8472c25 commit a6a270b

File tree

16 files changed

+175
-96
lines changed

16 files changed

+175
-96
lines changed

components/_util/extendsObject.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
type RecordType = Record<string, any>;
2+
3+
function extendsObject<T extends RecordType>(...list: T[]) {
4+
const result: RecordType = { ...list[0] };
5+
6+
for (let i = 1; i < list.length; i++) {
7+
const obj = list[i];
8+
if (obj) {
9+
Object.keys(obj).forEach(key => {
10+
const val = obj[key];
11+
if (val !== undefined) {
12+
result[key] = val;
13+
}
14+
});
15+
}
16+
}
17+
18+
return result;
19+
}
20+
21+
export default extendsObject;

components/table/ExpandIcon.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ function renderExpandIcon(locale: TableLocale) {
3232
[`${iconPrefix}-collapsed`]: expandable && !expanded,
3333
})}
3434
aria-label={expanded ? locale.collapse : locale.expand}
35+
aria-expanded={expanded}
3536
/>
3637
);
3738
};

components/table/Table.tsx

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -383,9 +383,19 @@ const InteralTable = defineComponent<
383383

384384
const [transformBasicColumns] = useColumns(toRef(props, 'contextSlots'));
385385

386-
const columnTitleProps = computed(() => ({
387-
...sorterTitleProps.value,
388-
}));
386+
const columnTitleProps = computed(() => {
387+
const mergedFilters: Record<string, FilterValue> = {};
388+
const filtersValue = filters.value;
389+
Object.keys(filtersValue).forEach(filterKey => {
390+
if (filtersValue[filterKey] !== null) {
391+
mergedFilters[filterKey] = filtersValue[filterKey]!;
392+
}
393+
});
394+
return {
395+
...sorterTitleProps.value,
396+
filters: mergedFilters,
397+
};
398+
});
389399
const [transformTitleColumns] = useTitleColumns(columnTitleProps);
390400

391401
// ========================== Pagination ==========================
@@ -413,7 +423,7 @@ const InteralTable = defineComponent<
413423
changeEventInfo.pagination =
414424
props.pagination === false
415425
? {}
416-
: getPaginationParam(props.pagination, mergedPagination.value);
426+
: getPaginationParam(mergedPagination.value, props.pagination);
417427

418428
changeEventInfo.resetPagination = resetPagination;
419429
});
@@ -556,8 +566,8 @@ const InteralTable = defineComponent<
556566
const defaultPosition = direction.value === 'rtl' ? 'left' : 'right';
557567
const { position } = mergedPagination.value;
558568
if (position !== null && Array.isArray(position)) {
559-
const topPos = position.find(p => p.indexOf('top') !== -1);
560-
const bottomPos = position.find(p => p.indexOf('bottom') !== -1);
569+
const topPos = position.find(p => p.includes('top'));
570+
const bottomPos = position.find(p => p.includes('bottom'));
561571
const isDisable = position.every(p => `${p}` === 'none');
562572
if (!topPos && !bottomPos && !isDisable) {
563573
bottomPaginationNode = renderPagination(defaultPosition);

components/table/__tests__/Table.filter.test.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,14 @@ describe('Table.filter', () => {
140140
});
141141
});
142142
// TODO
143-
xit('can be controlled by filterDropdownVisible', done => {
143+
xit('can be controlled by filterDropdownOpen', done => {
144144
const wrapper = mount(
145145
Table,
146146
getTableOptions({
147147
columns: [
148148
{
149149
...column,
150-
filterDropdownVisible: true,
150+
filterDropdownOpen: true,
151151
},
152152
],
153153
}),
@@ -160,7 +160,7 @@ describe('Table.filter', () => {
160160
columns: [
161161
{
162162
...column,
163-
filterDropdownVisible: false,
163+
filterDropdownOpen: false,
164164
},
165165
],
166166
});
@@ -179,7 +179,7 @@ describe('Table.filter', () => {
179179
columns: [
180180
{
181181
...column,
182-
onFilterDropdownVisibleChange: handleChange,
182+
onFilterDropdownOpenChange: handleChange,
183183
},
184184
],
185185
}),

components/table/__tests__/Table.rowSelection.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ describe('Table.rowSelection', () => {
525525
value: 'Lucy',
526526
},
527527
],
528-
filterDropdownVisible: true,
528+
filterDropdownOpen: true,
529529
onFilter: (value, record) => record.name.indexOf(value) === 0,
530530
},
531531
];

components/table/demo/custom-filter-panel.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ export default defineComponent({
123123
customFilterDropdown: true,
124124
onFilter: (value, record) =>
125125
record.name.toString().toLowerCase().includes(value.toLowerCase()),
126-
onFilterDropdownVisibleChange: visible => {
126+
onFilterDropdownOpenChange: visible => {
127127
if (visible) {
128128
setTimeout(() => {
129129
searchInput.value.focus();
@@ -143,7 +143,7 @@ export default defineComponent({
143143
customFilterDropdown: true,
144144
onFilter: (value, record) =>
145145
record.address.toString().toLowerCase().includes(value.toLowerCase()),
146-
onFilterDropdownVisibleChange: visible => {
146+
onFilterDropdownOpenChange: visible => {
147147
if (visible) {
148148
setTimeout(() => {
149149
searchInput.value.focus();

components/table/hooks/useFilter/FilterDropdown.tsx

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import isEqual from 'lodash-es/isEqual';
21
import FilterFilled from '@ant-design/icons-vue/FilterFilled';
32
import Button from '../../../button';
43
import Menu from '../../../menu';
@@ -26,6 +25,8 @@ import type { EventHandler } from '../../../_util/EventInterface';
2625
import FilterSearch from './FilterSearch';
2726
import Tree from '../../../tree';
2827
import type { CheckboxChangeEvent } from '../../../checkbox/interface';
28+
import devWarning from '../../../vc-util/devWarning';
29+
import isEqual from '../../../vc-util/isEqual';
2930

3031
interface FilterRestProps {
3132
confirm?: Boolean;
@@ -99,7 +100,7 @@ function renderFilterItems({
99100
return item;
100101
});
101102
}
102-
103+
export type TreeColumnFilterItem = ColumnFilterItem;
103104
export interface FilterDropdownProps<RecordType> {
104105
tablePrefixCls: string;
105106
prefixCls: string;
@@ -108,7 +109,7 @@ export interface FilterDropdownProps<RecordType> {
108109
filterState?: FilterState<RecordType>;
109110
filterMultiple: boolean;
110111
filterMode?: 'menu' | 'tree';
111-
filterSearch?: FilterSearchType;
112+
filterSearch?: FilterSearchType<ColumnFilterItem | TreeColumnFilterItem>;
112113
columnKey: Key;
113114
triggerFilter: (filterState: FilterState<RecordType>) => void;
114115
locale: TableLocale;
@@ -136,7 +137,29 @@ export default defineComponent<FilterDropdownProps<any>>({
136137
const contextSlots = useInjectSlots();
137138
const filterMode = computed(() => props.filterMode ?? 'menu');
138139
const filterSearch = computed(() => props.filterSearch ?? false);
139-
const filterDropdownVisible = computed(() => props.column.filterDropdownVisible);
140+
const filterDropdownOpen = computed(
141+
() => props.column.filterDropdownOpen || props.column.filterDropdownVisible,
142+
);
143+
const onFilterDropdownOpenChange = computed(
144+
() => props.column.onFilterDropdownOpenChange || props.column.onFilterDropdownVisibleChange,
145+
);
146+
147+
if (process.env.NODE_ENV !== 'production') {
148+
[
149+
['filterDropdownVisible', 'filterDropdownOpen', props.column.filterDropdownVisible],
150+
[
151+
'onFilterDropdownVisibleChange',
152+
'onFilterDropdownOpenChange',
153+
props.column.onFilterDropdownVisibleChange,
154+
],
155+
].forEach(([deprecatedName, newName, prop]) => {
156+
devWarning(
157+
prop === undefined || prop === null,
158+
'Table',
159+
`\`${deprecatedName}\` is deprecated. Please use \`${newName}\` instead.`,
160+
);
161+
});
162+
}
140163
const visible = ref(false);
141164
const filtered = computed(
142165
() =>
@@ -166,13 +189,11 @@ export default defineComponent<FilterDropdownProps<any>>({
166189

167190
const triggerVisible = (newVisible: boolean) => {
168191
visible.value = newVisible;
169-
props.column.onFilterDropdownVisibleChange?.(newVisible);
192+
onFilterDropdownOpenChange.value?.(newVisible);
170193
};
171194

172195
const mergedVisible = computed(() =>
173-
typeof filterDropdownVisible.value === 'boolean'
174-
? filterDropdownVisible.value
175-
: visible.value,
196+
typeof filterDropdownOpen.value === 'boolean' ? filterDropdownOpen.value : visible.value,
176197
);
177198

178199
const propFilteredKeys = computed(() => props.filterState?.filteredKeys);
@@ -234,14 +255,14 @@ export default defineComponent<FilterDropdownProps<any>>({
234255
});
235256

236257
// ======================= Submit ========================
237-
const internalTriggerFilter = (keys: Key[] | undefined | null) => {
258+
const internalTriggerFilter = (keys?: Key[]) => {
238259
const { column, columnKey, filterState } = props;
239260
const mergedKeys = keys && keys.length ? keys : null;
240261
if (mergedKeys === null && (!filterState || !filterState.filteredKeys)) {
241262
return null;
242263
}
243264

244-
if (isEqual(mergedKeys, filterState?.filteredKeys)) {
265+
if (isEqual(mergedKeys, filterState?.filteredKeys, true)) {
245266
return null;
246267
}
247268

@@ -318,6 +339,13 @@ export default defineComponent<FilterDropdownProps<any>>({
318339
return item;
319340
});
320341

342+
const getFilterData = (node: any): TreeColumnFilterItem => ({
343+
...node,
344+
text: node.title,
345+
value: node.key,
346+
children: node.children?.map(item => getFilterData(item)) || [],
347+
});
348+
321349
const treeData = computed(() => getTreeData({ filters: props.column.filters }));
322350
// ======================== Style ========================
323351
const dropdownMenuClass = computed(() =>
@@ -394,7 +422,12 @@ export default defineComponent<FilterDropdownProps<any>>({
394422
// onExpand={onExpandChange}
395423
filterTreeNode={
396424
searchValue.value.trim()
397-
? node => searchValueMatched(searchValue.value, node.title)
425+
? node => {
426+
if (typeof filterSearch.value === 'function') {
427+
return filterSearch.value(searchValue.value, getFilterData(node));
428+
}
429+
return searchValueMatched(searchValue.value, node.title);
430+
}
398431
: undefined
399432
}
400433
/>
@@ -443,6 +476,7 @@ export default defineComponent<FilterDropdownProps<any>>({
443476
return isEqual(
444477
(props.column.defaultFilteredValue || []).map(key => String(key)),
445478
selectedKeys,
479+
true,
446480
);
447481
}
448482

@@ -464,6 +498,9 @@ export default defineComponent<FilterDropdownProps<any>>({
464498
filters: column.filters,
465499
visible: mergedVisible.value,
466500
column: column.__originColumn__,
501+
close: () => {
502+
triggerVisible(false);
503+
},
467504
});
468505
} else if (filterDropdownRef.value) {
469506
dropdownContent = filterDropdownRef.value;
@@ -512,8 +549,8 @@ export default defineComponent<FilterDropdownProps<any>>({
512549
<Dropdown
513550
overlay={menu}
514551
trigger={['click']}
515-
visible={mergedVisible.value}
516-
onVisibleChange={onVisibleChange}
552+
open={mergedVisible.value}
553+
onOpenChange={onVisibleChange}
517554
getPopupContainer={getPopupContainer}
518555
placement={direction.value === 'rtl' ? 'bottomLeft' : 'bottomRight'}
519556
>
Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
1+
import KeyCode from '../../../_util/KeyCode';
2+
import type { KeyboardEventHandler } from '../../../_util/EventInterface';
3+
4+
const onKeyDown: KeyboardEventHandler = event => {
5+
const { keyCode } = event;
6+
if (keyCode === KeyCode.ENTER) {
7+
event.stopPropagation();
8+
}
9+
};
110
const FilterDropdownMenuWrapper = (_props, { slots }) => (
2-
<div onClick={e => e.stopPropagation()}>{slots.default?.()}</div>
11+
<div onClick={e => e.stopPropagation()} onKeydown={onKeyDown}>
12+
{slots.default?.()}
13+
</div>
314
);
415

516
export default FilterDropdownMenuWrapper;

components/table/hooks/useFilter/index.tsx

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ function injectFilter<RecordType>(
7474
dropdownPrefixCls: string,
7575
columns: ColumnsType<RecordType>,
7676
filterStates: FilterState<RecordType>[],
77-
triggerFilter: (filterState: FilterState<RecordType>) => void,
78-
getPopupContainer: GetPopupContainer | undefined,
7977
locale: TableLocale,
78+
triggerFilter: (filterState: FilterState<RecordType>) => void,
79+
getPopupContainer?: GetPopupContainer | undefined,
8080
pos?: string,
8181
): ColumnsType<RecordType> {
8282
return columns.map((column, index) => {
@@ -121,9 +121,9 @@ function injectFilter<RecordType>(
121121
dropdownPrefixCls,
122122
newColumn.children,
123123
filterStates,
124+
locale,
124125
triggerFilter,
125126
getPopupContainer,
126-
locale,
127127
columnPos,
128128
),
129129
};
@@ -217,7 +217,9 @@ function useFilter<RecordType>({
217217

218218
const mergedFilterStates = computed(() => {
219219
const collectedStates = collectFilterStates(mergedColumns.value, false);
220-
220+
if (collectedStates.length === 0) {
221+
return collectedStates;
222+
}
221223
let filteredKeysIsAllNotControlled = true;
222224
let filteredKeysIsAllControlled = true;
223225
collectedStates.forEach(({ filteredKeys }) => {
@@ -230,7 +232,23 @@ function useFilter<RecordType>({
230232

231233
// Return if not controlled
232234
if (filteredKeysIsAllNotControlled) {
233-
return filterStates.value;
235+
// Filter column may have been removed
236+
const keyList = (mergedColumns.value || []).map((column, index) =>
237+
getColumnKey(column, getColumnPos(index)),
238+
);
239+
return filterStates.value
240+
.filter(({ key }) => keyList.includes(key))
241+
.map(item => {
242+
const col = mergedColumns.value[keyList.findIndex(key => key === item.key)];
243+
return {
244+
...item,
245+
column: {
246+
...item.column,
247+
...col,
248+
},
249+
forceFiltered: col.filtered,
250+
};
251+
});
234252
}
235253

236254
devWarning(
@@ -257,9 +275,9 @@ function useFilter<RecordType>({
257275
dropdownPrefixCls.value,
258276
innerColumns,
259277
mergedFilterStates.value,
278+
locale.value,
260279
triggerFilter,
261280
getPopupContainer.value,
262-
locale.value,
263281
);
264282
};
265283
return [transformColumns, mergedFilterStates, filters];

0 commit comments

Comments
 (0)