mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-12-11 10:05:07 +08:00
feat: more obviously tips for next sort (#21631)
This commit is contained in:
parent
c8c824c138
commit
e262d14c2b
@ -22,6 +22,9 @@ export default {
|
|||||||
sortTitle: 'Sort',
|
sortTitle: 'Sort',
|
||||||
expand: 'Expand row',
|
expand: 'Expand row',
|
||||||
collapse: 'Collapse row',
|
collapse: 'Collapse row',
|
||||||
|
triggerDesc: 'Click sort by descend',
|
||||||
|
triggerAsc: 'Click sort by ascend',
|
||||||
|
cancelSort: 'Click to cancel sort',
|
||||||
},
|
},
|
||||||
Modal: {
|
Modal: {
|
||||||
okText: 'OK',
|
okText: 'OK',
|
||||||
|
@ -23,6 +23,9 @@ export default {
|
|||||||
sortTitle: '排序',
|
sortTitle: '排序',
|
||||||
expand: '展开行',
|
expand: '展开行',
|
||||||
collapse: '关闭行',
|
collapse: '关闭行',
|
||||||
|
triggerDesc: '点击降序',
|
||||||
|
triggerAsc: '点击升序',
|
||||||
|
cancelSort: '取消排序',
|
||||||
},
|
},
|
||||||
Modal: {
|
Modal: {
|
||||||
okText: '确定',
|
okText: '确定',
|
||||||
|
@ -84,6 +84,7 @@ export interface TableProps<RecordType>
|
|||||||
scrollToFirstRowOnChange?: boolean;
|
scrollToFirstRowOnChange?: boolean;
|
||||||
};
|
};
|
||||||
sortDirections?: SortOrder[];
|
sortDirections?: SortOrder[];
|
||||||
|
showSorterTooltip?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Table<RecordType extends object = any>(props: TableProps<RecordType>) {
|
function Table<RecordType extends object = any>(props: TableProps<RecordType>) {
|
||||||
@ -110,6 +111,7 @@ function Table<RecordType extends object = any>(props: TableProps<RecordType>) {
|
|||||||
scroll,
|
scroll,
|
||||||
sortDirections,
|
sortDirections,
|
||||||
locale,
|
locale,
|
||||||
|
showSorterTooltip = true,
|
||||||
} = props;
|
} = props;
|
||||||
const size = React.useContext(SizeContext);
|
const size = React.useContext(SizeContext);
|
||||||
const { locale: contextLocale = defaultLocale, renderEmpty, direction } = React.useContext(
|
const { locale: contextLocale = defaultLocale, renderEmpty, direction } = React.useContext(
|
||||||
@ -208,12 +210,13 @@ function Table<RecordType extends object = any>(props: TableProps<RecordType>) {
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const [transformSorterColumns, sortStates, sorterTitleProps, getSorters] = useSorter<RecordType>({
|
const [transformSorterColumns, sortStates, sorterTitleProps, getSorters] = useSorter<RecordType>({
|
||||||
prefixCls,
|
prefixCls,
|
||||||
columns: columns || [],
|
columns: columns || [],
|
||||||
onSorterChange,
|
onSorterChange,
|
||||||
sortDirections: sortDirections || ['ascend', 'descend'],
|
sortDirections: sortDirections || ['ascend', 'descend'],
|
||||||
|
tableLocale,
|
||||||
|
showSorterTooltip,
|
||||||
});
|
});
|
||||||
const sortedData = React.useMemo(() => getSortData(rawData, sortStates, childrenColumnName), [
|
const sortedData = React.useMemo(() => getSortData(rawData, sortStates, childrenColumnName), [
|
||||||
rawData,
|
rawData,
|
||||||
|
@ -150,6 +150,45 @@ describe('Table.sorter', () => {
|
|||||||
expect(sorter3.columnKey).toBe('name');
|
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', () => {
|
it('works with grouping columns in controlled mode', () => {
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
|
@ -10,9 +10,14 @@ import {
|
|||||||
CompareFn,
|
CompareFn,
|
||||||
ColumnTitleProps,
|
ColumnTitleProps,
|
||||||
SorterResult,
|
SorterResult,
|
||||||
|
TableLocale,
|
||||||
} from '../interface';
|
} from '../interface';
|
||||||
|
import Tooltip from '../../tooltip';
|
||||||
import { getColumnKey, getColumnPos, renderColumnTitle } from '../util';
|
import { getColumnKey, getColumnPos, renderColumnTitle } from '../util';
|
||||||
|
|
||||||
|
const ASCEND = 'ascend';
|
||||||
|
const DESCEND = 'descend';
|
||||||
|
|
||||||
function getMultiplePriority<RecordType>(column: ColumnType<RecordType>): number | false {
|
function getMultiplePriority<RecordType>(column: ColumnType<RecordType>): number | false {
|
||||||
if (typeof column.sorter === 'object' && typeof column.sorter.multiple === 'number') {
|
if (typeof column.sorter === 'object' && typeof column.sorter.multiple === 'number') {
|
||||||
return column.sorter.multiple;
|
return column.sorter.multiple;
|
||||||
@ -89,6 +94,8 @@ function injectSorter<RecordType>(
|
|||||||
sorterSates: SortState<RecordType>[],
|
sorterSates: SortState<RecordType>[],
|
||||||
triggerSorter: (sorterSates: SortState<RecordType>) => void,
|
triggerSorter: (sorterSates: SortState<RecordType>) => void,
|
||||||
defaultSortDirections: SortOrder[],
|
defaultSortDirections: SortOrder[],
|
||||||
|
tableLocale?: TableLocale,
|
||||||
|
tableShowSorterTooltip?: boolean,
|
||||||
pos?: string,
|
pos?: string,
|
||||||
): ColumnsType<RecordType> {
|
): ColumnsType<RecordType> {
|
||||||
return (columns || []).map((column, index) => {
|
return (columns || []).map((column, index) => {
|
||||||
@ -97,53 +104,69 @@ function injectSorter<RecordType>(
|
|||||||
|
|
||||||
if (newColumn.sorter) {
|
if (newColumn.sorter) {
|
||||||
const sortDirections: SortOrder[] = newColumn.sortDirections || defaultSortDirections;
|
const sortDirections: SortOrder[] = newColumn.sortDirections || defaultSortDirections;
|
||||||
|
const showSorterTooltip =
|
||||||
|
newColumn.showSorterTooltip === undefined
|
||||||
|
? tableShowSorterTooltip
|
||||||
|
: newColumn.showSorterTooltip;
|
||||||
const columnKey = getColumnKey(newColumn, columnPos);
|
const columnKey = getColumnKey(newColumn, columnPos);
|
||||||
const sorterState = sorterSates.find(({ key }) => key === columnKey);
|
const sorterState = sorterSates.find(({ key }) => key === columnKey);
|
||||||
const sorterOrder = sorterState ? sorterState.sortOrder : null;
|
const sorterOrder = sorterState ? sorterState.sortOrder : null;
|
||||||
|
const nextSortOrder = nextSortDirection(sortDirections, sorterOrder);
|
||||||
const upNode: React.ReactNode = sortDirections.includes('ascend') && (
|
const upNode: React.ReactNode = sortDirections.includes(ASCEND) && (
|
||||||
<CaretUpOutlined
|
<CaretUpOutlined
|
||||||
className={classNames(`${prefixCls}-column-sorter-up`, {
|
className={classNames(`${prefixCls}-column-sorter-up`, {
|
||||||
active: sorterOrder === 'ascend',
|
active: sorterOrder === ASCEND,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
const downNode: React.ReactNode = sortDirections.includes('descend') && (
|
const downNode: React.ReactNode = sortDirections.includes(DESCEND) && (
|
||||||
<CaretDownOutlined
|
<CaretDownOutlined
|
||||||
className={classNames(`${prefixCls}-column-sorter-down`, {
|
className={classNames(`${prefixCls}-column-sorter-down`, {
|
||||||
active: sorterOrder === 'descend',
|
active: sorterOrder === DESCEND,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
const { cancelSort, triggerAsc, triggerDesc } = tableLocale || {};
|
||||||
|
let sortTip: string | undefined = cancelSort;
|
||||||
|
if (nextSortOrder === DESCEND) {
|
||||||
|
sortTip = triggerDesc;
|
||||||
|
} else if (nextSortOrder === ASCEND) {
|
||||||
|
sortTip = triggerAsc;
|
||||||
|
}
|
||||||
newColumn = {
|
newColumn = {
|
||||||
...newColumn,
|
...newColumn,
|
||||||
className: classNames(newColumn.className, { [`${prefixCls}-column-sort`]: sorterOrder }),
|
className: classNames(newColumn.className, { [`${prefixCls}-column-sort`]: sorterOrder }),
|
||||||
title: (renderProps: ColumnTitleProps<RecordType>) => (
|
title: (renderProps: ColumnTitleProps<RecordType>) => {
|
||||||
<div className={`${prefixCls}-column-sorters`}>
|
const renderSortTitle = (
|
||||||
<span>{renderColumnTitle(column.title, renderProps)}</span>
|
<div className={`${prefixCls}-column-sorters`}>
|
||||||
<span
|
<span>{renderColumnTitle(column.title, renderProps)}</span>
|
||||||
className={classNames(`${prefixCls}-column-sorter`, {
|
<span
|
||||||
[`${prefixCls}-column-sorter-full`]: upNode && downNode,
|
className={classNames(`${prefixCls}-column-sorter`, {
|
||||||
})}
|
[`${prefixCls}-column-sorter-full`]: upNode && downNode,
|
||||||
>
|
})}
|
||||||
<span className={`${prefixCls}-column-sorter-inner`}>
|
>
|
||||||
{upNode}
|
<span className={`${prefixCls}-column-sorter-inner`}>
|
||||||
{downNode}
|
{upNode}
|
||||||
|
{downNode}
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</div>
|
||||||
</div>
|
);
|
||||||
),
|
return showSorterTooltip ? (
|
||||||
|
<Tooltip title={sortTip}>{renderSortTitle}</Tooltip>
|
||||||
|
) : (
|
||||||
|
renderSortTitle
|
||||||
|
);
|
||||||
|
},
|
||||||
onHeaderCell: col => {
|
onHeaderCell: col => {
|
||||||
const cell: React.HTMLAttributes<HTMLElement> =
|
const cell: React.HTMLAttributes<HTMLElement> =
|
||||||
(column.onHeaderCell && column.onHeaderCell(col)) || {};
|
(column.onHeaderCell && column.onHeaderCell(col)) || {};
|
||||||
const originOnClick = cell.onClick;
|
const originOnClick = cell.onClick;
|
||||||
|
|
||||||
cell.onClick = (event: React.MouseEvent<HTMLElement>) => {
|
cell.onClick = (event: React.MouseEvent<HTMLElement>) => {
|
||||||
triggerSorter({
|
triggerSorter({
|
||||||
column,
|
column,
|
||||||
key: columnKey,
|
key: columnKey,
|
||||||
sortOrder: nextSortDirection(sortDirections, sorterOrder),
|
sortOrder: nextSortOrder,
|
||||||
multiplePriority: getMultiplePriority(column),
|
multiplePriority: getMultiplePriority(column),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -168,6 +191,8 @@ function injectSorter<RecordType>(
|
|||||||
sorterSates,
|
sorterSates,
|
||||||
triggerSorter,
|
triggerSorter,
|
||||||
defaultSortDirections,
|
defaultSortDirections,
|
||||||
|
tableLocale,
|
||||||
|
tableShowSorterTooltip,
|
||||||
columnPos,
|
columnPos,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
@ -238,7 +263,7 @@ export function getSortData<RecordType>(
|
|||||||
const compareResult = compareFn(record1, record2, sortOrder);
|
const compareResult = compareFn(record1, record2, sortOrder);
|
||||||
|
|
||||||
if (compareResult !== 0) {
|
if (compareResult !== 0) {
|
||||||
return sortOrder === 'ascend' ? compareResult : -compareResult;
|
return sortOrder === ASCEND ? compareResult : -compareResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -265,6 +290,8 @@ interface SorterConfig<RecordType> {
|
|||||||
sortStates: SortState<RecordType>[],
|
sortStates: SortState<RecordType>[],
|
||||||
) => void;
|
) => void;
|
||||||
sortDirections: SortOrder[];
|
sortDirections: SortOrder[];
|
||||||
|
tableLocale?: TableLocale;
|
||||||
|
showSorterTooltip?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function useFilterSorter<RecordType>({
|
export default function useFilterSorter<RecordType>({
|
||||||
@ -272,6 +299,8 @@ export default function useFilterSorter<RecordType>({
|
|||||||
columns,
|
columns,
|
||||||
onSorterChange,
|
onSorterChange,
|
||||||
sortDirections,
|
sortDirections,
|
||||||
|
tableLocale,
|
||||||
|
showSorterTooltip,
|
||||||
}: SorterConfig<RecordType>): [
|
}: SorterConfig<RecordType>): [
|
||||||
TransformColumns<RecordType>,
|
TransformColumns<RecordType>,
|
||||||
SortState<RecordType>[],
|
SortState<RecordType>[],
|
||||||
@ -363,7 +392,15 @@ export default function useFilterSorter<RecordType>({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const transformColumns = (innerColumns: ColumnsType<RecordType>) =>
|
const transformColumns = (innerColumns: ColumnsType<RecordType>) =>
|
||||||
injectSorter(prefixCls, innerColumns, mergedSorterStates, triggerSorter, sortDirections);
|
injectSorter(
|
||||||
|
prefixCls,
|
||||||
|
innerColumns,
|
||||||
|
mergedSorterStates,
|
||||||
|
triggerSorter,
|
||||||
|
sortDirections,
|
||||||
|
tableLocale,
|
||||||
|
showSorterTooltip,
|
||||||
|
);
|
||||||
|
|
||||||
const getSorters = () => {
|
const getSorters = () => {
|
||||||
return generateSorterInfo(mergedSorterStates);
|
return generateSorterInfo(mergedSorterStates);
|
||||||
|
@ -82,6 +82,7 @@ const columns = [
|
|||||||
| onRow | Set props on per row | Function(record, index) | - |
|
| onRow | Set props on per row | Function(record, index) | - |
|
||||||
| getPopupContainer | the render container of dropdowns in table | (triggerNode) => HTMLElement | `() => TableHtmlElement` |
|
| getPopupContainer | the render container of dropdowns in table | (triggerNode) => HTMLElement | `() => TableHtmlElement` |
|
||||||
| sortDirections | supported sort way, could be `'ascend'`, `'descend'` | Array | `['ascend', 'descend']` |
|
| sortDirections | supported sort way, could be `'ascend'`, `'descend'` | Array | `['ascend', 'descend']` |
|
||||||
|
| showSorterTooltip | header show next sorter direction tooltip | boolean | `true` |
|
||||||
|
|
||||||
#### onRow usage
|
#### 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 | - |
|
| onFilter | Callback executed when the confirm filter button is clicked | Function | - |
|
||||||
| onFilterDropdownVisibleChange | Callback executed when `filterDropdownVisible` is changed | function(visible) {} | - |
|
| onFilterDropdownVisibleChange | Callback executed when `filterDropdownVisible` is changed | function(visible) {} | - |
|
||||||
| onHeaderCell | Set props on per header cell | Function(column) | - |
|
| onHeaderCell | Set props on per header cell | Function(column) | - |
|
||||||
|
| showSorterTooltip | header show next sorter direction tooltip, override `showSorterTooltip` in table | boolean | `true` |
|
||||||
|
|
||||||
### ColumnGroup
|
### ColumnGroup
|
||||||
|
|
||||||
|
@ -87,6 +87,7 @@ const columns = [
|
|||||||
| onRow | 设置行属性 | Function(record, index) | - |
|
| onRow | 设置行属性 | Function(record, index) | - |
|
||||||
| getPopupContainer | 设置表格内各类浮层的渲染节点,如筛选菜单 | (triggerNode) => HTMLElement | `() => TableHtmlElement` |
|
| getPopupContainer | 设置表格内各类浮层的渲染节点,如筛选菜单 | (triggerNode) => HTMLElement | `() => TableHtmlElement` |
|
||||||
| sortDirections | 支持的排序方式,取值为 `'ascend'` `'descend'` | Array | `['ascend', 'descend']` |
|
| sortDirections | 支持的排序方式,取值为 `'ascend'` `'descend'` | Array | `['ascend', 'descend']` |
|
||||||
|
| showSorterTooltip | 表头是否显示下一次排序的 tooltip 提示 | boolean | `true` |
|
||||||
|
|
||||||
#### onRow 用法
|
#### onRow 用法
|
||||||
|
|
||||||
@ -143,6 +144,7 @@ const columns = [
|
|||||||
| onFilter | 本地模式下,确定筛选的运行函数 | Function | - |
|
| onFilter | 本地模式下,确定筛选的运行函数 | Function | - |
|
||||||
| onFilterDropdownVisibleChange | 自定义筛选菜单可见变化时调用 | function(visible) {} | - |
|
| onFilterDropdownVisibleChange | 自定义筛选菜单可见变化时调用 | function(visible) {} | - |
|
||||||
| onHeaderCell | 设置头部单元格属性 | Function(column) | - |
|
| onHeaderCell | 设置头部单元格属性 | Function(column) | - |
|
||||||
|
| showSorterTooltip | 表头显示下一次排序的 tooltip 提示, 覆盖 table 中`showSorterTooltip` | boolean | `true` |
|
||||||
|
|
||||||
### ColumnGroup
|
### ColumnGroup
|
||||||
|
|
||||||
|
@ -23,6 +23,9 @@ export interface TableLocale {
|
|||||||
sortTitle?: string;
|
sortTitle?: string;
|
||||||
expand?: string;
|
expand?: string;
|
||||||
collapse?: string;
|
collapse?: string;
|
||||||
|
triggerDesc?: string;
|
||||||
|
triggerAsc?: string;
|
||||||
|
cancelSort?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SortOrder = 'descend' | 'ascend' | null;
|
export type SortOrder = 'descend' | 'ascend' | null;
|
||||||
@ -74,6 +77,7 @@ export interface ColumnType<RecordType> extends RcColumnType<RecordType> {
|
|||||||
sortOrder?: SortOrder;
|
sortOrder?: SortOrder;
|
||||||
defaultSortOrder?: SortOrder;
|
defaultSortOrder?: SortOrder;
|
||||||
sortDirections?: SortOrder[];
|
sortDirections?: SortOrder[];
|
||||||
|
showSorterTooltip?: boolean;
|
||||||
|
|
||||||
// Filter
|
// Filter
|
||||||
filters?: ColumnFilterItem[];
|
filters?: ColumnFilterItem[];
|
||||||
|
@ -188,6 +188,7 @@
|
|||||||
|
|
||||||
// ============================ Sorter ============================
|
// ============================ Sorter ============================
|
||||||
thead th.@{table-prefix-cls}-column-has-sorters {
|
thead th.@{table-prefix-cls}-column-has-sorters {
|
||||||
|
padding: 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
|
||||||
@ -210,6 +211,8 @@
|
|||||||
&-column-sorters {
|
&-column-sorters {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
padding: @table-padding-vertical @table-padding-horizontal;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-column-sorter {
|
&-column-sorter {
|
||||||
|
@ -9,3 +9,4 @@ import '../../checkbox/style';
|
|||||||
import '../../dropdown/style';
|
import '../../dropdown/style';
|
||||||
import '../../spin/style';
|
import '../../spin/style';
|
||||||
import '../../pagination/style';
|
import '../../pagination/style';
|
||||||
|
import '../../tooltip/style';
|
||||||
|
Loading…
Reference in New Issue
Block a user