mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-12-02 12:09:14 +08:00
fix: Table columns sorter a11y experience (#35269)
* Make table sortable columns focusable and keyboard accessible. * Fix typo. * Change focus style for sortable table column header from broken outline to color text. * Update snapshots. * Change order to fix lint error. * Add unit test to test sorting with keypress. * Update components/table/hooks/useSorter.tsx * chore: improve code style * style: use focus-visible * fix: test case * test: update snapshot Co-authored-by: Katsiaryna Pustakhod <Katsiaryna_Pustakhod@epam.com>
This commit is contained in:
parent
45a19024ab
commit
5a6b3ccd98
@ -22867,6 +22867,7 @@ exports[`ConfigProvider components Table configProvider 1`] = `
|
||||
<tr>
|
||||
<th
|
||||
class="config-table-cell config-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="config-table-filter-column"
|
||||
@ -23147,6 +23148,7 @@ exports[`ConfigProvider components Table configProvider componentSize large 1`]
|
||||
<tr>
|
||||
<th
|
||||
class="config-table-cell config-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="config-table-filter-column"
|
||||
@ -23427,6 +23429,7 @@ exports[`ConfigProvider components Table configProvider componentSize middle 1`]
|
||||
<tr>
|
||||
<th
|
||||
class="config-table-cell config-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="config-table-filter-column"
|
||||
@ -23707,6 +23710,7 @@ exports[`ConfigProvider components Table configProvider virtual and dropdownMatc
|
||||
<tr>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-filter-column"
|
||||
@ -23987,6 +23991,7 @@ exports[`ConfigProvider components Table normal 1`] = `
|
||||
<tr>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-filter-column"
|
||||
@ -24267,6 +24272,7 @@ exports[`ConfigProvider components Table prefixCls 1`] = `
|
||||
<tr>
|
||||
<th
|
||||
class="prefix-Table-cell prefix-Table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="prefix-Table-filter-column"
|
||||
|
@ -119,6 +119,18 @@ describe('Table.sorter', () => {
|
||||
expect(getNameColumn().prop('aria-sort')).toEqual('descending');
|
||||
});
|
||||
|
||||
it('sort records with keydown', () => {
|
||||
const wrapper = mount(createTable());
|
||||
|
||||
// ascend
|
||||
wrapper.find('.ant-table-column-sorters').simulate('keydown', { keyCode: 13 });
|
||||
expect(renderedNames(wrapper)).toEqual(['Jack', 'Jerry', 'Lucy', 'Tom']);
|
||||
|
||||
// descend
|
||||
wrapper.find('.ant-table-column-sorters').simulate('keydown', { keyCode: 13 });
|
||||
expect(renderedNames(wrapper)).toEqual(['Tom', 'Lucy', 'Jack', 'Jerry']);
|
||||
});
|
||||
|
||||
describe('can be controlled by sortOrder', () => {
|
||||
it('single', () => {
|
||||
const wrapper = mount(
|
||||
|
@ -7,6 +7,7 @@ exports[`Table.sorter renders sorter icon correctly 1`] = `
|
||||
<tr>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -98,6 +99,7 @@ exports[`Table.sorter should support defaultOrder in Column 1`] = `
|
||||
<th
|
||||
aria-sort="ascending"
|
||||
class="ant-table-cell ant-table-column-sort ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
|
@ -36,6 +36,7 @@ exports[`renders ./components/table/demo/ajax.md extend context correctly 1`] =
|
||||
<tr>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -1516,6 +1517,7 @@ exports[`renders ./components/table/demo/custom-filter-panel.md extend context c
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-filter-column"
|
||||
@ -3205,6 +3207,7 @@ Array [
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -3514,6 +3517,7 @@ Array [
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -7454,6 +7458,7 @@ exports[`renders ./components/table/demo/filter-in-tree.md extend context correc
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -8273,6 +8278,7 @@ exports[`renders ./components/table/demo/filter-search.md extend context correct
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -12145,6 +12151,7 @@ exports[`renders ./components/table/demo/grouping-columns.md extend context corr
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
rowspan="3"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -13250,6 +13257,7 @@ exports[`renders ./components/table/demo/head.md extend context correctly 1`] =
|
||||
<tr>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-filter-column"
|
||||
@ -13713,6 +13721,7 @@ exports[`renders ./components/table/demo/head.md extend context correctly 1`] =
|
||||
<th
|
||||
aria-sort="descending"
|
||||
class="ant-table-cell ant-table-column-sort ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -14574,6 +14583,7 @@ exports[`renders ./components/table/demo/multiple-sorter.md extend context corre
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -14657,6 +14667,7 @@ exports[`renders ./components/table/demo/multiple-sorter.md extend context corre
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -14740,6 +14751,7 @@ exports[`renders ./components/table/demo/multiple-sorter.md extend context corre
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -17420,6 +17432,7 @@ Array [
|
||||
<tr>
|
||||
<th
|
||||
class="ant-table-cell ant-table-cell-ellipsis ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-filter-column"
|
||||
@ -17724,6 +17737,7 @@ Array [
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-cell-ellipsis ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -17807,6 +17821,7 @@ Array [
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-cell-ellipsis ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-filter-column"
|
||||
@ -18347,6 +18362,7 @@ exports[`renders ./components/table/demo/resizable-column.md extend context corr
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters react-resizable"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
|
@ -36,6 +36,7 @@ exports[`renders ./components/table/demo/ajax.md correctly 1`] = `
|
||||
<tr>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -1134,6 +1135,7 @@ exports[`renders ./components/table/demo/custom-filter-panel.md correctly 1`] =
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-filter-column"
|
||||
@ -2714,6 +2716,7 @@ Array [
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -2811,6 +2814,7 @@ Array [
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -5773,6 +5777,7 @@ exports[`renders ./components/table/demo/filter-in-tree.md correctly 1`] = `
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -6118,6 +6123,7 @@ exports[`renders ./components/table/demo/filter-search.md correctly 1`] = `
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -9316,6 +9322,7 @@ exports[`renders ./components/table/demo/grouping-columns.md correctly 1`] = `
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
rowspan="3"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -10281,6 +10288,7 @@ exports[`renders ./components/table/demo/head.md correctly 1`] = `
|
||||
<tr>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-filter-column"
|
||||
@ -10355,6 +10363,7 @@ exports[`renders ./components/table/demo/head.md correctly 1`] = `
|
||||
<th
|
||||
aria-sort="descending"
|
||||
class="ant-table-cell ant-table-column-sort ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -11004,6 +11013,7 @@ exports[`renders ./components/table/demo/multiple-sorter.md correctly 1`] = `
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -11063,6 +11073,7 @@ exports[`renders ./components/table/demo/multiple-sorter.md correctly 1`] = `
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -11122,6 +11133,7 @@ exports[`renders ./components/table/demo/multiple-sorter.md correctly 1`] = `
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -13662,6 +13674,7 @@ Array [
|
||||
<tr>
|
||||
<th
|
||||
class="ant-table-cell ant-table-cell-ellipsis ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-filter-column"
|
||||
@ -13754,6 +13767,7 @@ Array [
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-cell-ellipsis ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
@ -13813,6 +13827,7 @@ Array [
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-cell-ellipsis ant-table-column-has-sorters"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-filter-column"
|
||||
@ -14141,6 +14156,7 @@ exports[`renders ./components/table/demo/resizable-column.md correctly 1`] = `
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-cell ant-table-column-has-sorters react-resizable"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="ant-table-column-sorters"
|
||||
|
@ -2,6 +2,7 @@ import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import CaretDownOutlined from '@ant-design/icons/CaretDownOutlined';
|
||||
import CaretUpOutlined from '@ant-design/icons/CaretUpOutlined';
|
||||
import KeyCode from 'rc-util/lib/KeyCode';
|
||||
import {
|
||||
TransformColumns,
|
||||
ColumnsType,
|
||||
@ -104,7 +105,7 @@ function collectSortStates<RecordType>(
|
||||
function injectSorter<RecordType>(
|
||||
prefixCls: string,
|
||||
columns: ColumnsType<RecordType>,
|
||||
sorterSates: SortState<RecordType>[],
|
||||
sorterStates: SortState<RecordType>[],
|
||||
triggerSorter: (sorterSates: SortState<RecordType>) => void,
|
||||
defaultSortDirections: SortOrder[],
|
||||
tableLocale?: TableLocale,
|
||||
@ -122,7 +123,7 @@ function injectSorter<RecordType>(
|
||||
? tableShowSorterTooltip
|
||||
: newColumn.showSorterTooltip;
|
||||
const columnKey = getColumnKey(newColumn, columnPos);
|
||||
const sorterState = sorterSates.find(({ key }) => key === columnKey);
|
||||
const sorterState = sorterStates.find(({ key }) => key === columnKey);
|
||||
const sorterOrder = sorterState ? sorterState.sortOrder : null;
|
||||
const nextSortOrder = nextSortDirection(sortDirections, sorterOrder);
|
||||
const upNode: React.ReactNode = sortDirections.includes(ASCEND) && (
|
||||
@ -179,6 +180,7 @@ function injectSorter<RecordType>(
|
||||
const cell: React.HTMLAttributes<HTMLElement> =
|
||||
(column.onHeaderCell && column.onHeaderCell(col)) || {};
|
||||
const originOnClick = cell.onClick;
|
||||
const originOKeyDown = cell.onKeyDown;
|
||||
cell.onClick = (event: React.MouseEvent<HTMLElement>) => {
|
||||
triggerSorter({
|
||||
column,
|
||||
@ -186,9 +188,17 @@ function injectSorter<RecordType>(
|
||||
sortOrder: nextSortOrder,
|
||||
multiplePriority: getMultiplePriority(column),
|
||||
});
|
||||
|
||||
if (originOnClick) {
|
||||
originOnClick(event);
|
||||
originOnClick?.(event);
|
||||
};
|
||||
cell.onKeyDown = (event: React.KeyboardEvent<HTMLElement>) => {
|
||||
if (event.keyCode === KeyCode.ENTER) {
|
||||
triggerSorter({
|
||||
column,
|
||||
key: columnKey,
|
||||
sortOrder: nextSortOrder,
|
||||
multiplePriority: getMultiplePriority(column),
|
||||
});
|
||||
originOKeyDown?.(event);
|
||||
}
|
||||
};
|
||||
|
||||
@ -202,6 +212,7 @@ function injectSorter<RecordType>(
|
||||
}
|
||||
|
||||
cell.className = classNames(cell.className, `${prefixCls}-column-has-sorters`);
|
||||
cell.tabIndex = 0;
|
||||
|
||||
return cell;
|
||||
},
|
||||
@ -214,7 +225,7 @@ function injectSorter<RecordType>(
|
||||
children: injectSorter(
|
||||
prefixCls,
|
||||
newColumn.children,
|
||||
sorterSates,
|
||||
sorterStates,
|
||||
triggerSorter,
|
||||
defaultSortDirections,
|
||||
tableLocale,
|
||||
|
@ -216,6 +216,7 @@
|
||||
|
||||
// ============================ Sorter ============================
|
||||
&-thead th.@{table-prefix-cls}-column-has-sorters {
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
@ -227,6 +228,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
color: @primary-color;
|
||||
}
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/30969
|
||||
&.@{table-prefix-cls}-cell-fix-left:hover,
|
||||
&.@{table-prefix-cls}-cell-fix-right:hover {
|
||||
|
Loading…
Reference in New Issue
Block a user