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:
afc163 2022-04-27 16:27:13 +08:00 committed by GitHub
parent 45a19024ab
commit 5a6b3ccd98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 74 additions and 6 deletions

View File

@ -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"

View File

@ -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(

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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,

View File

@ -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 {