diff --git a/components/locale/default.tsx b/components/locale/default.tsx index a84887e95d..e1237de794 100644 --- a/components/locale/default.tsx +++ b/components/locale/default.tsx @@ -22,6 +22,9 @@ export default { sortTitle: 'Sort', expand: 'Expand row', collapse: 'Collapse row', + triggerDesc: 'Click sort by descend', + triggerAsc: 'Click sort by ascend', + cancelSort: 'Click to cancel sort', }, Modal: { okText: 'OK', diff --git a/components/locale/zh_CN.tsx b/components/locale/zh_CN.tsx index 27a4a8b3c6..828ad8fa2d 100644 --- a/components/locale/zh_CN.tsx +++ b/components/locale/zh_CN.tsx @@ -23,6 +23,9 @@ export default { sortTitle: '排序', expand: '展开行', collapse: '关闭行', + triggerDesc: '点击降序', + triggerAsc: '点击升序', + cancelSort: '取消排序', }, Modal: { okText: '确定', diff --git a/components/table/Table.tsx b/components/table/Table.tsx index d531fa58c8..f853144bd6 100644 --- a/components/table/Table.tsx +++ b/components/table/Table.tsx @@ -84,6 +84,7 @@ export interface TableProps scrollToFirstRowOnChange?: boolean; }; sortDirections?: SortOrder[]; + showSorterTooltip?: boolean; } function Table(props: TableProps) { @@ -110,6 +111,7 @@ function Table(props: TableProps) { scroll, sortDirections, locale, + showSorterTooltip = true, } = props; const size = React.useContext(SizeContext); const { locale: contextLocale = defaultLocale, renderEmpty, direction } = React.useContext( @@ -208,12 +210,13 @@ function Table(props: TableProps) { false, ); }; - const [transformSorterColumns, sortStates, sorterTitleProps, getSorters] = useSorter({ prefixCls, columns: columns || [], onSorterChange, sortDirections: sortDirections || ['ascend', 'descend'], + tableLocale, + showSorterTooltip, }); const sortedData = React.useMemo(() => getSortData(rawData, sortStates, childrenColumnName), [ rawData, diff --git a/components/table/__tests__/Table.sorter.test.js b/components/table/__tests__/Table.sorter.test.js index d7cdc93f44..12ed7d2e7b 100644 --- a/components/table/__tests__/Table.sorter.test.js +++ b/components/table/__tests__/Table.sorter.test.js @@ -150,6 +150,45 @@ describe('Table.sorter', () => { expect(sorter3.columnKey).toBe('name'); }); + it('hover header show sorter tooltip', () => { + // tooltip has delay + jest.useFakeTimers(); + const wrapper = mount(createTable({})); + // default show sorter tooltip + wrapper.find('.ant-table-column-sorters').simulate('mouseenter'); + jest.runAllTimers(); + wrapper.update(); + expect(wrapper.find('.ant-tooltip-open').length).toBeTruthy(); + wrapper.find('.ant-table-column-sorters').simulate('mouseout'); + // set table props showSorterTooltip is false + wrapper.setProps({ showSorterTooltip: false }); + wrapper.find('.ant-table-column-sorters').simulate('mouseenter'); + jest.runAllTimers(); + wrapper.update(); + expect(wrapper.find('.ant-tooltip-open').length).toBeFalsy(); + wrapper.find('.ant-table-column-sorters').simulate('mouseout'); + // set table props showSorterTooltip is false, column showSorterTooltip is true + wrapper.setProps({ + showSorterTooltip: false, + columns: [{ ...column, showSorterTooltip: true }], + }); + wrapper.find('.ant-table-column-sorters').simulate('mouseenter'); + jest.runAllTimers(); + wrapper.update(); + expect(wrapper.find('.ant-tooltip-open').length).toBeTruthy(); + wrapper.find('.ant-table-column-sorters').simulate('mouseout'); + // set table props showSorterTooltip is true, column showSorterTooltip is false + wrapper.setProps({ + showSorterTooltip: true, + columns: [{ ...column, showSorterTooltip: false }], + }); + wrapper.find('.ant-table-column-sorters').simulate('mouseenter'); + jest.runAllTimers(); + wrapper.update(); + expect(wrapper.find('.ant-tooltip-open').length).toBeFalsy(); + wrapper.find('.ant-table-column-sorters').simulate('mouseout'); + }); + it('works with grouping columns in controlled mode', () => { const columns = [ { diff --git a/components/table/hooks/useSorter.tsx b/components/table/hooks/useSorter.tsx index cde513ce57..701ec2d3bd 100644 --- a/components/table/hooks/useSorter.tsx +++ b/components/table/hooks/useSorter.tsx @@ -10,9 +10,14 @@ import { CompareFn, ColumnTitleProps, SorterResult, + TableLocale, } from '../interface'; +import Tooltip from '../../tooltip'; import { getColumnKey, getColumnPos, renderColumnTitle } from '../util'; +const ASCEND = 'ascend'; +const DESCEND = 'descend'; + function getMultiplePriority(column: ColumnType): number | false { if (typeof column.sorter === 'object' && typeof column.sorter.multiple === 'number') { return column.sorter.multiple; @@ -89,6 +94,8 @@ function injectSorter( sorterSates: SortState[], triggerSorter: (sorterSates: SortState) => void, defaultSortDirections: SortOrder[], + tableLocale?: TableLocale, + tableShowSorterTooltip?: boolean, pos?: string, ): ColumnsType { return (columns || []).map((column, index) => { @@ -97,53 +104,69 @@ function injectSorter( if (newColumn.sorter) { const sortDirections: SortOrder[] = newColumn.sortDirections || defaultSortDirections; + const showSorterTooltip = + newColumn.showSorterTooltip === undefined + ? tableShowSorterTooltip + : newColumn.showSorterTooltip; const columnKey = getColumnKey(newColumn, columnPos); const sorterState = sorterSates.find(({ key }) => key === columnKey); const sorterOrder = sorterState ? sorterState.sortOrder : null; - - const upNode: React.ReactNode = sortDirections.includes('ascend') && ( + const nextSortOrder = nextSortDirection(sortDirections, sorterOrder); + const upNode: React.ReactNode = sortDirections.includes(ASCEND) && ( ); - const downNode: React.ReactNode = sortDirections.includes('descend') && ( + const downNode: React.ReactNode = sortDirections.includes(DESCEND) && ( ); - + const { cancelSort, triggerAsc, triggerDesc } = tableLocale || {}; + let sortTip: string | undefined = cancelSort; + if (nextSortOrder === DESCEND) { + sortTip = triggerDesc; + } else if (nextSortOrder === ASCEND) { + sortTip = triggerAsc; + } newColumn = { ...newColumn, className: classNames(newColumn.className, { [`${prefixCls}-column-sort`]: sorterOrder }), - title: (renderProps: ColumnTitleProps) => ( -
- {renderColumnTitle(column.title, renderProps)} - - - {upNode} - {downNode} + title: (renderProps: ColumnTitleProps) => { + const renderSortTitle = ( +
+ {renderColumnTitle(column.title, renderProps)} + + + {upNode} + {downNode} + - -
- ), +
+ ); + return showSorterTooltip ? ( + {renderSortTitle} + ) : ( + renderSortTitle + ); + }, onHeaderCell: col => { const cell: React.HTMLAttributes = (column.onHeaderCell && column.onHeaderCell(col)) || {}; const originOnClick = cell.onClick; - cell.onClick = (event: React.MouseEvent) => { triggerSorter({ column, key: columnKey, - sortOrder: nextSortDirection(sortDirections, sorterOrder), + sortOrder: nextSortOrder, multiplePriority: getMultiplePriority(column), }); @@ -168,6 +191,8 @@ function injectSorter( sorterSates, triggerSorter, defaultSortDirections, + tableLocale, + tableShowSorterTooltip, columnPos, ), }; @@ -238,7 +263,7 @@ export function getSortData( const compareResult = compareFn(record1, record2, sortOrder); if (compareResult !== 0) { - return sortOrder === 'ascend' ? compareResult : -compareResult; + return sortOrder === ASCEND ? compareResult : -compareResult; } } } @@ -265,6 +290,8 @@ interface SorterConfig { sortStates: SortState[], ) => void; sortDirections: SortOrder[]; + tableLocale?: TableLocale; + showSorterTooltip?: boolean; } export default function useFilterSorter({ @@ -272,6 +299,8 @@ export default function useFilterSorter({ columns, onSorterChange, sortDirections, + tableLocale, + showSorterTooltip, }: SorterConfig): [ TransformColumns, SortState[], @@ -363,7 +392,15 @@ export default function useFilterSorter({ } const transformColumns = (innerColumns: ColumnsType) => - injectSorter(prefixCls, innerColumns, mergedSorterStates, triggerSorter, sortDirections); + injectSorter( + prefixCls, + innerColumns, + mergedSorterStates, + triggerSorter, + sortDirections, + tableLocale, + showSorterTooltip, + ); const getSorters = () => { return generateSorterInfo(mergedSorterStates); diff --git a/components/table/index.en-US.md b/components/table/index.en-US.md index 5bc0c6c07a..d7a045b789 100644 --- a/components/table/index.en-US.md +++ b/components/table/index.en-US.md @@ -82,6 +82,7 @@ const columns = [ | onRow | Set props on per row | Function(record, index) | - | | getPopupContainer | the render container of dropdowns in table | (triggerNode) => HTMLElement | `() => TableHtmlElement` | | sortDirections | supported sort way, could be `'ascend'`, `'descend'` | Array | `['ascend', 'descend']` | +| showSorterTooltip | header show next sorter direction tooltip | boolean | `true` | #### onRow usage @@ -138,6 +139,7 @@ One of the Table `columns` prop for describing the table's columns, Column has t | onFilter | Callback executed when the confirm filter button is clicked | Function | - | | onFilterDropdownVisibleChange | Callback executed when `filterDropdownVisible` is changed | function(visible) {} | - | | onHeaderCell | Set props on per header cell | Function(column) | - | +| showSorterTooltip | header show next sorter direction tooltip, override `showSorterTooltip` in table | boolean | `true` | ### ColumnGroup diff --git a/components/table/index.zh-CN.md b/components/table/index.zh-CN.md index dfee632b57..ebc41ac55b 100644 --- a/components/table/index.zh-CN.md +++ b/components/table/index.zh-CN.md @@ -87,6 +87,7 @@ const columns = [ | onRow | 设置行属性 | Function(record, index) | - | | getPopupContainer | 设置表格内各类浮层的渲染节点,如筛选菜单 | (triggerNode) => HTMLElement | `() => TableHtmlElement` | | sortDirections | 支持的排序方式,取值为 `'ascend'` `'descend'` | Array | `['ascend', 'descend']` | +| showSorterTooltip | 表头是否显示下一次排序的 tooltip 提示 | boolean | `true` | #### onRow 用法 @@ -143,6 +144,7 @@ const columns = [ | onFilter | 本地模式下,确定筛选的运行函数 | Function | - | | onFilterDropdownVisibleChange | 自定义筛选菜单可见变化时调用 | function(visible) {} | - | | onHeaderCell | 设置头部单元格属性 | Function(column) | - | +| showSorterTooltip | 表头显示下一次排序的 tooltip 提示, 覆盖 table 中`showSorterTooltip` | boolean | `true` | ### ColumnGroup diff --git a/components/table/interface.tsx b/components/table/interface.tsx index c2bb7bdfb5..a9a0928c1a 100644 --- a/components/table/interface.tsx +++ b/components/table/interface.tsx @@ -23,6 +23,9 @@ export interface TableLocale { sortTitle?: string; expand?: string; collapse?: string; + triggerDesc?: string; + triggerAsc?: string; + cancelSort?: string; } export type SortOrder = 'descend' | 'ascend' | null; @@ -74,6 +77,7 @@ export interface ColumnType extends RcColumnType { sortOrder?: SortOrder; defaultSortOrder?: SortOrder; sortDirections?: SortOrder[]; + showSorterTooltip?: boolean; // Filter filters?: ColumnFilterItem[]; diff --git a/components/table/style/index.less b/components/table/style/index.less index 2c15125609..f4de858e0b 100644 --- a/components/table/style/index.less +++ b/components/table/style/index.less @@ -188,6 +188,7 @@ // ============================ Sorter ============================ thead th.@{table-prefix-cls}-column-has-sorters { + padding: 0; cursor: pointer; transition: all 0.3s; @@ -210,6 +211,8 @@ &-column-sorters { display: inline-flex; align-items: center; + width: 100%; + padding: @table-padding-vertical @table-padding-horizontal; } &-column-sorter { diff --git a/components/table/style/index.tsx b/components/table/style/index.tsx index c1ff86a1ad..c85b1dfde8 100644 --- a/components/table/style/index.tsx +++ b/components/table/style/index.tsx @@ -9,3 +9,4 @@ import '../../checkbox/style'; import '../../dropdown/style'; import '../../spin/style'; import '../../pagination/style'; +import '../../tooltip/style';