diff --git a/components/locale/default.tsx b/components/locale/default.tsx index d12c1a89de..06cea25102 100644 --- a/components/locale/default.tsx +++ b/components/locale/default.tsx @@ -24,6 +24,7 @@ const localeValues: Locale = { emptyText: 'No data', selectAll: 'Select current page', selectInvert: 'Invert current page', + selectNone: 'Clear all data', selectionAll: 'Select all data', sortTitle: 'Sort', expand: 'Expand row', diff --git a/components/locale/zh_CN.tsx b/components/locale/zh_CN.tsx index 425de93dd3..79635e5613 100644 --- a/components/locale/zh_CN.tsx +++ b/components/locale/zh_CN.tsx @@ -24,6 +24,7 @@ const localeValues: Locale = { filterEmptyText: '无筛选项', selectAll: '全选当页', selectInvert: '反选当页', + selectNone: '清空所有', selectionAll: '全选所有', sortTitle: '排序', expand: '展开行', diff --git a/components/locale/zh_HK.tsx b/components/locale/zh_HK.tsx index 193b83ab1a..8a148c892a 100644 --- a/components/locale/zh_HK.tsx +++ b/components/locale/zh_HK.tsx @@ -23,6 +23,7 @@ const localeValues: Locale = { filterEmptyText: '無篩選項', selectAll: '全部選取', selectInvert: '反向選取', + selectNone: '清空所有', selectionAll: '全選所有', sortTitle: '排序', expand: '展開行', diff --git a/components/locale/zh_TW.tsx b/components/locale/zh_TW.tsx index 5139e673d9..6dcbb8324f 100644 --- a/components/locale/zh_TW.tsx +++ b/components/locale/zh_TW.tsx @@ -23,6 +23,7 @@ const localeValues: Locale = { filterEmptyText: '無篩選項', selectAll: '全部選取', selectInvert: '反向選取', + selectNone: '清空所有', selectionAll: '全選所有', sortTitle: '排序', expand: '展開行', diff --git a/components/table/Table.tsx b/components/table/Table.tsx index 5136a097d7..5639b088df 100644 --- a/components/table/Table.tsx +++ b/components/table/Table.tsx @@ -26,7 +26,11 @@ import { TableLocale, TableAction, } from './interface'; -import useSelection, { SELECTION_ALL, SELECTION_INVERT } from './hooks/useSelection'; +import useSelection, { + SELECTION_ALL, + SELECTION_INVERT, + SELECTION_NONE, +} from './hooks/useSelection'; import useSorter, { getSortData, SortState } from './hooks/useSorter'; import useFilter, { getFilterData, FilterState } from './hooks/useFilter'; import useTitleColumns from './hooks/useTitleColumns'; @@ -509,6 +513,7 @@ Table.defaultProps = { Table.SELECTION_ALL = SELECTION_ALL; Table.SELECTION_INVERT = SELECTION_INVERT; +Table.SELECTION_NONE = SELECTION_NONE; Table.Column = Column; Table.ColumnGroup = ColumnGroup; Table.Summary = Summary; diff --git a/components/table/__tests__/Table.rowSelection.test.js b/components/table/__tests__/Table.rowSelection.test.js index fa5a51d95d..9c356d1a1a 100644 --- a/components/table/__tests__/Table.rowSelection.test.js +++ b/components/table/__tests__/Table.rowSelection.test.js @@ -294,11 +294,28 @@ describe('Table.rowSelection', () => { checkboxes.at(1).simulate('change', { target: { checked: true } }); const dropdownWrapper = mount(wrapper.find('Trigger').instance().getComponent()); - dropdownWrapper.find('.ant-dropdown-menu-item').last().simulate('click'); + dropdownWrapper.find('.ant-dropdown-menu-item').at(1).simulate('click'); expect(handleSelectInvert).toHaveBeenCalledWith([1, 2, 3]); }); + it('fires selectNone event', () => { + const handleSelectNone = jest.fn(); + const rowSelection = { + onSelectNone: handleSelectNone, + selections: true, + }; + const wrapper = mount(createTable({ rowSelection })); + const checkboxes = wrapper.find('input'); + + checkboxes.at(1).simulate('change', { target: { checked: true } }); + + const dropdownWrapper = mount(wrapper.find('Trigger').instance().getComponent()); + dropdownWrapper.find('.ant-dropdown-menu-item').last().simulate('click'); + + expect(handleSelectNone).toHaveBeenCalled(); + }); + it('fires selection event', () => { const handleSelectOdd = jest.fn(); const handleSelectEven = jest.fn(); diff --git a/components/table/__tests__/__snapshots__/Table.rowSelection.test.js.snap b/components/table/__tests__/__snapshots__/Table.rowSelection.test.js.snap index 221eec1058..adb6ad8554 100644 --- a/components/table/__tests__/__snapshots__/Table.rowSelection.test.js.snap +++ b/components/table/__tests__/__snapshots__/Table.rowSelection.test.js.snap @@ -984,6 +984,12 @@ exports[`Table.rowSelection render with default selection correctly 1`] = ` > Invert current page + @@ -1093,6 +1099,12 @@ exports[`Table.rowSelection should support getPopupContainer 1`] = ` > Invert current page + @@ -1420,6 +1432,12 @@ exports[`Table.rowSelection should support getPopupContainer from ConfigProvider > Invert current page + diff --git a/components/table/demo/row-selection-custom.md b/components/table/demo/row-selection-custom.md index 4e150e1389..490f353e9f 100644 --- a/components/table/demo/row-selection-custom.md +++ b/components/table/demo/row-selection-custom.md @@ -59,6 +59,7 @@ class App extends React.Component { selections: [ Table.SELECTION_ALL, Table.SELECTION_INVERT, + Table.SELECTION_NONE, { key: 'odd', text: 'Select Odd Row', diff --git a/components/table/hooks/useSelection.tsx b/components/table/hooks/useSelection.tsx index 36e99d2bcc..f224535c44 100644 --- a/components/table/hooks/useSelection.tsx +++ b/components/table/hooks/useSelection.tsx @@ -28,6 +28,7 @@ import { // TODO: warning if use ajax!!! export const SELECTION_ALL = 'SELECT_ALL' as const; export const SELECTION_INVERT = 'SELECT_INVERT' as const; +export const SELECTION_NONE = 'SELECT_NONE' as const; function getFixedType(column: ColumnsType[number]): FixedType | undefined { return column && column.fixed; @@ -49,7 +50,8 @@ interface UseSelectionConfig { export type INTERNAL_SELECTION_ITEM = | SelectionItem | typeof SELECTION_ALL - | typeof SELECTION_INVERT; + | typeof SELECTION_INVERT + | typeof SELECTION_NONE; function flattenData( data: RecordType[] | undefined, @@ -82,6 +84,7 @@ export default function useSelection( onSelect, onSelectAll, onSelectInvert, + onSelectNone, onSelectMultiple, columnWidth: selectionColWidth, type: selectionType, @@ -255,7 +258,7 @@ export default function useSelection( } const selectionList: INTERNAL_SELECTION_ITEM[] = - selections === true ? [SELECTION_ALL, SELECTION_INVERT] : selections; + selections === true ? [SELECTION_ALL, SELECTION_INVERT, SELECTION_NONE] : selections; return selectionList.map((selection: INTERNAL_SELECTION_ITEM) => { if (selection === SELECTION_ALL) { @@ -296,6 +299,18 @@ export default function useSelection( }, }; } + if (selection === SELECTION_NONE) { + return { + key: 'none', + text: tableLocale.selectNone, + onSelect() { + setSelectedKeys([]); + if (onSelectNone) { + onSelectNone(); + } + }, + }; + } return selection as SelectionItem; }); }, [selections, derivedSelectedKeySet, pageData, getRowKey, onSelectInvert, setSelectedKeys]); diff --git a/components/table/index.en-US.md b/components/table/index.en-US.md index 72bcdba4f9..a5daf86e62 100644 --- a/components/table/index.en-US.md +++ b/components/table/index.en-US.md @@ -203,6 +203,7 @@ Properties for row selection. | onSelect | Callback executed when select/deselect one row | function(record, selected, selectedRows, nativeEvent) | - | | | onSelectAll | Callback executed when select/deselect all rows | function(selected, selectedRows, changeRows) | - | | | onSelectInvert | Callback executed when row selection is inverted | function(selectedRowKeys) | - | | +| onSelectNone | Callback executed when row selection is cleared | function() | - | | ### scroll diff --git a/components/table/index.zh-CN.md b/components/table/index.zh-CN.md index 6b0cbe017b..390360b1f1 100644 --- a/components/table/index.zh-CN.md +++ b/components/table/index.zh-CN.md @@ -210,6 +210,7 @@ const columns = [ | onSelect | 用户手动选择/取消选择某行的回调 | function(record, selected, selectedRows, nativeEvent) | - | | | onSelectAll | 用户手动选择/取消选择所有行的回调 | function(selected, selectedRows, changeRows) | - | | | onSelectInvert | 用户手动选择反选的回调 | function(selectedRowKeys) | - | | +| onSelectNone | 用户清空选择的回调 | function() | - | | ### scroll diff --git a/components/table/interface.tsx b/components/table/interface.tsx index b3f7cb2de0..75e4804b67 100644 --- a/components/table/interface.tsx +++ b/components/table/interface.tsx @@ -29,6 +29,7 @@ export interface TableLocale { filterEmptyText?: React.ReactNode; emptyText?: React.ReactNode | (() => React.ReactNode); selectAll?: React.ReactNode; + selectNone?: React.ReactNode; selectInvert?: React.ReactNode; selectionAll?: React.ReactNode; sortTitle?: string; @@ -143,6 +144,7 @@ export interface TableRowSelection { onSelectAll?: (selected: boolean, selectedRows: T[], changeRows: T[]) => void; /** @deprecated This function is meaningless and should use `onChange` instead */ onSelectInvert?: (selectedRowKeys: Key[]) => void; + onSelectNone?: () => void; selections?: INTERNAL_SELECTION_ITEM[] | boolean; hideSelectAll?: boolean; fixed?: boolean;